Poczekaj, aż strona zostanie załadowana za pomocą Selenium WebDriver for Python
Chcę zeskrobać wszystkie dane strony zaimplementowanej przez nieskończony zwój. Działa następujący kod Pythona.
for i in range(100):
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
time.sleep(5)
Oznacza to, że za każdym razem, gdy przewijam w dół do dołu, muszę odczekać 5 sekund, co generalnie wystarczy, aby Strona zakończyła Ładowanie nowo Wygenerowanej zawartości. Ale to może nie być efektywne czasowo. Strona może zakończyć ładowanie nowej zawartości w ciągu 5 sekund. Jak mogę sprawdzić, czy strona zakończyła Ładowanie nowej zawartości za każdym razem, gdy przewijam w dół? If I mogę to wykryć, mogę ponownie przewijać w dół, aby zobaczyć więcej treści, gdy tylko dowiem się, że strona została załadowana. To jest bardziej efektywne czasowo.
8 answers
webdriver
będzie czekać na domyślnie załadowaną stronę za pomocą metody .get()
.
Ponieważ być może szukasz jakiegoś konkretnego elementu, jak powiedział @user227215, powinieneś użyć WebDriverWait
, aby poczekać na element znajdujący się na twojej stronie:
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!"
Użyłem go do sprawdzania alertów. Możesz użyć innych metod typu, aby znaleźć lokalizator.
Edytuj 1:
Powinienem wspomnieć, że webdriver
będzie domyślnie czekać na załadowanie strony. Nie czeka na załadowanie wewnątrz ramek ani na żądania ajax. Oznacza to, że gdy używasz .get('url')
, twoja przeglądarka będzie czekać, aż strona zostanie całkowicie załadowana, a następnie przejść do następnego polecenia w kodzie. Ale kiedy publikujesz żądanie ajax, webdriver
nie czeka i Twoim obowiązkiem jest poczekać odpowiednią ilość czasu na załadowanie strony lub części strony; więc istnieje moduł o nazwie expected_conditions
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-17 02:21:44
Próba przekazania find_element_by_id
konstruktorowi dla presence_of_element_located
(Jak pokazano wzaakceptowanej odpowiedzi ) spowodowała podniesienie NoSuchElementException
. Musiałem użyć składni w fragles' komentarz :
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"
Pasuje do przykładu w dokumentacji . Oto link do dokumentacji Dla By.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:10:08
Znajdź poniżej 3 metody:
ReadyState
Sprawdzanie czytelności strony (nie wiarygodne):
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'
Funkcja helpera
wait_for
jest dobra, ale niestetyclick_through_to_new_page
jest otwarta do stanu race, w którym udaje nam się wykonać skrypt na starej stronie, zanim przeglądarka zacznie przetwarzać kliknięcie ipage_has_loaded
od razu zwraca true.
id
Porównywanie nowych identyfikatorów stron ze starymi:
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
It ' s possible porównywanie identyfikatorów nie jest tak skuteczne, jak oczekiwanie na przestarzałe wyjątki referencyjne.
staleness_of
Stosując metodę 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))
[[9]}aby uzyskać więcej informacji, sprawdź Harry ' s blog .
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-03 09:40:01
Z 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"))
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-12 13:43:23
Jak wspomniano w odpowiedź od Davida Cullena , widziałem zawsze zalecane użycie linii jak następujący:
element_present = EC.presence_of_element_located((By.ID, 'element_id'))
WebDriverWait(driver, timeout).until(element_present)
Trudno mi było znaleźć wszędzie wszystkie możliwe lokalizatory, które mogą być używane ze składnią By
, więc pomyślałem, że przydałoby się podać tutaj listę.
Według Scrapowanie stron z Pythonem autor: Ryan Mitchell:
ID
Użyte w przykładzie; wyszukuje elementy przez atrybut HTML id
CLASS_NAME
Używane do znajdowania elementów za pomocą atrybutu klasy HTML. Dlaczego to Funkcja
CLASS_NAME
nie po prostuCLASS
? Korzystanie z formularzaobject.CLASS
tworzy problemy dla Biblioteki Javy Selenium, gdzie.class
jest metoda zarezerwowana. W celu zachowania spójności składni selenu pomiędzy różnymi językami zamiast tego użytoCLASS_NAME
.
CSS_SELECTOR
Znajdź elementy według ich klasy, id lub nazwa znacznika, używając
#idName
,.className
,tagName
zjazd.
LINK_TEXT
Znajduje znaczniki HTML po tekście, który zawierają. Na przykład link, który mówi "Next" można wybrać za pomocą
(By.LINK_TEXT, "Next")
.
PARTIAL_LINK_TEXT
Podobny do
LINK_TEXT
, ale pasuje do częściowego ciągu.
NAME
Znajduje znaczniki HTML według ich atrybutu name. Jest to przydatne dla HTML formularze.
TAG_NAME
Fins tagów HTML według ich nazwy tagu.
XPATH
Używa wyrażenia XPath ... aby wybrać pasujące elementy.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:10:08
Na marginesie, zamiast przewijać 100 razy w dół, Możesz sprawdzić, czy nie ma już żadnych modyfikacji w DOM (jesteśmy w przypadku, gdy dół strony jest 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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-09 16:18:52
Jak o umieszczenie WebDriverWait w pętli While I przechwytywanie WYJĄTKÓW.
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"
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-08 06:44:07
Czy próbowałeś driver.implicitly_wait
. Jest to jak ustawienie dla sterownika, więc wywołujesz go tylko raz w sesji i w zasadzie mówi sterownikowi, aby poczekał określoną ilość czasu, aż każde polecenie może być wykonane.
driver = webdriver.Chrome()
driver.implicitlyWait(10)
Więc jeśli ustawisz czas oczekiwania na 10 sekund, wykonasz polecenie tak szybko, jak to możliwe, czekając 10 sekund, zanim się podda. Używałem tego w podobnych scenariuszach przewijania w dół, więc nie rozumiem, dlaczego miałoby to nie działać w Twoim przypadku. Mam nadzieję, że to pomoże:)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-13 04:36:48