Wacht tot de pagina is geladen met Selenium WebDriver voor Python

Ik wil alle gegevens van een pagina die is geïmplementeerd door een oneindige scroll, schrapen. De volgende python-code werkt.

for i in range(100):
    driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
    time.sleep(5)

Dit betekent dat elke keer dat ik naar beneden scrol, ik 5 seconden moet wachten, wat over het algemeen genoeg is om de pagina de nieuw gegenereerde inhoud te laten laden. Maar dit is misschien niet tijdbesparend. De pagina kan binnen 5 seconden klaar zijn met het laden van de nieuwe inhoud. Hoe kan ik detecteren of de pagina klaar is met het laden van de nieuwe inhoud elke keer dat ik naar beneden scrol? Als ik dit kan detecteren, kan ik weer naar beneden scrollen om meer inhoud te zien zodra ik weet dat de pagina is geladen. Dit is meer tijdbesparend.


Antwoord 1, autoriteit 100%

De webdriverwacht tot een pagina standaard is geladen via de methode .get().

Omdat je misschien op zoek bent naar een specifiek element, zoals @user227215 zei, moet je WebDriverWaitgebruiken om te wachten op een element op je pagina:

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!"

Ik heb het gebruikt om waarschuwingen te controleren. U kunt elk ander type methode gebruiken om de locator te vinden.

BEWERK 1:

Ik moet vermelden dat de webdriverstandaard wacht tot een pagina is geladen. Het wacht niet op het laden in frames of op ajax-verzoeken. Dit betekent dat wanneer je .get('url')gebruikt, je browser wacht tot de pagina volledig is geladen en dan naar de volgende opdracht in de code gaat. Maar wanneer u een ajax-verzoek plaatst, wacht webdriverniet en is het uw verantwoordelijkheid om een gepaste hoeveelheid tijd te wachten voordat de pagina of een deel van de pagina is geladen; dus er is een module met de naam expected_conditions.


Antwoord 2, autoriteit 29%

Proberen find_element_by_iddoor te geven aan de constructor voor presence_of_element_located(zoals getoond in de geaccepteerd antwoord) zorgde ervoor dat NoSuchElementExceptionwerd verhoogd. Ik moest de syntaxis gebruiken in fraglescommentaar:

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"

Dit komt overeen met het voorbeeld in de documentatie. Hier is een link naar de documentatie voor By.


Antwoord 3, autoriteit 19%

Vind hieronder 3 methoden:

readyState

Pagina readyState controleren (niet betrouwbaar):

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'

De wait_forhelperfunctie is goed, maar helaas staat click_through_to_new_pageopen voor de raceconditie waarbij we erin slagen om het script op de oude pagina uit te voeren, voordat de browser is gestart het verwerken van de klik, en page_has_loadedgeeft meteen true terug.

id

Nieuwe pagina-ID’s vergelijken met de oude:

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

Het is mogelijk dat het vergelijken van ID’s niet zo effectief is als wachten op verouderde referentie-uitzonderingen.

staleness_of

Met behulp van de staleness_ofmethode:

@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))

Controleer Harry’s blog .


Antwoord 4, autoriteit 7%

Van 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"))

Antwoord 5, autoriteit 5%

Trouwens, in plaats van 100 keer naar beneden te scrollen, kun je controleren of er geen wijzigingen meer zijn aan de DOM (we zijn in het geval dat de onderkant van de pagina AJAX lui is geladen)

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

Antwoord 6, autoriteit 4%

Heb je driver.implicitly_waitgeprobeerd. Het is als een instelling voor de bestuurder, dus je roept het maar één keer in de sessie aan en het vertelt de bestuurder in feite dat hij de opgegeven hoeveelheid tijd moet wachten totdat elk commando kan worden uitgevoerd.

driver = webdriver.Chrome()
driver.implicitly_wait(10)

Dus als je een wachttijd van 10 seconden instelt, zal het de opdracht zo snel mogelijk uitvoeren en 10 seconden wachten voordat het opgeeft. Ik heb dit in vergelijkbare scrolscenario’s gebruikt, dus ik zie niet in waarom het in jouw geval niet zou werken. Ik hoop dat dit nuttig is.

Om dit antwoord te kunnen corrigeren, moet ik nieuwe tekst toevoegen. Zorg ervoor dat u een kleine letter ‘w’ gebruikt in implicitly_wait.


Antwoord 7, autoriteit 2%

Hier deed ik het met een vrij eenvoudig formulier:

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

Antwoord 8, autoriteit 2%

Oplossing voor ajax-pagina’s die continu gegevens laden. De vermelde voorbeeldmethoden werken niet. Wat we in plaats daarvan kunnen doen, is de pagina dom pakken en deze hashen en oude en nieuwe hash-waarden met elkaar vergelijken over een delta-tijd.

import time
from selenium import webdriver
def page_has_loaded(driver, sleep_time = 2):
    '''
    Waits for page to completely load by comparing current page hash values.
    '''
    def get_page_hash(driver):
        '''
        Returns html dom hash
        '''
        # can find element by either 'html' tag or by the html 'root' id
        dom = driver.find_element_by_tag_name('html').get_attribute('innerHTML')
        # dom = driver.find_element_by_id('root').get_attribute('innerHTML')
        dom_hash = hash(dom.encode('utf-8'))
        return dom_hash
    page_hash = 'empty'
    page_hash_new = ''
    # comparing old and new page DOM hash together to verify the page is fully loaded
    while page_hash != page_hash_new: 
        page_hash = get_page_hash(driver)
        time.sleep(sleep_time)
        page_hash_new = get_page_hash(driver)
        print('<page_has_loaded> - page not loaded')
    print('<page_has_loaded> - page loaded: {}'.format(driver.current_url))

Antwoord 9, autoriteit 2%

Wat dacht je ervan om WebDriverWait in een While-lus te plaatsen en de uitzonderingen op te vangen.

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"

Antwoord 10

Je kunt dat heel eenvoudig doen met deze functie:

def page_is_loading(driver):
    while True:
        x = driver.execute_script("return document.readyState")
        if x == "complete":
            return True
        else:
            yield False

en als u iets wilt doen nadat het laden van de pagina is voltooid, kunt u het volgende gebruiken:

Driver = webdriver.Firefox(options=Options, executable_path='geckodriver.exe')
Driver.get("https://www.google.com/")
while not page_is_loading(Driver):
    continue
Driver.execute_script("alert('page is loaded')")

Antwoord 11

gebruik dit in code:

from selenium import webdriver
driver = webdriver.Firefox() # or Chrome()
driver.implicitly_wait(10) # seconds
driver.get("http://www.......")

of u kunt deze code gebruiken als u op zoek bent naar een specifieke tag :

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
driver = webdriver.Firefox() #or Chrome()
driver.get("http://www.......")
try:
    element = WebDriverWait(driver, 10).until(
        EC.presence_of_element_located((By.ID, "tag_id"))
    )
finally:
    driver.quit()

Antwoord 12

Heel goede antwoorden hier. Snel voorbeeld van wachten op XPATH.

# wait for sizes to load - 2s timeout
try:
    WebDriverWait(driver, 2).until(expected_conditions.presence_of_element_located(
        (By.XPATH, "//div[@id='stockSizes']//a")))
except TimeoutException:
    pass

Other episodes