Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
271
Help us understand the problem. What is going on with this article?

More than 1 year has passed since last update.

@_akisato

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) != 3:
        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) != 3:
        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) != 3:
        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 を見ると良いと思います. 

271
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
271
Help us understand the problem. What is going on with this article?