はじめに
あけましておめでとうございます。今年もPython界の江古田ちゃんとして頑張っていく所存です。さて id:nishiohirokazu が5分でPythonは便利だと思える記事を元旦から書いていました。
「ほえー、さすが西尾さんや」って思ってたら、西尾さんが「おい山口、5分でPython便利だなーって思える記事書けや」っていう無言の圧力をかけてきたので*1 *2なんとなく書きました。
「5分で」っていうのが読者が読む時間なのか、筆者が書く時間なのかがわからなかったので前者ということにしました。5分で記事とコード両方書くとか無理や。
こんなことないですか
「Webでスクレイピングしたいよー、てへへ。だけど文字コードとかがページごとにバラバラでマジしんどいっす。しかもタグ抜き出すのとかめちゃめんどいっす><」ってことはあったりしませんか?
リンクのタイトルとかも綺麗に抜き出したいなーっていうときにはページの文字コードが問題になってきますよね。でもいちいちどのページがどのエンコードとか調べるのめんどくさいですよね。
最近はPythonでは便利なライブラリが増えたので、簡単にできちゃいます。
やってみよう
用意するもの
- 410 Gone
- 文字コード自動判別ライブラリ
- pyquery: a jquery-like library for python — pyquery 1.2.1 documentation
- jQueryと同様にDOMを扱えるライブラリ
とりあえずeasy_insallでもpipでもいいけど、このライブラリをインストールしましょう。コマンドで一発です。うちの環境ではvirtualenv下でpip使ってるのでそのまま転載。
$ pip install chardet $ pip install pyquery
ただしPyQueryにはlxmlが必要で、lxmlにはlibxml2とlibxsltが必要です。これ用意する時点でちょっと面倒ですね。ブログ書き始めた時点で気づいたけど、まあそれくらいはググってもらえばいっぱい手順がでてくるはず。
Webのスクレイピングをする大まかな手順
ここの「デコードして」っていう部分と「ぶっこぬく」っていう部分がなかなか面倒なのでライブラリ使いましょうっつー話。
こんな感じで書けばいいと思う
import urllib import chardet from pyquery import PyQuery as pq # テスト用URL # METAタグでcharset指定してなくてもちゃんと文字コード判別できるかもテスト urls = [ 'http://python-history-jp.blogspot.com/', # UTF-8 'http://iblinux.rios.co.jp/PyJdoc/lib-j/', # EUC-JP 'http://osksn2.hep.sci.osaka-u.ac.jp/~taku/osx/python/encoding.html', # ISO-2022-JP 'http://www.atmarkit.co.jp/news/200812/04/python.html', # Shift_JIS 'http://pyunit.sourceforge.net/pyunit_ja.html', # EUC-JP, w/o META 'http://www.f7.ems.okayama-u.ac.jp/~yan/python/', # ISO-2022-JP, w/o META 'http://weyk.com/weyk/etc/OpenRPG.html', # Shift_JIS, w/o META ] if __name__ == '__main__': # 各サイトの文字コードを判別 detected = [] for url in urls: data = ''.join(urllib.urlopen(url).readlines()) guess = chardet.detect(data) result = dict(url=url,data=data,**guess) detected.append(result) # 各サイトごとにaタグの文字とリンク先を引っ張ってくる for p in detected: print '%s -> %s (%s)' % (p['url'], p['encoding'], p['confidence']) unicoded = p['data'].decode(p['encoding']) # デコード d = pq(unicoded) for link in d.find('a'): # 見つけたaタグごとにタイトルとURLを抜き出す link_title = pq(link).text() link_url = pq(link).attr.href print ' %s => %s' % (link_title, link_url)
まあ例外処理もしてないのでちゃんと書くならもっと時間かかりますが、ちょっと書くだけならこんなもんでしょう。
さらにリンク先のコンテンツを並列で取りに行ったりとか、そういうことするならeventlet使うのがいいって id:mopemope が言ってました!