Pythonでウェブスクレイピング

この記事のまとめ:

Pythonでウェブスクレイピング(ウェブクローリング)する上で基本的な処理として下記を紹介しています。

  • Refequestsライブラリを使ったHTMLの取得方法
  • Seleniumを使ったJavaScript対応ページのHTMLの取得方法
  • robots.txtの確認方法
  • Beautiful Soupを使ったHTML解析方法
  • ウェブスクレイピングの利用例

背景:

仕事や趣味でウェブページから手早く取得するためにウェブスクレイピングをやってみようと思った次第で、意外と簡単にできたのでその作業をまとめております。

もくじ
  1. Refequestsライブラリを使ったHTMLの取得
  2. Seleniumを使ったJavaScript対応ページのHTMLの取得
  3. robots.txtの確認
  4. Beautiful Soupを使ったHTML解析
  5. ウェブスクレイピングの利用例
1. Requestsライブラリを使ったHTMLの取得
Requestsとは

Requestsとは、本家のホームページの説明を参照すると、

Requestsは、人が使いやすいように設計されていて、Pythonで書かれている Apache2 Licensed ベースのHTTPライブラリです。

とのことです。Python用のHTTPライブラリとしては、httplib2などがありますが、確かに必要な手順が多いので使いにくいです。

Requestsのインストール

pipがインストールされていれば下記でインストールできます。

$ pip install requests

Condaでインストールする場合には下記でインストールできます。

$ conda install -c anaconda requests
Requestsの使い方

例えば、HTTP GETコマンドで指定したURLからHTMLを取得する場合には下記のコード(ここではYahoo!Japanのホームページを対象にしています)だけで取得できます。

import requests
url = 'http://www.yahoo.co.jp'
html = requests.get(url)
print(html.text)

スクレイピングするだけであれば基本的にはHTTP GETコマンドが使えれば十分だと思いますが、Requestsライブラリを使えばHTTP GETコマンドだけでなく、POST、PUTなどのコマンドも容易に使えますし、コマンドと一緒にcookieやheader、proxy、パラメーターなども使うことができますので、特殊なサイトにも対応できます。

2. Seleniumを使ったJavaScript対応ページのHTMLの取得
Requestsではだめなのか?

上記のRequestsを使って大体のページのHTMLを取得することはできると思いますが、一部JavaScriptでHTMLを生成するページがあります。

例えば、Amazonの検索結果をRequestsで取得しようとしても取得できません。試しにやってみます。下記ではpythonというキーワードをAmazonで検索するURLからGETコマンドを行っています。

import requests
url = 'https://www.amazon.co.jp/gp/search/?field-keywords=python'
html = requests.get(url)
print(html.text)

ブラウザなどJavaScriptが動いている状態での検索結果は、<div id="atfResults">というタグで囲われた中にリスト上になって表示されているはずですが、JavaScriptが動いていないとこのタグ自体見当たらないはずです。

そこで、Seleniumの出番です。

Seleniumとは

ウェブブラウザを自動操作するツールです。スクレイピング用というわけではありませんが、ウェブブラウザを操作できるのでウェブブラウザがJavaScriptを動かしてその結果取得したHTMLも取得可能なわけです。

Seleniumのインストール

pipでインストールする場合には下記でインストールできます。

$ pip install selenium

Condaでインストールする場合には下記でインストールできます。

$ conda install -c conda-forge selenium
FirefoxをSeleniumで使う

今回はFirefoxをヘッドレス(画面を表示させずに使用する)モードで使用することを前提に進めますので、Firefoxをまずはインストールしておきます。

また、Firefoxはgeckodriverが提供するHTTP APIで操作されるので、geckodriverをインストールしなければなりません。

geckodriverはこちらからダウンロードできますので、動作環境に適したファイルをダウンロード、解凍を行い、実行ファイルを任意のディレクトリに保存しておきます。また、Linux系の場合は実行権限も与えておく必要があります。

PythonでSeleniumを使ってFirefoxをヘッドレスモードで動かす

