Python
Selenium
PhantomJS
BeautifulSoup

Pythonでかんたんスクレイピング (JavaScript・Proxy・Cookie対応版)

みなさま,おはようございます,@_akisato でございます.

クローラ/webスクレイピングAdvent Calendar http://qiita.com/advent-calendar/2015/crawler の6日目の記事として書いております.

本日は,JavaScriptやcookieを許可していないと読み込めないwebページのスクレイピングについて,紹介します.

実装は GitHub https://github.com/akisato-/pyScraper にアップしてあります.

まずは何の工夫もないスクレイピング

(1) requestsでwebページを取得し,(2) BeautufulSoup4でスクレイピングを実行します.Python標準のHTMLパーサはあまり優秀ではないですので,ここではlxmlを利用します.
BeautifulSoup4の基本的な使い方は http://qiita.com/itkr/items/513318a9b5b92bd56185 などを参照すると良いでしょう.

必要パッケージのインストール

pipを使います.

pip install requests
pip install lxml
pip install beautifulsoup4

ソース

以下のようになると思います.
スクレイピングしたいページのURLと出力ファイル名を指定すると,ページのタイトルなどがJSON形式で帰ってくる仕組みです.
関数scrapingが本体です.

scraping.py
import sys
import json
import requests
from bs4 import BeautifulSoup
import codecs

def scraping(url, output_name):
    # get a HTML response
    response = requests.get(url)
    html = response.text.encode(response.encoding)  # prevent encoding errors
    # parse the response
    soup = BeautifulSoup(html, "lxml")
    # extract
    ## title
    header = soup.find("head")
    title = header.find("title").text
    ## description
    description = header.find("meta", attrs={"name": "description"})
    description_content = description.attrs['content'].text
    # output
    output = {"title": title, "description": description_content}
    # write the output as a json file
    with codecs.open(output_name, 'w', 'utf-8') as fout:
        json.dump(output, fout, indent=4, sort_keys=True, ensure_ascii=False)

if __name__ == '__main__':
    # arguments
    argvs = sys.argv
    ## check
    if len(argvs) != 2:
        print "Usage: python scraping.py [url] [output]"
        exit()
    url = argvs[1]
    output_name = argvs[2]

    scraping(url, output_name)

JavaScriptに対応する

JavaScriptを有効にしていないと見られないwebページが非常に増加しています.先ほどまでのソースでそのようなページにアクセスすると,「JavaScriptを有効にして下さい」というページしか取れなくなります.

このようなページに対応するために,requestsで行っていたwebページ取得を,SeleniumとPhantomJSを組み合わせたものに置き換えます.
Seleniumはブラウザ動作を自動化するためのツール,PhantomJSはQtベースのブラウザです.1

PhantomJSのインストール

MacやLinuxでは,brewやyumなどのパッケージマネージャで即座にインストールできます.

Mac
brew install phantomjs
CentOS
yum install phantomjs

Windowsでは,http://phantomjs.org/download.html からバイナリをダウンロードして,適当な場所に置いた後に,パスを通しておきます.

Seleniumのインストール

pipですぐできます.

pip install selenium

ソース

SeleniumとPhantomJSを利用すると,スクレイピングのソースは以下のように修正されます.webページ取得以降の手順は変更不要です.
SeleniumでPhantomJSのwebドライバを構成し,そのドライバを通じてHTMLを取得します.以降は同じです.
ドライバの動作ログを記録したい場合には,os.path.devnullをファイル名に変更します.

scraping_js.py
import sys
import json
import os
import requests
from selenium import webdriver
from bs4 import BeautifulSoup
import codecs

def scraping(url, output_name):
    # Selenium settings
    driver = webdriver.PhantomJS(service_log_path=os.path.devnull)
    # get a HTML response
    driver.get(url)
    html = driver.page_source.encode('utf-8')  # more sophisticated methods may be available
    # parse the response
    soup = BeautifulSoup(html, "lxml")
    # extract
    ## title
    header = soup.find("head")
    title = header.find("title").text
    ## description
    description = header.find("meta", attrs={"name": "description"})
    description_content = description.attrs['content'].text
    # output
    output = {"title": title, "description": description_content}
    # write the output as a json file
    with codecs.open(output_name, 'w', 'utf-8') as fout:
        json.dump(output, fout, indent=4, sort_keys=True, ensure_ascii=False)

if __name__ == '__main__':
    # arguments
    argvs = sys.argv
    ## check
    if len(argvs) != 2:
        print "Usage: python scraping.py [url] [output]"
        exit()
    url = argvs[1]
    output_name = argvs[2]

    scraping(url, output_name)

Proxyに対応する

PhantomJSの引数としてproxyの設定を入力することができます.

phantomjs_args = [ '--proxy=proxy.server.no.basho:0000' ]
driver = webdriver.PhantomJS(service_args=phantomjs_args, service_log_path=os.path.devnull)

Cookieに対応する

PhantomJSはデフォルトでCookieが有効になっています.もしcookieファイルを手元に置きたい場合には,PhantomJSの引数に設定することができます.

phantomjs_args = [ '--cookie-file={}'.format("cookie.txt") ]
driver = webdriver.PhantomJS(service_args=phantomjs_args, service_log_path=os.path.devnull)

ソース最終形態

全ての機能をカバーすると,以下のようになります.

scraping_complete.py
import sys
import json
import os
import requests
from selenium import webdriver
from bs4 import BeautifulSoup
import codecs

def scraping(url, output_name):
    # Selenium settings
    phantomjs_args = [ '--proxy=proxy.server.no.basho:0000', '--cookie-file={}'.format("cookie.txt") ]
    driver = webdriver.PhantomJS(service_args=phantomjs_args, service_log_path=os.path.devnull)
    # get a HTML response
    driver.get(url)
    html = driver.page_source.encode('utf-8')  # more sophisticated methods may be available
    # parse the response
    soup = BeautifulSoup(html, "lxml")
    # extract
    ## title
    header = soup.find("head")
    title = header.find("title").text
    ## description
    description = header.find("meta", attrs={"name": "description"})
    description_content = description.attrs['content']
    # output
    output = {"title": title, "description": description_content}
    # write the output as a json file
    with codecs.open(output_name, 'w', 'utf-8') as fout:
        json.dump(output, fout, indent=4, sort_keys=True, ensure_ascii=False)

if __name__ == '__main__':
    # arguments
    argvs = sys.argv
    ## check
    if len(argvs) != 2:
        print "Usage: python scraping.py [url] [output]"
        exit()
    url = argvs[1]
    output_name = argvs[2]

    scraping(url, output_name)

  1. PhantomJSはブラウザですので,IE・Firefox・Chromeなど,一般的に利用されるwebブラウザに置き換えることもできます.詳細は公式ドキュメント http://docs.seleniumhq.org/docs/03_webdriver.jsp#selenium-webdriver-s-drivers を見ると良いと思います.