BeautifulSoup4でhrefの値を捕まえる方法

119, 2020-11-25

目次

BeautifulSoup4でhrefを捕まえる

Pythonの外部ライブラリに「BeautifulSoup4(ビューティフル・スープ・フォー)」というライブラリがあります。
このライブラリはHTML/XMLを解析するときに使われるパーサーです。

BeautifulSoup4を使うと簡単にHTMLの要素の属性hrefの値を取得することが出来ます。

この記事ではBeautifulSoup4を使ってHTMLの要素が持つhrefの値を取得する方法を解説します。
具体的には↓を見ていきます。

  • BeautifulSoup4の簡単な使い方

  • find()でhrefを得る

  • find_all()でhrefを得る

BeautifulSoup4の簡単な使い方

BeautifulSoup4は↓のようにBeautifulSoupをオブジェクトにして使います。

from bs4 import BeautifulSoup

html = '<p>test</p>'
soup = BeautifulSoup(html, 'html.parser')
print(type(soup))
# <class 'bs4.BeautifulSoup'>

bs4.BeautifulSoupbs4.element.Tagを継承したクラスです。
よってbs4.BeautifulSoupが持っているメソッドのほとんどはbs4.element.Tagが持っているメソッドです。
この記事で紹介するfind()find_all(), select()などはbs4.element.Tagで定義されています。

find()でhrefを得る

bs4.element.Tagが持つfind(ファインド)メソッドは要素を検索するメソッドです。
基本的には第1引数にタグ名を指定して使います。

el = soup.find('p')

find()メソッドは最初に見つかった要素をbs4.element.Tagで返します。
見つからなかった場合はNoneを返します。

bs4.element.Tagget()というメソッドを持っています。
このget()を使うと、そのタグの属性値を得ることが出来ます。
たとえばタグが属性hrefを持っている場合、↓のようにすることで、その属性値を得ることが出来ます。

val = el.get('href')

get()メソッドは属性が見つからなかった場合はNoneを返します。
属性が見つからなかった場合のデフォルト値を指定したい場合はget()の第2引数に値を指定します。

val = el.get('href', 'default value')

find()で要素を検索し、その要素の属性値を得るサンプル・コードは↓のようになります。

from bs4 import BeautifulSoup

html = '<a href="/home">Go to home</a>'
soup = BeautifulSoup(html, 'html.parser')
el = soup.find('a')
print(el.get('href'))
# /home

また、find()の代わりにタグにドット演算子でアクセスすることで、その演算子についているタグを辿ることも出来ます。

soup.a

このドット演算子によるタグの参照を使うと、↓のように書くことも出来ます。

from bs4 import BeautifulSoup

html = '<a href="/home">Go to home</a>'
soup = BeautifulSoup(html, 'html.parser')
print(soup.a.get('href'))
# /home

find()メソッドは引数attrsに属性と属性値を指定することが出来ます。
特定のhrefの値を参照したい時に便利です。
具体的には↓のように使います。

soup.find('a', attrs={ 'href': '/home' })

サンプル・コードは↓のようになります。

from bs4 import BeautifulSoup

html = '<a href="/home">Go to home</a>'
soup = BeautifulSoup(html, 'html.parser')
a = soup.find('a', attrs={ 'href': '/home' })
print(a.get('href'))
# /home

attrs引数の属性値にはリストや正規表現オブジェクトを指定することも出来ます。
リストの場合はOR検索になります。

soup.find('a', attrs={ 'href': ['/home', '/sitemap'] })

正規表現オブジェクトは↓のように指定します。

import re
soup.find('a', attrs={ 'href': re.compile(r'/h.*') })

特定のclassの要素のhrefを参照したい場合は↓のように書くことが出来ます。
↓はblueというクラス名を持つ要素のhrefを参照する例です。

a = soup.find('a', class_='blue')
print(a.get('href'))

idで検索したい場合は引数にidを指定します。

a = soup.find('a', id='red')
print(a.get('href'))

find_all()でhrefを得る

find()メソッドは単一の要素を得るメソッドでしたが、検索にヒットした要素をすべて得るメソッドもあります。
その名もfind_all(ファインド・オール)です。

find_all()メソッドも基本的にはfind()メソッドと同じ使い方をします。
たとえばリンクの要素をまとめて検索し、それらすべての要素のhrefを参照したい場合は↓のようなコードになります。

from bs4 import BeautifulSoup
import re

html = '''
<a href="/red">Red</a>
<a href="/green">Green</a>
<a href="/blue">Blue</a>
'''
soup = BeautifulSoup(html, 'html.parser')

links = soup.find_all('a')
for link in links:
    print(link.get('href'))

find_all()でもfind()のようにattrsclass_などの引数を使うことが出来ます。
たとえば特定のドメインのhrefのみを抽出したい場合は、↓のように書くことも出来ます。

from bs4 import BeautifulSoup
import re

html = '''
<a href="https://red.com/i-am-red/">Red</a>
<a href="https://green.com/hello-green/">Green</a>
<a href="https://green.com/good-bye-green/">Green</a>
<a href="https://blue.com/i-am-blue/">Blue</a>
'''
soup = BeautifulSoup(html, 'html.parser')

links = soup.find_all('a', attrs={ 'href': re.compile(r'.*://green\.com/.*$') })
for link in links:
    print(link.get('href'))

ドメインによるフィルタリングは1度要素を取得した後に行うこともできますが、↑のようにすればfind_all()の段階でフィルタリングを行うことが出来ます。

おわりに

スクレイピングでHTML要素のhref属性を取得したいケースは多いと思います。
BeautifulSoup4では簡単に取得が可能です。

(^ _ ^)

ところでhrefって「フレフ」でいいの?

(・ v ・)

「エイチレフ」じゃない?



この記事のアンケートを送信する