Python, Beautiful Soupでスクレイピング、Yahooのヘッドライン抽出
Beautiful Soupは、HTML
やXML
のファイルからデータを抽出(スクレイピング)するためのPythonライブラリ。
Beautiful Soup is a Python library for pulling data out of HTML and XML files.
Beautiful Soup Documentation — Beautiful Soup 4.4.0 documentation
ここではBeautiful Soupの基本的な使い方の例として、以下の内容について説明する。
- Beautiful Soupのインストール
- Yahooのヘッドラインを抽出する例
- urllibでサイトにアクセス
- Beautiful Soupで対象を抽出
Pythonにはスクレイピングに加えてクローリングも行うフレームワークScrapyもある。リンクを辿って複数ページから情報を抽出するような場合はScrapyのほうが便利。
Beautiful Soupのインストール
pip
でインストールできる(環境によってはpip3
)。
$ pip install beautifulsoup4
beautifulsoup
ではなくbeautifulsoup4
なので注意。
Yahooのヘッドラインを抽出する例
例として、Yahoo! JAPANのニュースのヘッドラインを抽出する。
- macOS: 10.12.3
- Python: 3.6.0
で動作確認。
import urllib.request
from bs4 import BeautifulSoup
url = 'https://www.yahoo.co.jp/'
ua = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) '\
'AppleWebKit/537.36 (KHTML, like Gecko) '\
'Chrome/55.0.2883.95 Safari/537.36 '
req = urllib.request.Request(url, headers={'User-Agent': ua})
html = urllib.request.urlopen(req)
soup = BeautifulSoup(html, "html.parser")
topicsindex = soup.find('div', attrs={'class': 'topicsindex'})
topics = topicsindex.find_all('li')
for topic in topics:
print(topic.find('a').contents[0])
以下、サンプルコードの各部分を説明する。
urllibでサイトにアクセス
標準ライブラリurllib
モジュールはPython3から変更されているので注意。
urllib モジュールは、Python 3 で urllib.request, urllib.parse, urllib.error に分割されて名称変更されました。 2to3 ツールが自動的にソースコードのimportを修正します。また、 Python 3 の urllib.request.urlopen() 関数は urllib2.urlopen() を移動したもので、 urllib.urlopen() のほうは削除されています。
20.5. urllib — URL による任意のリソースへのアクセス — Python 2.7.x ドキュメント
今回はPython3で実行しているので、urllib.request
を使う。
urllib.request.Request()でユーザーエージェントを偽装
url = 'https://www.yahoo.co.jp/'
ua = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) '\
'AppleWebKit/537.36 (KHTML, like Gecko) '\
'Chrome/55.0.2883.95 Safari/537.36 '
req = urllib.request.Request(url, headers={'User-Agent': ua})
Yahoo! JAPANは、ユーザーエージェント (User agent)によって表示を変えているので、urllib.request.Request()
でユーザーエージェントを偽装する。
class urllib.request.Request(url, data=None, headers={}, origin_req_host=None, unverifiable=False, method=None)
このクラスは URL リクエストを抽象化したものです。
…
headers は辞書でなければなりません。この辞書は add_header() を辞書のキーおよび値を引数として呼び出した時と同じように扱われます。この引数は、多くの場合ブラウザーが何であるかを特定する User-Agent ヘッダーの値を “偽装” するために用いられます。これは一部の HTTP サーバーが、スクリプトからのアクセスを禁止するために一般的なブラウザーの User-Agent ヘッダーしか許可しないためです。例えば、 Mozilla Firefox は User-Agent に "Mozilla/5.0 (X11; U; Linux i686) Gecko/20071127 Firefox/2.0.0.11" のように設定し、 urllib はデフォルトで "Python-urllib/2.6" (Python 2.6の場合) と設定します。
21.6. urllib.request — URL を開くための拡張可能なライブラリ — Python 3.5.2 ドキュメント
自分が使っているブラウザのユーザーエージェントは、
の現在のブラウザー
で確認できる。
ユーザーエージェントはけっこう長い文字列になる。複数行に分けて書く方法は以下の関連記事参照。
- 関連記事: Pythonで長い文字列を複数行に分けて書く
urllib.request.urlopen()でurlを開く
urllib.request.Request()
でユーザーエージェントを偽装したRequest
オブジェクトを渡す。
html = urllib.request.urlopen(req)
特にユーザーエージェントを偽装したりする必要がなければ、https://www.yahoo.co.jp/
などのようにurl
をそのまま渡せばOK。
urllib.request.urlopen(url, data=None, [timeout, ]*, cafile=None, capath=None, cadefault=False, context=None)
URL url を開きます。 url は文字列でも Request オブジェクトでもかまいません。
21.6. urllib.request — URL を開くための拡張可能なライブラリ — Python 3.5.2 ドキュメント
標準ライブラリのurllibではなくサードパーティライブラリのRequestsを使ってurlを開いてデータを取得することも可能。Requestsのほうがシンプルに書ける。以下の記事を参照。
- 関連記事: Python, Requestsの使い方
Beautiful Soupで対象を抽出
htmlをパースする
soup = BeautifulSoup(html, "html.parser")
HTMLパーサーを指定しないとWarning
が出る。
Python標準ライブラリのhtml.parser
以外に、lxml
やhtml5lib
を指定することもできる。その場合は、それぞれをpip
などでインストールしておく必要がある。
$ pip install lxml
$ pip install html5lib
Beautiful Soupのドキュメントによるとlxml
が速いのでオススメとのこと。
If you can, I recommend you install and use lxml for speed.
Beautiful Soup Documentation — Beautiful Soup 4.4.0 documentation
目的の部分を抽出する
topicsindex = soup.find('div', attrs={'class': 'topicsindex'})
topics = topicsindex.find_all('li')
for topic in topics:
# print(topic.find('a').text)
# 北 5年前から正男氏暗殺狙う写真NEW
# のように、"写真NEW"という余計な部分が表示されてしまう
print(topic.find('a').contents[0])
Chromeの場合、抽出したい対象の部分を選択して、右クリック→検証でその部分のソースが開発者ツールに表示される。
今回の例の場合、抽出したいYahooのヘッドラインは、<div class="topicsindex">
で囲まれて、<li>
で<a>
タグが列挙されていることが分かる。
find()
は先頭の一つのタグを取得するのに対し、find_all()
は指定したすべてのタグを取得しリストで返す。
タグの内容は、.string
, .text
, .contents
などで取得できる。