Beautiful SoupとPythonを使ってウェブスクレイピングをしてみました。

参考にしたサイト

前提

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を使ってみます。以下のサイトが参考になります。

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スクレイピングの実例

スクレイピングをして以下のようなデータ調査を行いました。