seleniumの2つの待機方法
seleniumの待機方法でsleep.time()を使っている人は、この記事を読んで、心を清めてほしい。
seleniumには、2つの待機方法がある。
- Explicit Waits(明示的な待機)
- Implicit Waits(暗黙的な待機)
この2つの待機方法の使い分けは、こんな感じ。
- Explicit Waits = 複雑な条件で待機させたい
- Implicit Waits = 単純な待機
Implicit Waitsは、要素が出現するまで待機する、という設定になる。
そのため、ごくごく単純なスクレイピング、例えば静的サイトなどであればImplicit Waitsで十分である。
しかし、非同期のWebサイトであればImplicit Waitsでは対応できないことが多い。
例えば、スクロールしてくことでページが読み込まれていくサイトのスクレイピングなど。
非同期のWebサイトからスクレイピングするときは、「このログインボタンがクリックできるようになるまで待つ」などの条件を指定したほうが、エラーは出にくいコードが書ける。
ま、使い分けと言いつつ、実際に使うときはImplicit Waitsに10秒くらい指定して、各ポイントでExplicit Waitsに30秒とかを指定することが多い。
implicitly_waitの使い方
driver = webdriver.Chrome()
driver.implicitly_wait(20)
これだけ。
とても簡単。書くのは1回だけ。
デフォルトは、0が設定されている。
上の例では、要素が読み込まれるまで20秒待機している。
例えば、Webページの読み込むスピードが単純に遅いときは、コードが実行された時点で要素が現れておらず、エラーとなることがある。
selenium.common.exceptions.ElementNotVisibleException: Message: element not visible: Element is not currently visible and may not be manipulated
seleniumを使っていれば、このエラーに100%エンカウントしているはず。
その時は、implicitly_wait(20)の待機時間を充分な時間を指定して、ページが読み込まれるのを待てばいい。
ただ、implicitly_waitは基本的に一律の設定である。
この処理は何秒待つ、とかの指定はできない。
できないことはないけど、絶対に人に見せたくないコードになる。
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
driver.implicitly_wait(5) driver.find_element_by_id("mul_t").send_keys("ログインしたい") driver.implicitly_wait(20) driver.find_element_by_xpath('//*[@id="control_object_class1"]/div/div[3]/div[1]/div').click() driver.implicitly_wait(10) driver.find_element_by_name("forward_sch").click()
Explicit Waitsの使い方
Explicit Waitsは複雑な条件を指定して、条件が満たされるまで待機するという設定ができる。
この例は、"sch"というIDを持つ要素がクリックできるようになるまで最大30待機する、という指示。
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By WebDriverWait(driver, 30).until(EC.element_to_be_clickable((By.ID, "sch"))) # 探している要素↓ よくある検索ボタンのhtmlだと思う。 # <input type="button" value="検索" id="sch">
seleniumの公式ページにものっているし、定番はこれ。
IDが"myDynamicElement"の要素が読み込まれるまで待機。使いやすい。
WebDriverWait(driver, 30).until(EC.presence_of_element_located((By.ID, "myDynamicElement"))
presence_of_element_located以外にも指定できる条件はある。
title_is title_contains presence_of_element_located visibility_of_element_located visibility_of presence_of_all_elements_located text_to_be_present_in_element text_to_be_present_in_element_value frame_to_be_available_and_switch_to_it invisibility_of_element_located element_to_be_clickable staleness_of element_to_be_selected element_located_to_be_selected element_selection_state_to_be element_located_selection_state_to_be alert_is_present
また、By.はID以外も指定できる。
ID XPATH LINK_TEXT PARTIAL_LINK_TEXT NAME TAG_NAME CLASS_NAME CSS_SELECTOR
まとめ
大抵のサイトは、非同期技術が使ってあるため、requestsでリクエストをWebサイトに送って、返ってきたレスポンスをbeautifulsoup4で読み込む、という定番のスクレイピング方法では対応できないことが多い。
ただ、seleniumでも非同期技術を考慮なしに、スクレイピングをしても、とても不安定なコードになってしまう。
面倒ではあるが、ある程度は考えて待機時間は設定したほうが、後々のメンテも楽になるので、がんばりましょう。
最後にtime.sleep()で待機させてから、スクレイピングをしている方へ。
time.sleep()は、要素が読み込まれていようといまいと待機することになるので、時間がもったいないからやめよう。
以上、終わり!!