PythonはWebスクレイピングするのに大変便利な言語です。ライブラリーが充実しているため、簡単にWeb上のデータを取得することができるのです。今回はPythonで可能な2種類のスクレイピングの手法についてまとめてみました。
目次
- Webスクレイピングを実施するために知っておくべきこと
- 静的なhtmlからデータを取得する(BeautifulSoup4)
- 動的にJavaScriptで出力されるhtmlのデータを取得する(Selenium & ChromeDriver )
- Webサイトのキャプチャを取得するには?
- まとめ
1. スクレイピングを実施するために知っておくべきこと
まずスクレイピングをする前に知っておくべきことから扱いたいと思います。Web上の膨大な情報にはすべて知的財産権があります。特定の情報やコンテンツを公開している個人や組織の権利を犯さないようにする必要があるのです。取得した情報を個人的に利用するのであれば、ほとんどのケースで特に問題はありませんが、営利・非営利に関わらず取得した情報を公開する場合は、特に注意が必要です。
一例としてWikipediaについて考えてみましょう。Wikipediaに掲載されている情報は「CC-BY-SA 3.0」でライセンスが保護されています。このCCライセンス(クリエイティブ・コモンズ・ライセンス)は、国際的に広く認知されたライセンスです。「CC-BY-SA 3.0」の場合、利用目的が非営利目的で、かつ適切な著作帰属表記があればOK。改変した場合は、元のライセンスを継承する必要があると定められています。
また、Twitterのように、事前承諾なしのスクレイピングを禁じていたり、一切のスクレイピングを禁止しているというようなケースもあるでしょう。またスクレイピングを禁止していなくても、データを取得する頻度にも配慮が必要です。高頻度のスクレイピングは相手方のサーバーに余計な負荷をかけることになるのでその点でも注意が必要です。配慮に欠いたスクレイピングを実施すれば、訴訟問題にまで発展することさえあり得ます。
この記事では著作権保護が主なテーマではないので、この点に関しては以上とさせていただきますが、スクレイピングを実施する前に、各自こうした点を十分調査・検討してから実施するようにしましょう。
2. 静的なhtmlからデータを取得する(BeautifulSoup4)
では、本論に入っていきたいと思います。Pythonにおけるスクレイピングといえば、BeautifulSoupライブラリによる手法が最も一般的ではないでしょうか。この手法は、取得先のサイトが静的なhtmlである場合やサーバー側の動的なhtml出力である場合に有効な手法です。
ではまず、BeautifulSoup4を導入しましょう。
$ pip install BeautifulSoup4
Python3以上を必要としますので、Macの場合など、環境によっては「pip3」としましょう。
では早速ですがサンプルコードです。ここでは仮想通貨の相場を取得することを想定してコードを書いてみました。ビットコイン(BTC)の日本円の相場を取得することためのコードです。
# -*- coding: utf-8 -*-
from bs4 import BeautifulSoup
import urllib.request as req
# 通貨設定
crypto = 'BTC'
currency = 'JPY'
# 価格の取得先
url = 'https://coinyep.com/ja/ex/' + crypto + '-' + currency
# 取得結果
current_value = ''
# 取得先URLにアクセス
res = req.urlopen(url)
# 対象を抽出
soup = BeautifulSoup(res, 'html.parser');
values = soup.select_one("#coinyep-reverse1").findAll(text=True)
current_value = str(''.join(values))
current_value = current_value.replace('1 ' + crypto + ' = ', '')
current_value = current_value.replace(' ' + currency, '')
# 取得結果
print('1' + crypto + '(' + currency + '): ' + str(current_value))
※ データの取得先は https://coinyep.com という海外のサイトです。特にスクレイピングに関しての規約はないようでしたので、試験的に情報を取得するのは問題ないだろうと判断しました。
20行目の「soup.select_one」で取得先のidを「#」を付記した上で指定して、その内容を「text」として取得しています。仮に、取得先がclassなら「#」ではなく「.」でclassを指定します。
21〜23行目では、不要な文字列を削除して必要な部分のみ「current_value」変数に格納しています。
取得先のhtml構造が簡単であれば、これだけの記述で必要なデータを取得することができるのです。本当に便利ですね。
3. 動的にJavaScriptで出力されるhtmlのデータを取得する(Selenium & ChromeDriver )
今度は、BeautifulSoupとは異なる手法でスクレイピングする方法について考えてみたいと思います。大抵の場合は、BeautifulSoupで事が足りてしまうのですが、取得先のhtmlがフロントサイドでの出力、つまりJavaScriptやAjaxで描画されているようなケースでは、BeautifulSoupでのスクレイピングが不可能です。また取得先がユーザーエージェントを確認の上、コンテンツを出力しているようなケースでも、BeautifulSoupでのスクレイピングは困難でしょう。
※ 取得先のサイトがユーザーエージェントを確認している場合、スクレイピングを禁止する目的だとするならスクレイピングはやめましょう。
このような場合は、実際にブラウザを使ってスクレイピングすることができます。Seleniumライブラリと、Chromeを自動制御するためのChromeDriverを使えばOKです。まずは、SeleniumとChromeDriverを導入しましょう。
$ pip install selenium
$ pip install chromedriver-binary==バージョン番号
Python3以上を必要としますので、Macの場合など、環境によっては「pip3」としましょう。それとChromeDriverは、スクレイピングに使用するChrome、つまりコードを実行するPCやサーバーに実際にインストールされているChromeのバージョンを合わせる必要があります。
下記のサイトからインストールされているChromeのバージョンに最も近いものを選んで番号を決めてください。
https://sites.google.com/a/chromium.org/chromedriver/
必要な環境が構築できたら、コードを書いてみましょう。先ほどのBeautifulSoupで書いたコードを基本的にそのまま置き換えてみました。
# -*- coding: utf-8 -*-
import traceback
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import chromedriver_binary
import time
# 通貨設定
crypto = 'BTC'
currency = 'JPY'
# 価格の取得先
url = 'https://coinyep.com/ja/ex/' + crypto + '-' + currency
# 取得結果
current_value = ''
options = Options()
# ヘッドレスモードで実行する場合
# options.add_argument("--headless")
driver = webdriver.Chrome(options=options)
try:
# 取得先URLにアクセス
driver.get(url)
# コンテンツが描画されるまで待機
time.sleep(10)
# 対象を抽出
values = driver.find_element_by_id("coinyep-reverse1")
current_value = str(values.text)
current_value = current_value.replace('1 ' + crypto + ' = ', '')
current_value = current_value.replace(' ' + currency, '')
finally:
# プラウザを閉じる
driver.quit()
# 取得結果
print('1' + crypto + '(' + currency + '): ' + str(current_value))
注意点としては、スクレイピング後にブラウザを閉じてやる必要があるので、「try:」内に取得コードを書いて、最後に「finally:」内で「driver.quit()」してやります。また、実際にブラウザを起動させるので「time.sleep(10)」のように描画されるまで、数秒待ってやったほうが無難という点でしょうか。
31行目に関してですが、今回はid名で取得していますが、classの場合は「driver.find_element_by_class_name(‘class名’)」で取得してやります。その他、htmlタグで取得するなど多彩なメソッドが用意されています。
3. Webサイトのキャプチャを取得するには?
SeleniumライブラリとChromeDriverの組み合わせなら、Webサイトを巡回して、そのサイトのキャプチャ画像を取得するというような用途にも使えます。簡単な記述でキャプチャ画像を取得できます。
# -*- coding: utf-8 -*-
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import chromedriver_binary
import time
import re
# ターゲットURL
url = 'https://coinyep.com/ja/ex/BTC-JPY'
# ファイル名
file_name = 'capture.png'
# プラウザ起動(Chrome)
driver = webdriver.Chrome()
# ウィンドウサイズとズームを設定(縦サイズは+123pxで設定)
driver.set_window_size(1360, 803)
#driver.execute_script("document.body.style.zoom='100%'")
# URLを開く
driver.get(url)
# 読み込み待機時間
time.sleep(10)
# imagesフォルダにスクリーンショットを保存
driver.save_screenshot(file_name)
# プラウザを閉じる
driver.quit()
18行目でサイズを指定しますが、このサイズはブラウザのウィンドウサイズらしく、縦サイズは123px大きく指定すると、欲しいサイズで取得できました。(Mac環境のみで確認)
28行目では、実際にキャプチャを取得していますが、「driver.save_screenshot(‘ファイル名’)」のみで取得できてしまいます。簡単ですね。
5. まとめ
さて今回は、pythonを使った2種類のスクレイピングの方法について扱ってみました。著作権保護の観点から、取得するデータの扱いには十分注意が必要ですし、また頻度にも注意が必要です。ですが、データ収集を自動化して作業効率を高めたり、統計や調査などのために自動でデータを集めたりできるなど、スクレイピングは実に便利です。しかもpythonを使えば、それらを少ないコードで実現できます。pythonのスクレイピングを使いこなして有効に活用しましょう。