पायथन के लिए सेलेनियम वेबड्राइवर के साथ पेज लोड होने तक प्रतीक्षा करें


181

मैं एक अनंत स्क्रॉल द्वारा कार्यान्वित पृष्ठ के सभी डेटा को परिमार्जन करना चाहता हूं। निम्नलिखित अजगर कोड काम करता है।

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

इसका मतलब है कि हर बार जब मैं नीचे की ओर स्क्रॉल करता हूं, तो मुझे 5 सेकंड प्रतीक्षा करने की आवश्यकता होती है, जो आम तौर पर पृष्ठ के लिए पर्याप्त है ताकि नई उत्पन्न सामग्री को लोड किया जा सके। लेकिन, यह समय कुशल नहीं हो सकता है। पृष्ठ 5 सेकंड के भीतर नई सामग्री लोड करना समाप्त कर सकता है। मैं कैसे पता लगा सकता हूं कि पृष्ठ ने हर बार स्क्रॉल करते समय नई सामग्री लोड की है या नहीं? अगर मुझे यह पता चल सके, तो पेज को लोड करने के बाद मुझे एक बार फिर से अधिक सामग्री देखने के लिए नीचे स्क्रॉल कर सकते हैं। यह अधिक समय कुशल है।


1
यह पृष्ठ के बारे में थोड़ा और जानने में मदद कर सकता है। क्या तत्व अनुक्रमिक या अनुमानित हैं? आप आईडी या xpath का उपयोग करके तत्वों के लोड होने की प्रतीक्षा कर सकते हैं
user2272115

मैं निम्नलिखित पृष्ठ को क्रॉल कर रहा हूं: pinterest.com/cremedelacrumb/yum
apogne


क्या इससे आपके सवाल का जवाब मिलता है? सेलेनियम में पेज लोड होने की प्रतीक्षा करें
Matej J

जवाबों:


234

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डिफ़ॉल्ट रूप से लोड करने के लिए पेज का इंतजार करना होगा। यह फ़्रेम के अंदर या अजाक्स अनुरोध के लिए लोड होने की प्रतीक्षा नहीं करता है। इसका मतलब है कि जब आप उपयोग करते हैं .get('url'), तो आपका ब्राउज़र तब तक इंतजार करेगा जब तक पेज पूरी तरह से लोड नहीं हो जाता है और फिर कोड में अगले कमांड पर जाएं। लेकिन जब आप अजाक्स अनुरोध पोस्ट कर रहे होते हैं, webdriverतो इंतजार नहीं करते हैं और यह आपकी जिम्मेदारी है कि पृष्ठ के लिए उचित समय का इंतजार करें या पेज का एक हिस्सा लोड करने के लिए; इसलिए एक मॉड्यूल नाम है expected_conditions


3
मैं "find_element () तर्क प्राप्त कर रहा था * के बाद एक अनुक्रम होना चाहिए, WebElement नहीं" बदलकर "WebDriverWait (ब्राउज़र, देरी) ।until (EC.presence_of_element_located ((By.ID," IdOfMyElement ")))" मैनुअल सेलेनियम
स्लेप्स

2
@Fragles द्वारा टिप्पणी और डेविड कलन द्वारा जवाब मेरे लिए क्या काम कर रहे थे। शायद इस स्वीकृत जवाब को तदनुसार अपडेट किया जा सकता है?
माइकल ओहलोग ने

6
उत्तीर्ण होने का browser.find_element_by_id('IdOfMyElement')कारण बनता है NoSuchElementExceptionप्रलेखन एक टपल कि इस तरह दिखता है पारित करने के लिए कहते हैं: (By.ID, 'IdOfMyElement')मेरा जवाब
डेविड कुलेन

2
उम्मीद है कि यह किसी और को बाहर करने में मदद करता है क्योंकि यह मेरे लिए शुरू में स्पष्ट नहीं था: WebDriverWait वास्तव में एक वेब ऑब्जेक्ट लौटाएगा जिसे आप तब (जैसे click()) पर एक क्रिया कर सकते हैं , आदि से बाहर पाठ पढ़ें मैं गलत धारणा के तहत था कि यह बस एक प्रतीक्षा के कारण, जिसके बाद आपको अभी भी तत्व ढूंढना था। यदि आप प्रतीक्षा करते हैं, तो बाद में एक तत्व खोजें, सेलेनियम त्रुटि करेगा क्योंकि यह तत्व को खोजने की कोशिश करता है जबकि पुराना इंतजार अभी भी प्रसंस्करण है (उम्मीद है कि समझ में आता है)। नीचे पंक्ति है, आपको WebDriverWait का उपयोग करने के बाद तत्व को खोजने की आवश्यकता नहीं है - यह पहले से ही एक ऑब्जेक्ट है।
बेन विल्सन

