PythonでWebのスクレイピング時にオススメのライブラリ「Beautiful Soup 4」です
Webスクレイピングを活用することで、
- Webサイトから大量に情報を取得
- Webの情報取得を自動化
できるので普段繰り替えている作業が簡略化され業務効率が上がります。
またデータサイエンスや機械学習に必要な大量データを取得する時にも便利ですので、この記事で使い方をマスターしてください。
BeautifulSoup4とは?何でSoupなの?
「BeautifulSoup4」とはHTMLやXMLを取得・解析・編集するためのライブラリになります。
「BeautifulSoup4」は前身として「BeautifulSoup3」がありましたが、Python 3系で利用されるは「BeautifulSoup4」です。
「BeautifulSoup3」はPython 3系では利用できないので注意してください。
なぜ「Soup」なのか?というと、マークアップの世界では「不正なマークアップを持つもの、しっかりと閉じられていないマークアップタグをタグスープ」と呼びます。
恐らくそこからモジって、「Beautiful Soup」というライブラリ名になったのでしょう。
スクレイピングの準備:BeautifulSoup4のインストール
ではスクレイピングのために準備をしていきましょう。
Pythonでスクレイピングをするために必要なライブラリは以下になります。
- BeautifulSoup:HTML/XML形式のファイルを解析するためのライブラリ
- lxml:より高速にHTML/XML形式を解析できるライブラリ。Beautifulsoupで呼び出して使用。
- requests:シンプルなHTTPリクエストを生成できるライブラリ
まずはBeautifulsoupをインストールしましょう。
「BeautifulSoup4」のインストール方法は下になります。
pip install beautifulsoup4
「beautifulsoup4」としっかり記載しないと「BeautifulSoup3」がインストールされてしまいます。
また「BeautifulSoup3」はPython 3系では利用できないので注意してください。
次にlxmlをインストールしましょう。 より高速にHTML、XMLを解析するために「lxml」ライブラリがおすすめです。
pip install lxml
最後にHTTPリクエストでHTMLを取得するため「requests」をインストールしましょう。
インストール方法は以下になります。
pip install requests
Beautiful Soup 4の基本的な使い方
ここからは実際にBeautifulsoup4を使用したスクレイピング方法を紹介します。
初めてスクレイピングをやる方のために大まかな流れを説明します。
- Webページをurlで取得する。(requestを使います)
- 取得したWebページをスクレイピングできる形に整形します。(パーサーでhtmlページを解析してスクレイピングできるようにします)
- スクレイピングする(要素を抽出します)
では流れにそってスクレイピングをしてみましょう。
今回はyahoo.co.jpのtitleを取得したいと思います。
まず初めにモジュールをインポートします。
import requests
from bs4 import BeautifulSoup
注意:lxmlはBeautifulsoupで内部的に利用するためインポートは不要です。
しかしインストールしないとエラーがでます。
次に対象のurlを指定してHTMLファイルを取得します。
今回はyahoo.co.jpで挑戦してみたいと思います。
url =https://www.yahoo.co.jp/
response = requests.get(url)
取得が終わったらWebページをスクレイピングできる形にします。
soup = BeautifulSoup(response.content, 'lxml')
最後にTitleをスクレイピングします。
title = soup.title
では、今回解説したコードの全文は以下になります。
import requests
from bs4 import BeautifulSoup
url =https://www.yahoo.co.jp/
response = requests.get(url)
soup = BeautifulSoup(response.content, 'lxml')
title = soup.title
print(title)
# <title>Yahoo! JAPAN</title>
このコーディング方法をマニュアルにも書いてある「beautifulsoup4」の一般的な書き方になります。
6行目の「bs4.BeautifulSoup(html.text, \’lxml\’)」に注目してください。
第2引数に「\’lxml\’」を渡していますが、
これがPython3系でHTMLを解析する時に最も高速なコーディング方法になります。
昔のブログなどでは「BeautifulSoup(markup, html.parser) 」と書かれていることが多いですが今は使いません。
下は各パース方法のメリット・デメリットになります。
XMLファイルを解析する時は下のように書きます。
<pre class="EnlighterJSRAW" data-enlighter-language="python">BeautifulSoup(markup, lxml-xml)
または
BeautifulSoup(markup, xml)
まずは基本的に流れを掴むために、WebサイトからHTMLファイルを取得する時の基本的なコーディングをマスターしましょう。
import requests
from bs4 import BeautifulSoup
url = '<解析対象ファイルのURL>'
html = requests.get(url)
soup = BeautifulSoup(html.text, lxml)
HTMLからタグ情報取得
実際にHTMLファイルからタグ情報を取得する方法を紹介します。
取得方法 | 構文 | コードディング例 |
---|---|---|
1件検索 | soup.find(<タグ名>) | soup.find("title") |
タグ全検索 | soup.find_all(<タグ名>) | soup.find_all("a") |
属性検索 | soup.find(<タグ名>, <属性値>) | soup.find("a", href="http://example.com/lacie") |
id検索 | soup.find(<タグ名>, id= | soup.find("a", id="link3") |
class検索 | soup.find(<タグ名>, class_=<クラス名>) | soup.find("p", class_="title") |
タグ名で検索 | soup.[タグ名].[タグ名]… | soup.html.head |
※ find_all()メソッド以外は検索対象に合致したタグの1つ目が出力されます。
なお、今回読み込むHTMLファイルは以下になります。
<html>
<head>
<title>The Dormouse''s story</title>
</head>
<body>
<p class=title><b>The Dormouse''s story</b></p>
<p class=story>
Once upon a time there were three little sisters; and their names were
<a class=sister href=http://example.com/elsie id=link1>Elsie</a>
,
<a class=sister href=http://example.com/lacie id=link2>Lacie</a>
and
<a class=sister href=http://example.com/tillie id=link3>Tillie</a>
</p>
</body>
</html>
下がサンプルコードになります。
import lxml
from bs4 import BeautifulSoup
html_text = '''
<html>
<head>
<title>The Dormouse''s story</title>
</head>
<body>
<p class=title><b>The Dormouse''s story</b></p>
<p class=story>
Once upon a time there were three little sisters; and their names were
<a class=sister href=http://example.com/elsie id=link1>Elsie</a>
,
<a class=sister href=http://example.com/lacie id=link2>Lacie</a>
and
<a class=sister href=http://example.com/tillie id=link3>Tillie</a>
</p>
</body>
</html>
'''
soup = BeautifulSoup(html_text, lxml)
print(soup.find(title))
# <title>The Dormouse''s story</title>
print(soup.find_all(a))
# [<a class =sister href=http://example.com/elsie id=link1 > Elsie </a>,
# <a class =sister href=http://example.com/lacie id=link2 > Lacie </a>,
# <a class =sister href=http://example.com/tillie id=link3 > Tillie </a>]
print(soup.find(a, href=http://example.com/lacie))
# <a class=sister href=http://example.com/lacie id=link2>Lacie</a>
print(soup.find(a, id=link3))
# <a class=sister href=http://example.com/tillie id=link3>Tillie</a>
print(soup.find(p, class_=title))
# <p class=title><b>The Dormouse''s story</b></p>
print(soup.html.head)
# <head>
# <title>The Dormouse''s story</title>
# </head>
CSSセレクタを使用したタグ情報取得
CSSのセレクタを使用したタグ情報の取得方法は紹介します。
取得方法 | 構文 | コードディング例 |
---|---|---|
タグ検索 | soup.select(<タグ名>) | soup.select("title") |
1件検索 | soup.select_one(<タグ名>) | soup.select_one("a") |
属性存在有無で検索 | soup.select(<属性名>) | soup.select("a[data]") |
属性値検索 | soup.select(<属性名と属性値>) | soup.select('a[href="http://example.com/lacie"]') |
CSSセレクタ検索 | soup.select(CSSセレクタ) | soup.select("p.title") |
soup.select("p > .title") | ||
soup.select("p > a:nth-first-of-type") |
**上記のようにCSSセレクタのように柔軟にタグ情報を取得することができます。
classが複数適用されている場合には、下のようにピリオドでclass名を繋げて記載します。**
css_soup = BeautifulSoup('<p class=body strikeout></p>')
css_soup.select(p.strikeout.body)
# [<p class=body strikeout></p>]
css_soup.find_all(p, class_=body strikeout)
# [<p class=body strikeout></p>]
css_soup.find_all(p, class_=strikeout body)
# []
「find_all()」メソッドだとclass名とその記載されている順序を守る必要がありますが、
「select()」メソッドだと記載されて順序は意識する必要はありません。
下がサンプルコードになります。
import lxml
from bs4 import BeautifulSoup
html_text = '''
<html>
<head>
<title>The Dormouse''s story</title>
</head>
<body>
<p class=title><b>The Dormouse''s story</b></p>
<p class=story>
Once upon a time there were three little sisters; and their names were
<a class=sister href=http://example.com/elsie id=link1>Elsie</a>
,
<a class=sister href=http://example.com/lacie id=link2>Lacie</a>
and
<a class=sister href=http://example.com/tillie id=link3>Tillie</a>
</p>
</body>
</html>
'''
soup = BeautifulSoup(html_text, lxml)
print(soup.select(title))
# [<title>The Dormouse''s story</title>]
print(soup.select_one(a))
# <a class=sister href=http://example.com/elsie id=link1>Elsie</a>
print(soup.select(a[href]))
# [<a class=sister href=http://example.com/elsie id=link1>Elsie</a>,
# <a class=sister href=http://example.com/lacie id=link2>Lacie</a>,
# <a class=sister href=http://example.com/tillie id=link3>Tillie</a>]
print(soup.select('a[href=http://example.com/lacie]'))
# [<a class=sister href=http://example.com/lacie id=link2>Lacie</a>]
print(soup.select(p.title))
# [<p class=title><b>The Dormouse''s story</b></p>]
正規表現を使用したタグ情報取得
正規表現を使用したタグ情報を取得は、「re」ライブラリを使用して行います。
import re
soup.find(re.compile(<正規表現>))
または
soup.find_all(re.compile(<正規表現>))
下がサンプルコードになります。
import lxml
import re
from bs4 import BeautifulSoup
html_text = '''
<html>
<head>
<title>The Dormouse''s story</title>
</head>
<body>
<p class=title><b>The Dormouse''s story</b></p>
<p class=story>
Once upon a time there were three little sisters; and their names were
<a class=sister href=http://example.com/elsie id=link1>Elsie</a>
,
<a class=sister href=http://example.com/lacie id=link2>Lacie</a>
and
<a class=sister href=http://example.com/tillie id=link3>Tillie</a>
</p>
</body>
</html>
'''
soup = BeautifulSoup(html_text, lxml)
for tag in soup.find_all(re.compile(^b)):
print(tag.name)
# body
# b
タグの属性や値を取得
タグの属性や値を取得するには、「name」タグや「string」タグを利用します。
出力方法 | 構文 | コードディング例 |
---|---|---|
タグのすべてを取得 | soup.<タグ名> | soup.title |
タグ名を取得 | soup.<タグ名>.name | soup.title.name |
タグの値を取得 | soup.<タグ名>.string | soup.title.string |
下がサンプルコードになります。
import lxml
from bs4 import BeautifulSoup
if __name__ == '__main__':
html_text = '''
<html>
<head>
<title>The Dormouse''s story</title>
</head>
<body>
<p class=title><b>The Dormouse''s story</b></p>
<p class=story>
Once upon a time there were three little sisters; and their names were
<a class=sister href=http://example.com/elsie id=link1>Elsie</a>
,
<a class=sister href=http://example.com/lacie id=link2>Lacie</a>
and
<a class=sister href=http://example.com/tillie id=link3>Tillie</a>
</p>
</body>
</html>
'''
soup = BeautifulSoup(html_text, lxml)
print(soup.title)
# <title>The Dormouse''s story</title>
print(soup.title.name)
# title
print(soup.title.string)
# The Dormouse''s story
取得したHTMLテキストを出力
取得したHTMLテキストを出力するには「prettify()」メソッドを使用します。
取得 | 構文 | コードディング例 |
---|---|---|
全テキストを取得 | soup.prettify() | soup.prettify() |
タグを指定して取得 | soup.<タグ名>.prettify() | soup.head.prettify() |
import lxml
from bs4 import BeautifulSoup
html_text = '''
<html>
<head>
<title>The Dormouse''s story</title>
</head>
<body>
<p class=title><b>The Dormouse''s story</b></p>
<p class=story>
Once upon a time there were three little sisters; and their names were
<a class=sister href=http://example.com/elsie id=link1>Elsie</a>
,
<a class=sister href=http://example.com/lacie id=link2>Lacie</a>
and
<a class=sister href=http://example.com/tillie id=link3>Tillie</a>
</p>
</body>
</html>
'''
soup = BeautifulSoup(html_text, lxml)
print(soup.prettify())
# <html>
# <head>
# <title>
# The Dormouse''s story
# </title>
# </head>
# <body>
# <p class=title>
# <b>
# The Dormouse''s story
# </b>
# </p>
# <p class=story>
# Once upon a time there were three little sisters; and their names were
# <a class=sister href=http://example.com/elsie id=link1>
# Elsie
# </a>
# ,
# <a class=sister href=http://example.com/lacie id=link2>
# Lacie
# </a>
# and
# <a class=sister href=http://example.com/tillie id=link3>
# Tillie
# </a>
# </p>
# </body>
# </html>
print(==========================================================================================)
print(soup.head.prettify())
# <head>
# <title>
# The Dormouse''s story
# </title>
# </head>