私は無限スクロールによって実装されたページのすべてのデータを削りたいです。次のpythonコードは動作します。
for i in range(100):
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
time.sleep(5)
これは、一番下までスクロールするたびに5秒間待つ必要があることを意味します。これは、通常、ページが新しく生成されたコンテンツのロードを完了するのに十分です。しかし、これは時間効率が悪いかもしれません。ページが5秒以内に新しいコンテンツの読み込みを完了することがあります。スクロールダウンするたびに、ページが新しいコンテンツの読み込みを完了したかどうかをどのように検出できますか?これが検出できたら、ページの読み込みが完了したことを確認したら、もう一度スクロールして他のコンテンツを表示できます。これはもっと時間効率的です。
webdriver
は.get()
メソッドを介してデフォルトでページがロードされるのを待ちます。
@ user227215が言ったように特定の要素を探しているかもしれないので、あなたはあなたのページにある要素を待つためにWebDriverWait
を使うべきです:
from Selenium import webdriver
from Selenium.webdriver.support.ui import WebDriverWait
from Selenium.webdriver.support import expected_conditions as EC
from Selenium.webdriver.common.by import By
from Selenium.common.exceptions import TimeoutException
browser = webdriver.Firefox()
browser.get("url")
delay = 3 # seconds
try:
myElem = WebDriverWait(browser, delay).until(EC.presence_of_element_located((By.ID, 'IdOfMyElement')))
print "Page is ready!"
except TimeoutException:
print "Loading took too much time!"
私はアラートをチェックするためにそれを使いました。ロケーターを見つけるために他の型メソッドを使用することができます。
編集1:
webdriver
はデフォルトでページがロードされるのを待つことになるでしょう。フレーム内の読み込みやajaxリクエストを待ちません。つまり、.get('url')
を使用すると、ブラウザはページが完全にロードされるまで待機してから、コード内の次のコマンドに進みます。しかし、あなたがajaxリクエストを投稿しているとき、webdriver
は待たず、ページまたはページの一部がロードされるのを適切な時間待つのはあなたの責任です。そのためexpected_conditions
という名前のモジュールがあります。
find_element_by_id
のコンストラクターにpresence_of_element_located
を渡そうとすると( 受け入れられた回答 を参照)、NoSuchElementException
が発生します。私は fragles ' comment の構文を使わなければなりませんでした:
from Selenium import webdriver
from Selenium.common.exceptions import TimeoutException
from Selenium.webdriver.support.ui import WebDriverWait
from Selenium.webdriver.support import expected_conditions as EC
from Selenium.webdriver.common.by import By
driver = webdriver.Firefox()
driver.get('url')
timeout = 5
try:
element_present = EC.presence_of_element_located((By.ID, 'element_id'))
WebDriverWait(driver, timeout).until(element_present)
except TimeoutException:
print "Timed out waiting for page to load"
以下の3つの方法を見つけます。
ページreadyStateの確認(信頼できない):
def page_has_loaded(self):
self.log.info("Checking if {} page is loaded.".format(self.driver.current_url))
page_state = self.driver.execute_script('return document.readyState;')
return page_state == 'complete'
wait_for
ヘルパー関数は優れていますが、残念ながらclick_through_to_new_page
は、ブラウザーがクリックの処理を開始する前に、古いページでスクリプトを実行する競合状態に対してオープンであり、page_has_loaded
はすぐにtrueを返します。
id
新しいページIDと古いページIDの比較:
def page_has_loaded_id(self):
self.log.info("Checking if {} page is loaded.".format(self.driver.current_url))
try:
new_page = browser.find_element_by_tag_name('html')
return new_page.id != old_page.id
except NoSuchElementException:
return False
IDの比較は、古い参照の例外を待つほど効果的ではない可能性があります。
staleness_of
staleness_of
メソッドの使用:
@contextlib.contextmanager
def wait_for_page_load(self, timeout=10):
self.log.debug("Waiting for page to load at {}.".format(self.driver.current_url))
old_page = self.find_element_by_tag_name('html')
yield
WebDriverWait(self, timeout).until(staleness_of(old_page))
詳細については、 Harryのブログ を確認してください。
から Selenium/webdriver/support/wait.py
driver = ...
from Selenium.webdriver.support.wait import WebDriverWait
element = WebDriverWait(driver, 10).until(
lambda x: x.find_element_by_id("someId"))
David Cullenからの 回答に記載されているように、 では、次のような行を使用することをお勧めします。
element_present = EC.presence_of_element_located((By.ID, 'element_id'))
WebDriverWait(driver, timeout).until(element_present)
By
構文で使用できるすべての可能なロケータをどこにでも見つけることは困難だったので、ここでリストを提供すると便利だと思いました。 Ryan MitchellによるPythonによるWebスクレイピングによると、
ID
例で使用されています。 HTMLのid属性で要素を見つける
CLASS_NAME
HTMLクラス属性によって要素を見つけるために使用されます。この関数
CLASS_NAME
が単にCLASS
ではないのはなぜですか?object.CLASS
という形式を使用すると、SeleniumのJavaライブラリーで問題が発生します。ここで、.class
は予約済みのメソッドです。 Seleniumの構文を異なる言語間で統一するために、代わりにCLASS_NAME
を使用しました。
CSS_SELECTOR
#idName
、.className
、tagName
の規則を使用して、クラス、ID、またはタグ名で要素を検索します。
LINK_TEXT
含まれているテキストでHTMLタグを検索します。たとえば、「次へ」というリンクは
(By.LINK_TEXT, "Next")
を使用して選択できます。
PARTIAL_LINK_TEXT
LINK_TEXT
と似ていますが、部分文字列で一致します。
NAME
Name属性でHTMLタグを見つけます。これはHTMLフォームには便利です。
TAG_NAME
HTMLタグをタグ名でまとめます。
XPATH
XPath式...を使用して、一致する要素を選択します。
ちなみに、100回スクロールダウンする代わりに、DOMへの変更がこれ以上ないかどうかを確認できます(ページの下部がAJAX lazy-loadedである場合)
def scrollDown(driver, value):
driver.execute_script("window.scrollBy(0,"+str(value)+")")
# Scroll down the page
def scrollDownAllTheWay(driver):
old_page = driver.page_source
while True:
logging.debug("Scrolling loop")
for i in range(2):
scrollDown(driver, 500)
time.sleep(2)
new_page = driver.page_source
if new_page != old_page:
old_page = new_page
else:
break
return True
WebDriverWaitをWhileループに入れて例外をキャッチするのはどうですか。
from Selenium import webdriver
from Selenium.webdriver.support.ui import WebDriverWait
from Selenium.webdriver.support import expected_conditions as EC
from Selenium.common.exceptions import TimeoutException
browser = webdriver.Firefox()
browser.get("url")
delay = 3 # seconds
while True:
try:
WebDriverWait(browser, delay).until(EC.presence_of_element_located(browser.find_element_by_id('IdOfMyElement')))
print "Page is ready!"
break # it will break from the loop once the specific element will be present.
except TimeoutException:
print "Loading took too much time!-Try again"
ここで私はやや単純な形を使ってそれをしました:
from Selenium import webdriver
browser = webdriver.Firefox()
browser.get("url")
searchTxt=''
while not searchTxt:
try:
searchTxt=browser.find_element_by_name('NAME OF ELEMENT')
searchTxt.send_keys("USERNAME")
except:continue
driver.implicitly_wait
を試してみましたか。これはドライバの設定に似ているので、セッションで一度だけ呼び出すだけで、基本的には各コマンドを実行できるようになるまで一定時間待つようドライバに指示します。
driver = webdriver.Chrome()
driver.implicitly_Wait(10)
そのため、10秒の待ち時間を設定した場合、コマンドはできるだけ早く実行され、中断するまで10秒待ちます。私はこれを似たようなスクロールダウンのシナリオで使ったので、あなたのケースではうまくいかないのかわかりません。これが役に立つことを願っています。