1
@Gopgop वाह यह इतना बदसूरत है एक रचनात्मक टिप्पणी नहीं है। इसके बारे में बदसूरत क्या है? इसे और बेहतर कैसे बनाया जा सकता था?
मोडस टॉलेंस

72

(जैसा कि में दिखाया गया है) के find_element_by_idलिए कंस्ट्रक्टर को पास करने की कोशिश की जा presence_of_element_locatedरही है स्वीकृत उत्तर ) NoSuchElementExceptionउठाए जाने के कारण । मैं में सिंटैक्स का उपयोग करने के लिए किया था fragles ' टिप्पणी :

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"

यह मेल खाता है प्रलेखन में उदाहरण से । यहाँ के लिए प्रलेखन के लिए एक कड़ी है ।


2
धन्यवाद! हां, मेरे लिए भी यही जरूरी था। आईडी एकमात्र विशेषता नहीं है जिसका उपयोग किया जा सकता है, पूरी सूची प्राप्त करने के लिए, सहायता (द्वारा) का उपयोग करें। उदाहरण के लिए मैंने इस्तेमाल कियाEC.presence_of_element_located((By.XPATH, "//*[@title='Check All Q1']"))
माइकल ओहलोग ने

यही कारण है कि यह मेरे लिए भी काम करता है! मैंने अलग-अलग लोकेटरों पर विस्तार से एक अतिरिक्त उत्तर लिखा है जो Byऑब्जेक्ट के साथ उपलब्ध हैं ।
J0ANMM

मैंने अपेक्षाओं के साथ एक अनुवर्ती प्रश्न पोस्ट किया है जहां विभिन्न पृष्ठ लोड किए जा सकते हैं, और हमेशा एक ही पृष्ठ नहीं: stackoverflow.com/questions/51641546/…
Liquidgenius

48

नीचे दिए गए 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सिर्फ सच रिटर्न सीधे।

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

यह संभव है कि आईडी की तुलना बासी संदर्भ अपवादों की प्रतीक्षा करने के रूप में प्रभावी नहीं है।

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

अधिक जानकारी के लिए, हैरी के ब्लॉग की जाँच करें ।


आप ऐसा क्यों कहते हैं कि self.driver.execute_script('return document.readyState;')विश्वसनीय नहीं है? यह मेरे उपयोग के मामले के लिए पूरी तरह से काम करता है, जो एक स्थिर टैब (जो कि .get के बजाय दूसरे टैब में जावास्क्रिप्ट के माध्यम से खोला जाता है) में लोड करने के लिए एक स्थिर फ़ाइल की प्रतीक्षा कर रहा है।
आर्थर हेबर्ट

1
@ArthurHebert दौड़ की स्थिति के कारण विश्वसनीय नहीं हो सकता है, मैंने प्रासंगिक हवाला दिया है।
kenorb

23

जैसा कि डेविड कुलेन के जवाब में बताया गया है , मैंने हमेशा निम्नलिखित की तरह एक पंक्ति का उपयोग करने के लिए सिफारिशें देखी हैं:

element_present = EC.presence_of_element_located((By.ID, 'element_id'))
WebDriverWait(driver, timeout).until(element_present)

मेरे लिए सभी संभावित लोकेटरों को ढूंढना मुश्किल था By, जिनका उपयोग किया जा सकता है , इसलिए मुझे लगा कि यहां सूची प्रदान करना उपयोगी होगा। रेयान मिशेल द्वारा अजगर के साथ वेब स्क्रैपिंग के अनुसार :

ID

उदाहरण में प्रयुक्त; तत्वों को उनके HTML आईडी विशेषता द्वारा ढूँढता है

CLASS_NAME

उनके एचटीएमएल वर्ग विशेषता द्वारा तत्वों को खोजने के लिए इस्तेमाल किया। यह फ़ंक्शन CLASS_NAMEकेवल क्यों नहीं है CLASS? फॉर्म का उपयोग करने से object.CLASS सेलेनियम के जावा पुस्तकालय के लिए समस्याएं पैदा होंगी, जहां .classएक आरक्षित पद्धति है। अलग-अलग भाषाओं के बीच सेलेनियम वाक्यविन्यास को सुसंगत रखने के लिए, CLASS_NAMEइसके बजाय उपयोग किया गया था।

CSS_SELECTOR

