ぷろぐら×でざいん

動的ページのスクレイピングをSeleniumでやってみた

動的ページのスクレイピングをSeleniumでやってみた

概要

動的に生成されるページをスクレイピングする際に下記のようなコードで実現しました。
ただ、リクエストのレスポンスをスクレイピングしても実際に取りたいオブジェクトが読み込まれていないことがあり、困りました。
今回は seleniumBeaBeautifulSoupで動作を実現していますが、
PhantomJS
を使う方がスマートだと思います。


動的ページとは

ページにアクセスすると一度に全ての情報をレンダリングするのではなく徐々に情報を取得していく主流が殆どのサイトで利用されるようになってきています。理由としてはスマートフォンなどのネット回線が安定しない端末でのアクセスが増加しており、そのようなユーザーにも快適にページを閲覧できるように非同期通信を使っています。AmazonのレコメンデーションやTwitter、インスタグラム、Facebookなどもそうですが、ユーザーが閲覧している座標部分の情報を表示しています。


テストページの仕様

今回テストに使用したページの仕様はユーザーがスクロールダウンすると、その座標にあるイメージの読み込みが行われるページです。スクロールダウンを一気に行うと、途中のイメージの読み込みが行われないため、徐々にスクロールダウンし、全ての座標にあるイメージをブラウザ上で取得する方式を取っています。

ロジック
  1. スクレイピングしたいページを開く
  2. 読み込みを1秒間を行う
  3. 取得すべき要素を全て取得する
  4. 読み込み途中かどうかの判定をかける
  5. 読み込み途中の要素がある場合はスクロールダウンし、読み込みを促す
  6. 読み込み途中の要素が無くなった場合はループを抜け、再度全てのページ情報取得する

コード
import time

from bs4 import BeautifulSoup
from selenium import webdriver

CHROME_PATH = 'WebdriverのDirectory'
LOAD_IMG = 'Loadが終了していない判定文字列'


def scroll_down(url):
    browser = webdriver.Chrome(CHROME_PATH)
    browser.get(url)
    scroll_count = 0

    for i in range(0, 200):
        if scroll_count == 0:
            time.sleep(1)
            
        link_list = []
        soup = BeautifulSoup(browser.page_source, 'html.parser')
        for src in soup.find_all('img'):
            link_list.append(src.get('src'))

        if scroll_count == 100:
            break

        if LOAD_IMG in link_list:
            browser.execute_script('window.scrollBy(0,160)', '')
            scroll_count += 1
            time.sleep(0.3)
            print 'Scroll: {}'.format(scroll_count)
            continue
        else:
            break

    print browser.page_source
    browser.close()
    sleep(0.3)

結果

結果としてはほぼ100%のイメージを取得することができましたが、一部の漏れを生むことになりました。このような動的ページにはAPI URLが用意されていることが多いですが、私が試したサイトにはなかったです。漏れが発生した理由としてはスクロールダウンが速過ぎた結果、イメージの読み込む前に次のイメージ読み込みを開始したのが原因だと思っています。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です