Requestsの時と比べるとだいぶコードは増えますが、下記でFirefoxを使ってウェブページのHTMLを取得できます。Firefoxとgeckodriverのパスは環境に応じて変更してください。

from selenium import webdriver # conda install -c conda-forge selenium
from selenium.webdriver.firefox.firefox_binary import FirefoxBinary
 
profile = webdriver.FirefoxProfile()
profile.set_preference("permissions.default.image", 2) # 画像を読み込まない
profile.set_preference('permissions.default.stylesheet', 2) # CSSを使わない
profile.set_preference('dom.ipc.plugins.enabled.libflashplayer.so', 'false') # Flashを使わない
 
binary = FirefoxBinary('/usr/bin/firefox')
binary.add_command_line_options('--headless')
 
options = webdriver.firefox.options.Options()
options.set_headless()  
 
geckodriver_path = "/usr/bin/geckodriver"
driver = webdriver.Firefox(executable_path=geckodriver_path, firefox_binary=binary, options=options, firefox_profile=profile)
 
try:
  driver.get('https://www.amazon.co.jp/gp/search/?field-keywords=python')
  html = driver.page_source.encode('utf-8')
  driver.close()
except:
  driver.close()
 
print(html)

上記のコードでは、Requestsのときには取得できなかったAmazonの検索結果が取得できているはずです。

(2019.1.13追記) Seleniumでブラウザを使うときは必ずdriver.close()でブラウザを閉じるように実装します。エラー終了した場合でもブラウザのプロセスは生き続けるためです。エラーはWebサーバー側の問題でも起こることがありますので、try文でエラー処理をすることをお勧めします。

3. robots.txtの確認
robots.txtとは

ウェブサイトによってはスクレイピングのようにロボットによるクローリングを禁止しているサイトがあります。これを守らないと利用規定違反にもなりますし、技術者としての倫理的にも反しますので必ず守りましょう。そしてその情報が書かれているファイルが robots.txt です。スクレイピングする場合にはスクレイピング先のサイトのrobots.txtに記述されている内容に従いましょう。robots.txtの見方などは他の解説記事など参照していただくとして、ここではPythonでのrobots.txt用のparserライブラリであるreppyを使ったrobots.txtの扱い方を紹介します。

reppyのインストール

pipでインストールする場合には下記でインストールできます。

$ pip install reppy

Windowsの場合は、reppyのインストール時にVC++ 14.0を使ったコンパイルを伴うため、Visual Studio 2015 (Communityで可)をインストール(Windows 10 SDKとC++が必須)しておく必要があります。Visual Studio 2015 Communityはこちらからダウンロードできます。なお、適切なVC++ 14.0がインストールされていないと下記のようなエラーが表示されると思います。

Installing collected packages: reppy
  Running setup.py install for reppy ... error
    Complete output from command c:\users\<user>\anaconda3\envs\<env>\python.exe -u -c "import setuptools, tokenize;__file__='C:\\Users\\<user>\\AppData\\Local\\Temp\\pip-install-obs2edkj\\reppy\\setup.py';f=getattr(tokenize, 'open',open)(__file__);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, __file__, 'exec'))" install --record C:\Users\<user>\AppData\Local\Temp\pip-record-dw6_a4ed\install-record.txt --single-version-externally-managed --compile:
 
    Building from C++
    running install
    running build
    running build_py
    creating build
    creating build\lib.win-amd64-3.5
    creating build\lib.win-amd64-3.5\reppy
    copying reppy\exceptions.py -> build\lib.win-amd64-3.5\reppy
    copying reppy\ttl.py -> build\lib.win-amd64-3.5\reppy
    copying reppy\util.py -> build\lib.win-amd64-3.5\reppy
    copying reppy\__init__.py -> build\lib.win-amd64-3.5\reppy
    creating build\lib.win-amd64-3.5\reppy\cache
    copying reppy\cache\policy.py -> build\lib.win-amd64-3.5\reppy\cache
    copying reppy\cache\__init__.py -> build\lib.win-amd64-3.5\reppy\cache
    running build_ext
    building 'reppy.robots' extension
    error: Microsoft Visual C++ 14.0 is required. Get it with "Microsoft Visual
