Pythonでクローリング・スクレイピングに使えるライブラリいろいろ
2016-12-09追記
「Pythonクローリング&スクレイピング」という本を書きました!
Pythonクローリング&スクレイピング -データ収集・解析のための実践開発ガイド-
- 作者: 加藤耕太
- 出版社/メーカー: 技術評論社
- 発売日: 2016/12/16
- メディア: 大型本
- この商品を含むブログを見る
これはクローラー/スクレイピング Advent Calendar 2014の7日目の記事です。
Pythonでクローリング・スクレイピングするにあたって、いろいろなライブラリがあるので一覧でまとめてみます。
以下の4つのカテゴリにわけて紹介します。
- Webページを取得する
- Webページからデータを抜き出す
- Webページの自動操作
- 総合的なフレームワーク
なんでこれが載ってないの?この説明はおかしい!などありましたらお気軽にお知らせください。なお、この記事はいろいろなライブラリを紹介することを目的にしているので、各ライブラリの細かい説明は他に譲ります。
サンプルで使用するPythonのバージョンは特に断りのない限り3.4で、一部3.xに対応していないライブラリは2.7を使います。
Webページを取得する
urllib.request
21.6. urllib.request — URL を開くための拡張可能なライブラリ — Python 3.4.2 ドキュメント
標準ライブラリです。Python 2.xではurllib2に相当します。
>>> from urllib.request import urlopen >>> f = urlopen('http://qiita.com/advent-calendar/2014') >>> f.code 200 >>> f.getheader('content-type') 'text/html; charset=utf-8' >>> f.info().get_content_charset() 'utf-8' >>> f.read() b'<!DOCTYPE html><html xmlns:og="http://ogp.me/ns#"><head><meta charset="UTF-8" /><title>2014\xe5\xb9\xb4\xe3\x81\xaeAdvent Calendar\xe4\xb8\x80\xe8\xa6\xa7 - Qiita</title><meta charset="UTF-8" />...
requests
Requests: HTTP for Humans — Requests 2.5.0 documentation
HTTP for Humans、人間のためのHTTP Clientです。このサンプルではurllibとの違いがわかりにくいですが、Basic認証を使うなどHTTPヘッダーを扱うときには簡単さが際立ちます。
pip install requests
>>> import requests >>> r = requests.get('http://qiita.com/advent-calendar/2014') >>> r.status_code 200 >>> r.headers['content-type'] 'text/html; charset=utf-8' >>> r.encoding 'utf-8' >>> r.text '<!DOCTYPE html><html xmlns:og="http://ogp.me/ns#"><head><meta charset="UTF-8" /><title>2014年のAdvent Calendar一覧 - Qiita</title><meta charset="UTF-8" />...
aiohttp
Python 3.3から使用可能なasyncioを使って非同期にページを取得できます。多数のWebサイトを高速にクロールしたいときに力を発揮するでしょう。
pip install aiohttp
>>> import asyncio >>> import aiohttp >>> def get_body(url): ... response = yield from aiohttp.request('GET', url) ... return (yield from response.text()) ... >>> loop = asyncio.get_event_loop() >>> loop.run_until_complete(get_body('http://qiita.com/advent-calendar/2014')) '<!DOCTYPE html><html xmlns:og="http://ogp.me/ns#"><head><meta charset="UTF-8" /><title>2014年のAdvent Calendar一覧 - Qiita</title><meta charset="UTF-8" />...
scrapelib
クロール先のサーバーに負荷をかけ過ぎないように、間隔を自動的に調整したりエラー時に自動でリトライしてくれます。内部ではrequestsを使っています。
pip install scrapelib
>>> import scrapelib >>> s = scrapelib.Scraper(requests_per_minute=10) >>> r = s.get('http://qiita.com/advent-calendar/2014') >>> type(r) <class 'requests.models.Response'> >>> r.status_code 200 >>> while True: ... r = s.get('http://qiita.com/advent-calendar/2014') ... r.status_code ... 200 200 200 ...
Webページからデータを抜き出す
html.parser
20.2. html.parser— HTML および XHTML のシンプルなパーサー — Python 3.4.2 ドキュメント
標準ライブラリです。SAX形式のイベント駆動型のAPIなので、あまり複雑な処理には向いていませんが、開始タグだけが必要な時なら手軽に使えます。
Python 2.xではHTMLParserというモジュール名でした。
>>> from html.parser import HTMLParser >>> from urllib.request import urlopen >>> class MyHTMLParser(HTMLParser): ... def handle_starttag(self, tag, attrs): ... if tag == 'a': ... print(dict(attrs).get('href')) ... >>> f = urlopen('http://qiita.com/advent-calendar/2014') >>> parser = MyHTMLParser() >>> parser.feed(f.read().decode('utf-8')) / /login?redirect_to=%2Fadvent-calendar%2F2014 /signup?redirect_to=%2Fadvent-calendar%2F2014 /advent-calendar /advent-calendar/2014 /advent-calendar/2014/new /advent-calendar/2014/muda/feed /advent-calendar/2014/muda /advent-calendar/2014/softlayer2/feed ...
lxml
lxml - Processing XML and HTML with Python
libxml2とlibxsltのPythonバインディングです。処理の高速さと機能の豊富さでは他の追随を許しません。
pip install lxml
>>> import lxml.html >>> root = lxml.html.parse('http://qiita.com/advent-calendar/2014').getroot() >>> root.cssselect('title')[0] <Element title at 0x10b391c78> >>> root.cssselect('title')[0].text '2014年のAdvent Calendar一覧 - Qiita' >>> for a in root.xpath('//a'): ... print(a.get('href')) ... / /login?redirect_to=%2Fadvent-calendar%2F2014 /signup?redirect_to=%2Fadvent-calendar%2F2014 /advent-calendar /advent-calendar/2014 /advent-calendar/2014/new /advent-calendar/2014/muda/feed /advent-calendar/2014/muda /advent-calendar/2014/softlayer2/feed ...
BeautifulSoup4
Beautiful Soup: We called him Tortoise because he taught us.
3まではPure Pythonのため処理の遅さが弱点でしたが、4からはパーサーを選択できるので、lxmlを使えば高速に処理できます。標準ライブラリのパーサーを使えばC拡張を使えない環境でも役立ちます。
日本語ドキュメントが存在するのも、とっつきやすいでしょう。
pip install beautifulsoup4
>>> from urllib.request import urlopen >>> from bs4 import BeautifulSoup >>> f = urlopen('http://qiita.com/advent-calendar/2014') >>> soup = BeautifulSoup(f) >>> soup.title <title>2014年のAdvent Calendar一覧 - Qiita</title> >>> soup.title.string '2014年のAdvent Calendar一覧 - Qiita' >>> for a in soup.find_all('a'): ... print(a.get('href')) ... / /login?redirect_to=%2Fadvent-calendar%2F2014 /signup?redirect_to=%2Fadvent-calendar%2F2014 /advent-calendar /advent-calendar/2014 /advent-calendar/2014/new /advent-calendar/2014/muda/feed /advent-calendar/2014/muda /advent-calendar/2014/softlayer2/feed ...
pyquery
pyquery 1.2.9 : Python Package Index
jQueryライクなAPIを提供するので、jQueryに慣れている人には馴染みやすいでしょう。内部ではlxmlが使われます。
pip install pyquery
>>> from pyquery import PyQuery as pq >>> d = pq(url='http://qiita.com/advent-calendar/2014') >>> d('title') [<title>] >>> d('title').text() '2014年のAdvent Calendar一覧 - Qiita' >>> for a in d('a').items(): ... print(a.attr('href')) ... / /login?redirect_to=%2Fadvent-calendar%2F2014 /signup?redirect_to=%2Fadvent-calendar%2F2014 /advent-calendar /advent-calendar/2014 /advent-calendar/2014/new /advent-calendar/2014/muda/feed /advent-calendar/2014/muda /advent-calendar/2014/softlayer2/feed
feedparser
feedparser 5.1.3 : Python Package Index
RSSなどのフィードをパースするための定番ライブラリです。フィードの種類に依らずに同じ書き方ができるため、標準ライブラリのxml.etree.ElementTreeなんかでパースするより簡単です。
pip install feedparser
>>> import feedparser >>> d = feedparser.parse('http://qiita.com/advent-calendar/2014/crawler/feed') >>> d.feed.title 'クローラー/スクレイピング Advent Calendarの投稿 - Qiita' >>> for entry in d.entries: ... print(entry.link) ... http://blog.takuros.net/entry/2014/12/06/235232 http://blog.takuros.net/entry/2014/12/05/061034 http://happyou-info.hatenablog.com/entry/2014/12/04/005504 http://qiita.com/nezuq/items/3cc9772118ad112c18dc http://blog.takuros.net/entry/2014/12/02/234959
Webページの自動操作
Mechanize
PerlのWWW:MechanizeのPython版です。ログインが必要なページのスクレイピングに向いています。最終更新は2011年で、Python 3に対応していません。以下のサンプルはPython 2.7で動かしたものです。6日目のdkfjさんの記事と同様にAmazonアソシエイトから売上を取得するサンプルです。
pip install mechanize pip install lxml # lxmlはサンプルで使用しているだけで必須ではありません
>>> import mechanize >>> import lxml.html >>> br = mechanize.Browser() >>> br.addheaders = [('User-agent', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36')] >>> br.open('https://affiliate.amazon.co.jp') <response_seek_wrapper at 0x1020b95f0 whose wrapped object = <closeable_response at 0x1020bd878 whose fp = <socket._fileobject object at 0x100d1a350>>> >>> print(br.title()) Amazonアソシエイト(アフィリエイト)プログラムに参加しよう! >>> br.select_form(name='sign_in') >>> br['username'] = 'YOUR_EMAIL' >>> br['password'] = 'YOUR_PASSWORD' >>> response = br.submit() >>> print(br.title()) Amazon アソシエイト(アフィリエイト) - ホーム >>> root = lxml.html.parse(response).getroot() >>> print(root.cssselect('#mini-report .line-item-total .data')[0].text) ¥0
selenium
selenium 2.44.0 : Python Package Index
SeleniumのPythonバインディングです。FirefoxやChromeなどのブラウザを自動操作したり、PhantomJSのようなヘッドレスブラウザを使うことができます。JavaScriptを使ったページにも対応できる点が強みです。
pip install selenium
>>> from selenium import webdriver >>> driver = webdriver.Firefox() >>> driver.get('https://affiliate.amazon.co.jp') >>> driver.title 'Amazonアソシエイト(アフィリエイト)プログラムに参加しよう!' >>> driver.find_element_by_name('username').send_keys('YOUR_EMAIL') >>> driver.find_element_by_name('password').send_keys('YOUR_PASSWORD') >>> driver.find_element_by_name('password').submit() >>> driver.title 'Amazon アソシエイト(アフィリエイト) - ホーム' >>> driver.find_element_by_css_selector('#mini-report .line-item-total .data').text '¥0'
Splinter
Splinter — Splinter 0.7.0 documentation
SeleniumのFirefox, Chrome, Remote, PhantomJSの各種ドライバーに加えて、zope.testbrowserなどもラップしており目的に応じて使い分けられます。シンプルで使いやすいAPIが特徴です。
pip install splinter
デフォルトではFirefox WebDriverが使われますが、以下のサンプルではPhantomJS WebDriverを使います。*1
PhantomJSがインストールされていない場合はインストールします。Mac以外の方はググってください。。
brew install phantomjs
>>> from splinter import Browser >>> browser = Browser('phantomjs', user_agent='Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36') >>> browser.visit('https://affiliate.amazon.co.jp') >>> browser.title.decode('utf-8') 'Amazonアソシエイト(アフィリエイト)プログラムに参加しよう!' >>> browser.fill('username', 'YOUR_EMAIL') >>> browser.fill('password', 'YOUR_PASSWORD') >>> browser.find_by_value('サインイン').click() >>> browser.title.decode('utf-8') 'Amazon アソシエイト(アフィリエイト) - ホーム' >>> browser.find_by_css('#mini-report .line-item-total .data').text '¥0'
総合的なフレームワーク
Scrapy
Scrapy | A Fast and Powerful Scraping and Web Crawling Framework
Pythonが誇るスクレイピングフレームワークです。Python 3への対応作業は進められていますが、現在はPython 2.7のみ対応です。
pip install scrapy
他のライブラリと違いフレームワークなので、インタラクティブシェルを使わずにファイルを作成します。
advent_spider.py
from scrapy import Spider, Item, Field class AdventCalendar(Item): title = Field() class AdventCalendarSpider(Spider): name = 'advent_spider' start_urls = ['http://qiita.com/advent-calendar/2014'] def parse(self, response): return [AdventCalendar(title=e.extract()) for e in response.css('td.adventCalendar_calendarList_calendarTitle a:nth-child(2)::text')]
$ scrapy runspider advent_spider.py ... 2014-12-07 22:47:47+0900 [advent_spider] DEBUG: Crawled (200) <GET http://qiita.com/advent-calendar/2014> (referer: None) 2014-12-07 22:47:47+0900 [advent_spider] DEBUG: Scraped from <200 http://qiita.com/advent-calendar/2014> {'title': u'1\u5186\u306b\u3082\u306a\u3089\u306a\u3044\u7121\u99c4\u306a\u6280\u8853'} 2014-12-07 22:47:47+0900 [advent_spider] DEBUG: Scraped from <200 http://qiita.com/advent-calendar/2014> {'title': u'1\u5206\u3067\u5b9f\u73fe\u3067\u304d\u308b\u6709\u7528\u306a\u6280\u8853'} 2014-12-07 22:47:47+0900 [advent_spider] DEBUG: Scraped from <200 http://qiita.com/advent-calendar/2014> {'title': u'2\u679a\u76ee SoftLayer '} 2014-12-07 22:47:47+0900 [advent_spider] DEBUG: Scraped from <200 http://qiita.com/advent-calendar/2014> {'title': u'Abby'} 2014-12-07 22:47:47+0900 [advent_spider] DEBUG: Scraped from <200 http://qiita.com/advent-calendar/2014> {'title': u'Adobe'} 2014-12-07 22:47:47+0900 [advent_spider] DEBUG: Scraped from <200 http://qiita.com/advent-calendar/2014> {'title': u'AngularJS'} ...
このサンプルはフレームワークとしての通常の使い方ではないので、以前書いた記事もどうぞ。
PythonとかScrapyとか使ってクローリングやスクレイピングするノウハウを公開してみる! - orangain flavor
まとめ
いかがでしたでしょうか。いろいろな選択肢を知り、適切なものを選ぶ助けになれば幸いです。
複数のライブラリを紹介した3つのカテゴリにおいて1つを選ぶとしたら、個人的には以下のものが定番かと思います。
- Webページを取得する:requests
- Webページからデータを抜き出す:lxml
- Webページの自動操作:selenium
今回調べて初めて知ったライブラリもありました。他にももっと良いものがありましたらぜひ教えて下さい。