SE(たぶん)の雑感記

一応SEやっている筆者の思ったことを書き連ねます。会計学もやってたので、両方を生かした記事を書きたいと考えています。 でもテーマが定まってない感がすごい。

HTMLのスクレイピング:lxmlを使う

このところ、スクレイピングの調べ物が多いです。

実際、本で紹介されていたモジュールで、面白いものがあったので、簡単に紹介します。

読んだ本

honto.jp

翔泳社電子書籍半額セールで買ったうちの一冊です。

PythonでWebリクエストを投げる

これは、標準モジュールはあまり使わず、requestsモジュールを使うことが多いです。

単純なGETリクエストなら、

import requests

res = requests.get(url)

だけで実行できます。

セッションの維持が必要になる場合も、

import requests

s = requests.Session()
s.auth = ('user', 'pass')
s.headers.update({'x-test': 'true'})

# both 'x-test' and 'x-test2' are sent
s.get('http://httpbin.org/headers', headers={'x-test2': 'true'})

のような感じで、わりと簡単に書けます。
作成したSessionオブジェクトを使って、リクエストを実行し続ければいいだけです。

ソースコードRequestsモジュールのヘルプから取得しています。

リクエスト結果を解釈する

GETリクエストを、通常の、普段私たちが見るWebページのURLに対して実行したら、返ってくるのはHTMLです。

スクレイピングは、すごく簡単に言うと、返ってきたHTMLの中身を検索して情報を取り出す作業です。
それを簡略化するのがlxmlモジュールです。

lxml.de

英語しかないですが、雰囲気で読みましょう。
解釈だけならそこまで難しくないです。

要素を取る

XPathで指定すると楽です。

import requests
import lxml.html

# HTMLソースを得る
url = "http://~~~"
r = requests.get(url)
html = r.text

# HTMLをHtmlElementオブジェクトにする
root = lxml.html.fromstring(html)

# XPathを指定して該当する要素のリストを得る
titleH1 = root.xpath("//*[@id=\"cx_contents_block\"]/div/section/h1")

# リストの1番目のテキストを表示する
print(titleH1[0].text)

相対パスを使ってのアクセスも、一度要素を取ってしまえば可能です。

import requests
import lxml.html

# HTMLソースを得る
url = "http://~~~"
r = requests.get(url)
html = r.text

# HTMLをHtmlElementオブジェクトにする
root = lxml.html.fromstring(html)

path = "//*[@id=\"cx_contents_block\"]/div/section/div/div[2]/dl"
dl = root.xpath(path)
# itemprop属性がある要素だけ抽出する
relation_path = ".//*[@itemprop]"
pub = dl[0].xpath(relation_path)

要素のループ

path = "//*[@id=\"cx_contents_block\"]/div/section/div/div[2]/dl"
dl = root.xpath(path)

の後、

relation_path = ".//*[@itemprop]"
pub = dl[0].xpath(relation_path)

と、dl[0]で要素にアクセスしているのですが、これは、xpathの戻り値がlistであるためです。

取得した要素全てに対して処理したい場合、単に

for p in pubs:
    print(p)

のように、forループするだけでいいです。

属性の取得

先ほどの続きです。

pub = dl[0].xpath(relation_path)

for prop in pub:
    # 書籍情報を取得する
    item_prop = prop.attrib.get("itemprop")

上のように、attribを使うと、属性にアクセスできます。

attrib自体はlxmlの独自型ですが、辞書(dict)と同じ感じでアクセスできます。

他の機能

上で書いた本には紹介されているのですが、HTMLを構築する機能もあるようです。*1

おわりに

今回、薄味ですみません。
私が準備している、別の勉強会のネタを流用して、この記事は作られました。

スクレイピング自体は、やってみるとなかなか楽しいですし、情報の収集としては現実的な手法です。
知っておいて損はない、と思っています。

まあ、scrapy使えばいいんじゃね?という話になるのですが、簡単なものなら本当にすぐ作れる、というのが事実です。

ではまた。

*1:フィードを作る、という内容。etreeというクラスが用意されている