C++ Build Tools": http://landinghub.visualstudio.com/visual-cpp-build-tools
 
    ----------------------------------------
Command "c:\users\<user>\anaconda3\envs\<env>\python.exe -u -c "import setuptools, tokenize;__file__='C:\\Users\\<user>\\AppData\\Local\\Temp\\pip-install-obs2edkj\\reppy\\setup.py';f=getattr(tokenize, 'open', open)(__file__);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, __file__, 'exec'))" install --record C:\Users\<user>\AppData\Local\Temp\pip-record-dw6_a4ed\install-record.txt --single-version-externally-managed --compile" failed with error code 1 in C:\Users\<user>\AppData\Local\Temp\pip-install-obs2edkj\reppy\

reppyを使う

サンプルとして下記のコードではツイッターのrobots.txtを読み込み、任意のツイッターページ(今回は私のツイッターアカウント)に対してクローリング可能かどうかと、Crawl_delayの値を取得しています。クローリング可能であれば、resultの中にはTrueが返され、delayの中には小数点でCrawl_delayの値が返されます。robots.txtにCrawl_delayが設定されていない場合にはNoneが返されます。

from reppy.robots import Robots
 
home = 'https://twitter.com'
target = 'https://twitter.com/hassiweb'
userAgent = 'MyCralwer'
 
robotsUrl = Robots.robots_url(home)
robots = Robots.fetch(robotsUrl)
 
result = robots.allowed(target, userAgent)
print(result)
 
delay = robots.agent(userAgent).delay
print(delay)
4. Beautiful Soupを使ったHTML解析
Beautiful Soupとは

公式ドキュメントの日本語訳のページから引用させていただくと下記の通りです。

Beautiful Soup はHTMLやXMLファイルからデータを取得するPythonのライブラリです。あなたの好きなパーサー(構文解析器)を使って、パースツリー(構文木)の探索、検索、修正を行います。 これはプログラマーの作業時間を大幅に短縮してくれます。

Beautiful Soupを使うことで任意のタグのパラメーターやタグの中身の取得等が容易にできます。

Beautiful Soupのインストール

pipでインストールする場合には下記でインストールできます。

$ pip install Beautifulsoup4 html5lib

Condaでインストールする場合には下記でインストールできます。

$ conda install -c anaconda beautifulsoup4 html5lib
Beautiful Soupを使う

ここでは一例としてAmazon.co.jpのプレスリリースのタイトルを取得してみます。

プレスリリースの一覧は<section class="element_newslist" >タグの中に<ul>タグによってリスト状になっており、<h3>タグにプレスリリースのそれぞれのタイトルが書かれています。それを一括して取得するサンプルを下記に記します。

import requests, bs4
url = 'https://amazon-press.jp/'
html = requests.get(url)
soup = bs4.BeautifulSoup(html.content, 'html5lib')
newslist = soup.find('section', class_='element_newslist').find('ul', class_='newslist').find_all('h3')
for news in newslist:
  print(news.text)

こうやってかなり簡単に書けることがわかります。スクレイピングする場合、ウェブサイトに応じてタグのIDやClassが異なりますので、ウェブサイトごとに調整が必要ですが、慣れれば比較的簡単に対応ができます。なお、スクレイピングしたい個所を特定するのには、Google Chromeブラウザの開発者向けツールを使ってHTMLを分析するのがおすすめです。

5. ウェブスクレイピングの利用例

ウェブスクレイピングしていると画像をダウンロードしたいというときも出てくるのではないかと思います。その際は、下記の記事が参考になるかもしれません。

これをウェブスクレイピングと組み合わせると下記のようなものもできたりします。

また、ウェブスクレイピングすると自然言語解析をしたくなることもあります。その際は、下記の記事が参考になるかもしれません。




今回は以上です。 最後まで読んでいただき、ありがとうございます。


コメント

このブログの人気の投稿

PythonでPosgreSQLを操作する

Python + dlibで顔検出を行う