अपने वर्ग, आईडी, या टैग नाम से तत्व ढूँढता है, का उपयोग करते हुए #idName, .className, tagNameसम्मेलन।

LINK_TEXT

HTML टैग्स को उनके द्वारा लिखे गए पाठ द्वारा ढूँढता है। उदाहरण के लिए, एक लिंक जो कहता है "अगला" का उपयोग करके चुना जा सकता है (By.LINK_TEXT, "Next")

PARTIAL_LINK_TEXT

के समान है LINK_TEXT, लेकिन एक आंशिक स्ट्रिंग पर मेल खाता है।

NAME

HTML टैग्स को उनके नाम विशेषता द्वारा ढूँढता है। यह HTML रूपों के लिए आसान है।

TAG_NAME

HTML टैग्स को उनके टैग नाम से ढूँढता है।

XPATH

मिलान तत्वों का चयन करने के लिए ... एक XPath अभिव्यक्ति का उपयोग करता है।


5
तक के लिए दस्तावेज़ गुण जो लोकेटर के रूप में इस्तेमाल किया जा सकता सूचीबद्ध करता है।
डेविड कुलेन

1
यही तो मैं ढूंढ रहा था! धन्यवाद! खैर, अब यह खोजना आसान होना चाहिए क्योंकि Google मुझे इस प्रश्न पर भेज रहा था, लेकिन आधिकारिक दस्तावेज को नहीं।
J0ANMM

पुस्तक से प्रशस्ति पत्र के लिए धन्यवाद। यह प्रलेखन की तुलना में बहुत स्पष्ट है।
ज़िग्ड


11

एक साइड नोट पर, 100 बार नीचे स्क्रॉल करने के बजाय, आप जांच सकते हैं कि क्या DOM में कोई अधिक संशोधन नहीं हैं (हम पेज के नीचे के मामले में AJAX आलसी-लोडेड हैं)

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

यह उपयोगी है। हालाँकि 500 ​​क्या दर्शाता है? क्या पेज के अंत तक पहुंचने के लिए यह काफी बड़ा है?
मूंदड़ा

यह वह राशि है जिसे पृष्ठ को स्क्रॉल करना चाहिए ... आपको इसे यथासंभव सेट करना चाहिए। मुझे अभी पता चला है कि यह संख्या मेरे लिए पर्याप्त थी, क्योंकि यह पेज को नीचे तक स्क्रॉल करता है जब तक AJAX तत्व आलसी-लोड नहीं होते हैं, फिर से पृष्ठ को फिर से लोड करने की आवश्यकता को
देखते हुए

यह तब मदद करता है जब गिटलैब में किसी मुद्दे पर सभी टिप्पणियों को सुनिश्चित करने की कोशिश की जाती है।
bgStack15

7

क्या आपने कोशिश की है driver.implicitly_wait? यह ड्राइवर के लिए एक सेटिंग की तरह है, इसलिए आप इसे सत्र में केवल एक बार कॉल करते हैं और यह मूल रूप से ड्राइवर को दिए गए समय का इंतजार करने के लिए कहता है जब तक कि प्रत्येक कमांड को निष्पादित नहीं किया जा सकता।

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

इसलिए यदि आप 10 सेकंड का प्रतीक्षा समय निर्धारित करते हैं, तो यह कमांड को जितनी जल्दी हो सके निष्पादित करेगा, 10 सेकंड प्रतीक्षा करने से पहले इसे छोड़ देता है। मैंने इसे इसी तरह के स्क्रॉल-डाउन परिदृश्यों में उपयोग किया है, इसलिए मैं यह नहीं देखता कि यह आपके मामले में काम क्यों नहीं करेगा। आशा है कि यह उपयोगी है।

इस उत्तर को ठीक करने में सक्षम होने के लिए, मुझे नया पाठ जोड़ना होगा। में कम केस 'w' का उपयोग करना सुनिश्चित करें implicitly_wait


अंतर्निहित प्रतीक्षा और वेबड्राइवरिट के बीच अंतर क्या है?
गीत ००

4

कैसे पाश में WebDriverWait डालने और अपवादों को पकड़ने के बारे में।

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"

तुम पाश की जरूरत नहीं है?
कोरी गोल्डबर्ग

4

यहाँ मैंने इसे एक सरल रूप का उपयोग करके किया है:

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

1

आप इस फ़ंक्शन द्वारा बहुत ही सरल कार्य कर सकते हैं:

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

और जब आप पेज लोड होने के बाद कुछ करना चाहते हैं, तो आप उपयोग कर सकते हैं:

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')")
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.