Beautiful SoupとPythonを使ってウェブスクレイピングをしてみました。
参考にしたサイト
- Beautiful Soupの公式
- Beautiful Soupの公式の日本語訳 ※やや古いので注意が必要
前提
Pythonはすでにインストールされている想定で進めます。Pythonがインストールされていない場合は、PythonとSeleniumを使ったブラウザ自動操作を参考にインストールしてください。
Beautiful Soupのバージョン
Beautiful Soupにはバージョン3系とバージョン4系があります。バージョン3系はすでに開発が終了していますので、ここではバージョン4系で進めます。
Beautiful Soupのインストール
コマンドプロンプトでpip install beautifulsoup4
を実行します。
>pip install beautifulsoup4
Collecting beautifulsoup4
Downloading beautifulsoup4-4.6.0-py3-none-any.whl (86kB)
100% |████████████████████████████████| 92kB 629kB/s
Installing collected packages: beautifulsoup4
Successfully installed beautifulsoup4-4.6.0
インターネット上のリソースを取得する
スクレイピングするにはまず、スクレイピングの対象となるWebページのHTMLを取得する必要があります。URLを指定してHTMLを取得する方法はいくつかありますが、ここではurllib.requestを使ってみます。以下のサイトが参考になります。
- Python公式
- Python公式の日本語訳
import urllib.request
with urllib.request.urlopen('http://www.yahoo.co.jp/') as response:
html = response.read()
print(html)
これを実行すると、対象のURLのHTMLが取得できることがわかります。
>python beautifulsoup.py
b'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
・・・
<!-- p03.f7.top.kks.yahoo.co.jp Mon Nov 20 11:06:50 JST 2017 -->\n'
HTMLソースをBeautiful Soupに食わせる
import urllib.request
from bs4 import BeautifulSoup
with urllib.request.urlopen('http://www.yahoo.co.jp/') as response:
html = response.read()
soup = BeautifulSoup(html, "html.parser")
print(soup.prettify())
7行目でHTMLからBeautiful Soup オブジェクトを取得しています。このBeautiful Soup オブジェクトを操作することで、このページのコンテンツを取得していきます。
8行目は取得したBeautiful Soup オブジェクトのprettify()メソッドを使用することで、1行に1タグのきれいにフォーマットされた形でHTMLを表示しています。
>python beautifulsoup.py
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
・・・
<!-- p07.f7.top.kks.yahoo.co.jp Mon Nov 20 11:11:20 JST 2017 -->
ユーザーエージェントを設定する
前の手順で出力されたHTMLをよく観察すると、Google ChromeでYahooへアクセスしたときのHTMLと異なっていることに気づきます。これはYahooのサイトがブラウザを判定してブラウザ毎に異なったHTMLを表示しているからです。
スクレイピングをする際に、Google Chromeなどで抽出したいタグを特定していく作業をしていきますが、取得されるHTMLがChromeと異なるとその作業が非常にやりにくくなります。そこでurllib.request.urlopenでYahooにアクセスする際にChromeでアクセスしていることにしてしまいます。HTTPヘッダーにはユーザーエージェントというデータが有り、これがアクセスしているブラウザを指定しています。これをChromeのものに書き換えます。
import urllib.request
from bs4 import BeautifulSoup
url = "http://www.yahoo.co.jp/"
data = None
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36"}
request = urllib.request.Request(url, data, headers)
response = urllib.request.urlopen(request)
html = response.read()
soup = BeautifulSoup(html, "html.parser")
print(soup.prettify())
6行目で設定しているのがユーザーエージェントでGoogle Chromeの例です。
これを実行すると先ほどとは異なるHTMLが取得できていることがわかるはずです。またこのHTMLがGoogle Chromeで見ているHTMLと同じものだということもわかります。
CSSセレクタを使ってタグを取得する
一旦Beautiful Soup オブジェクトを取得できると、このオブジェクトを操作して様々なデータを取得できます。select()メソッドを使うと、CSSセレクタを使ってタグオブジェクトを取得することができます。
import urllib.request
from bs4 import BeautifulSoup
url = "http://www.yahoo.co.jp/"
data = None
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36"}
request = urllib.request.Request(url, data, headers)
response = urllib.request.urlopen(request)
html = response.read()
soup = BeautifulSoup(html, "html.parser")
tags = soup.select("#yahooservice ul li a")
for tag in tags:
print(tag.string)
12行目で抽出したい要素のセレクタを指定しています。CSSと同様の指定方法でセレクタを指定できます。ここではYahooのページの左側メニューの主なメニューを取得しています。
ここで取得できる要素は複数ありますので結果(変数tags)はリストで返ります。そこで13行目でリストを繰り返しで処理して一つずつ表示しています。
スクレイピングでBeautiful Soupを使うかSeleniumを使うか
この記事ではBeautiful Soupを使ったスクレイピングを紹介しましたが、こちらの記事ではSeleniumを使ったスクレイピングを紹介しています。どちらを使うかはその時々で使い分けるべきでしょう。Seleniumを使うとブラウザの動作を自動化するという感覚に対し、Beautiful SoupはスクリプトでDOM操作する際に非常に便利になるという感覚で使用するレイヤーがそもそも違うように感じます。具体的にはログイン操作をしたり、JavaScriptの動的コンテンツを読み込んだりする場合はSeleniumを使ったほうが便利でしょうが、一つ一つの動作が重いためSeleniumを使うべき理由が無い場合はBeautifulSoupを使ったほうが良いことが多いでしょう。
Webスクレイピングの実例
スクレイピングをして以下のようなデータ調査を行いました。