Seleniumで非同期処理による動的データの待機処理ができない

ホーム » ブログ » スクレイピング » Seleniumで非同期処理による動的データの待機処理ができない

Seleniumでスクレイピングをする際にページの読み込みが完了するまで待機することがよくあります。このような処理を待機処理といいます。

取得する要素が静的に決まっていて、HTMLをパースする時点で要素の値が存在している場合は既存のメソッドで待機処理を実現することが可能ですが、非同期通信(Ajax)によって要素の値が動的に決定される場合、すなわち描画が終わった後に動的な変更によって要素の値が決まる場合は、既存のメソッドで待機処理を実現することができません。

今回の記事ではこうした課題を解決するための手法を紹介します。

背景

使い捨てEメールサービス「10 Minutes Mail」は、ユーザーに割り当てられるEメールは非同期処理によって取得しています。

このEメールをSeleniumで取得することが目標です。

しかしながら、通常の待機処理では非同期的かつ動的なデータを取得するメソッドが用意されていないため、自分で作る必要があります。

通常の待機処理

通常の待機処理は、例として以下が挙げられます。

メソッド条件
visibility_of_element_located指定した要素の表示される
text_to_be_present_in_element指定したテキストが表示される
presence_of_all_elements_locatedページ内のすべての要素が読み込まれる
presence_of_element_locatedDOM要素内に指定した要素が現れる
alert_is_presentAlertが表示される
element_to_be_clickable要素がクリック出来る状態になる
https://office54.net/python/scraping/selenium-wait-time より引用

試したこと

まず初めに試したのは以下です。

# text_to_be_present_in_elementを使う
# Eメールアドレスは待機した後にわかるので待機処理の段階で記述できない。
element = driver_wait.until(EC.text_to_be_present_in_element((By.XPATH, xpath), "{{Eメールアドレス}}"))

しかしながら、このメソッドでは、動的にテキストを指定することができません。当然ですが、どんなEメールアドレスが与えられるかがわからないので、このメソッドにテキストを指定することができないのです。

やりたいこと

Eメールアドレスを取得したいが、どんなEメールアドレスかはわからない。

→正規表現で取ればいいのでは?この時、監視対象のHTML要素に入るのはメールアドレスであることは自明なので、任意の文字列にマッチする正規表現を用いればよい。

結果、書いたコードは以下です。

import re

def email_has_arrived(x):
    element = x.find_element_by_xpath(xpath)
    if bool(re.match("[^ ]", element.get_attribute("value"))):
        return element
    else:
        return False

# メールアドレスを取得
xpath = '//*[@id="mail"]'
element = driver_wait.until(lambda x: email_has_arrived(x))

今回は、「Python Seleniumで汎用waitしたくない?」を参考にしました。詳細はそちらでご確認ください。

また、今回のやり方は正式なものではないので、ちゃんとやりたい方は「Selenium & Python で待機条件をカスタマイズするやり方」を参照されるといいと思います。

関連ブログ

https://kentarojay.com/archives/247

コメントを残す