はじめに
スクレイピングする際に、ブラウザをスクロールしないとそもそもデータがHTML上に出てこない時(いわゆる無限スクロールが必要な時)はSeleniumが活躍する。
無限スクロールの方法は検索すればいくつかの方法が出てくるが、今回小さな工夫をいれることでパフォーマンスが向上したので残しておく。
よくある方法と問題点
よく見かける方法は、じわじわとページ最下部までスクロールして、スクロール操作をしても高さに変化がなくなった時に終了する方法だ。そしてページ読込にかかる時間を考慮して、所々で一定時間のスリープを入れている。
この方法だと数十回程度のスクロール量であれば上手くいったが、数百回以上のスクロールが必要になった時にはまだスクロール出来るのに勝手に止まることが頻発した。
具体的には https://www.quora.com/ における検索結果を一気に取得しようとした際、本来は数百スクロール出来るのに大体10-20スクロールで止まってしまっていた。
原因
スクロールの回数が多くなるに従って、ロードにかかる時間もじわじわと増えている様で、一定のスリープ時間内にロードが完了せずに、終了判定をくらっていた。
対策
スクロール操作の前後で高さが変わらなかった回数を記録し、その回数によって可変的にスリープ時間を調整するようにした。
結果
所々スタックしながらも、全部のデータを取得できた。
サンプルコード
# スタックした回数によってスリープ時間を調整
def flexible_sleep(stuck_count):
if stuck_count <=5:
return 0.5
else:
return stuck_count/10
# Chromeドライバー設定
chrome_options = Options()
# chrome_options.add_argument("--headless")
chrome_options.add_argument('--user-data-dir=/Users/kaitetsuro/Library/Application Support/Google/Chrome/Profile 3')
driver = webdriver.Chrome(
chrome_options=chrome_options, executable_path="./chromedriver"
)
driver.set_window_size(1200,1000)
driver.get("https://www.quora.com/")
win_height = driver.execute_script("return window.innerHeight")
last_top = 1
# スタックした回数
stuck_count = 0
while True:
last_height = driver.execute_script("return document.body.scrollHeight")
top = last_top
while top < last_height:
top += int(win_height * 0.8)
driver.execute_script("window.scrollTo(0, %d)" % top)
time.sleep(flexible_sleep(stuck_count))
time.sleep(flexible_sleep(stuck_count*2))
new_last_height = driver.execute_script("return document.body.scrollHeight")
if last_height == new_last_height:
time.sleep(10)
driver.execute_script("window.scrollTo(0, %d)" % top)
time.sleep(10)
stuck_count +=1
print(stuck_count)
# 50回スクックしたら諦める
if stuck_count == 50:
break
last_top = last_height
コメント