Robobrowser + α によるスクレイピングの忘備録
Pythonクローリング&スクレイピング -データ収集・解析のための実践開発ガイド-』を読んでしばらく Robobrowser を使ってみようと思うので、その忘備録。
基本
browser = RoboBrowser( parser='html.parser', # Cookie が使用できないと表示されてログインできない問題を回避するため、通常のブラウザの User-Agent を使う。 user_agent='Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:45.0) Gecho/20100101 Firefox/45.0)' ) broswer.open(スクレイピング対象のページのURL) # 取得したページの中身の確認。デバッグ時以外は不要。 # print(broswer.parsed)
user_agent の指定はサイトによっては不要。少なくとも Amazon.co.jp については必要(設定しない状態で open すると、取得できる html で Cookie を有効にして下さい、という旨のメッセージが入っていることがわかる)。
以降のコード例は基本的に上記の続きで broswer が Robobrowser インスタンスを表すものとする。
CSSセレクターを使った要素の取得
select
関数で CSSセレクターを使用可能。条件に一致する要素の配列が取得できる。
条件を指定して要素を取得する関数としては find_all
関数も利用できるので、好みで。find_all
の方が柔軟かもしれない。
実際に使用したことのある一部の例のみ記載。
探したい要素 | 書き方 | 例 |
---|---|---|
特定のクラスを持つ要素 | 要素.クラス | a.active |
特定の要素の子孫 | 要素 要素 | body h1 |
特定の要素の直接の子 | 要素 > 要素 | body > h1 |
特定のID属性 | #ID | #main |
属性が特定の値 | 要素[属性=“値”] | a[href=“/sample/index.html”] |
属性が特定の値で始まる | 要素[属性^=“値”] | span[id^=“itemPrice_” ] |
属性が特定の値で終わる | 要素[属性$=“値”] | img[src$=“.jpg” ] |
以下の例では g-item-details というクラスを持った div 要素を取得し、取得した各要素に更に select
を実行して必要な値を取得している
for item_info_element in browser.select('div.g-item-details'): title = item_info_element.select('a[id^="itemName_"]') assert len(title) == 1 # text でテキストを取得。 title = title[0].text.strip() # href 属性をキーにリンク先を取得 # 要 from urllib.parse import urljoin url = urljoin(browser.url, title[0]['href']) # URL の ref= 以降は不要。 url = item.url[:item.url.find('ref=')] price = item_info_element.select('span[id^="itemPrice_"]') # 必要な処理を続ける
特定のテキストを持ったリンク
get_link
関数の第一引数でテキストを指定する。取得したリンクを開くには follow_link
関数を使用する。
# この例ではリンク先(href の値)が特定の URL パターンに一致することも確認している sign_in_link = browser.get_link('サインイン', href=re.compile(r'https://www\.amazon\.co\.jp/ap/signin\?')) # assert sing_in_link is not None # browser.follow_link(sign_in_link)
フォーム
action をキーに get_form
関数を使って取得。
name 要素をキーに各入力欄にアクセスして値を設定し、submit_form
関数で実行
browser.follow_link(sign_in_link) form = browser.get_form(action='https://www.amazon.co.jp/ap/signin') if form is None: raise Exception('Failed to get signin link.') form['email'] = '.....@gmail.com' form['password'] = 'secret, of course!' browser.submit_form(form, headers={ 'Referer': browser.url, 'Accept-Language': 'ja,en-US;q=0.7;q=0.3' })
Amazon では Referer と Accept-Language の設定が必要。必要ないサイトもある。この辺りの必要性は実際に確かめるしか無い?
関数のリトライ設定
Retrying パッケージを使用して、関数に @retry デコレータを使用する
@retry(stop_max_attempt_number=3, wait_exponential_multiplier=1000) def signin() -> RoboBrowser: # 処理に失敗した場合は raise Exception('失敗の理由') などで例外を発生させる