Instagram上包含“ webdriver等待直到”的循环时,Selenium / Python脚本出错

时间:2018-12-14 18:55:30

标签: python reactjs selenium selenium-webdriver instagram

我正在编写一个脚本,该脚本在instagram照片上设置了喜欢,但在喜欢后(一次14次,一次50次,一次64次),shell给我这个错误:

in <module> ui.WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.CSS_SELECTOR, ".dCJp8.afkep.coreSpriteHeartOpen._0mzm-"))).click() File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/selenium/webdriver/support/wait.py", line 80, in until raise TimeoutException(message, screen, stacktrace) TimeoutException: Message:

我知道问题应该出在webdriver等待中,但是我不知道如何改善我的脚本。

这是我的脚本:

from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import ui
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
import time

driver = webdriver.Chrome(executable_path = '/usr/local/bin/chromedriver')
driver.implicitly_wait(30)
driver.get("https://www.instagram.com/accounts/login/?source=auth_switcher")

#log in 
time.sleep(1)
usm = driver.find_element_by_name('username').send_keys("givcomomvrvglino")
pwd = driver.find_element_by_name('password').send_keys("x")
btnLog = driver.find_element_by_tag_name('form').submit()

#disattiva le notifiche
ui.WebDriverWait(driver,10).until(EC.element_to_be_clickable((By.CSS_SELECTOR,".aOOlW.HoLwm"))).click()

tag = "likeforfollow"

url_to_search = "https://www.instagram.com/explore/tags/" + tag + "/"

driver.get(url_to_search)

contatore = 0

for i in range(500):
  if i == 0:
        ui.WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, ".v1Nh3.kIKUG._bz0w"))).click()
        ui.WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, ".dCJp8.afkep.coreSpriteHeartOpen._0mzm-"))).click()
        ui.WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, ".HBoOv.coreSpriteRightPaginationArrow"))).click()

  else:
        ui.WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, ".dCJp8.afkep.coreSpriteHeartOpen._0mzm-"))).click()
        ui.WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, ".HBoOv.coreSpriteRightPaginationArrow"))).click()

  contatore = contatore + 1

  print(contatore)

  time.sleep(3)

2 个答案:

答案 0 :(得分:0)

首先关于异常。

引自Selenium doc.

TimeoutException当命令未在足够的时间内完成时抛出。

  

WebDriverWait默认情况下每500毫秒调用ExpectedCondition,直到成功返回。对于ExpectedCondition类型,成功返回是Boolean返回true,对于所有其他ExpectedCondition类型,返回值都是非null。

您正在使用Explicit Waits条件。这将等待您指定的条件,然后再继续执行代码。如果驱动程序在指定的时间内找不到该元素,则将抛出TimeoutException。您将需要增加等待时间,以解决在指定的指定时间范围内未加载的元素。

关于如何改进代码,我建议使用Implicit Waits,因为一旦调用此函数,它将在webdriver对象的生命周期内进行设置。

有关设置方法的示例

driver.implicitly_wait(30) # 30 seconds to wait. This tells the Webdriver to poll the DOM for a certain amount of time.
driver.get("http://")
my_element = driver.findElement(By.cssSelector(".v1Nh3.kIKUG._bz0w"))).click()

这一次到期后,将引发异常。隐式等待优于显式等待的好处是您无需重复添加诸如WebDriverWait(driver, 20).until(EC.element_to_be_clickable之类的代码。现在,隐式等待的缺点在于,如果需要,则不允许预期的条件。

如果确实需要使用“显式等待”,则可以在try块中创建一次Webdriver实例,也可以通过设置脚本/方法来完成。我看不到完整的脚本,但是如果您没有在脚本末尾添加quit(),则需要这样做。退出将关闭浏览器并关闭已启动的Driver可执行文件。 Quit()方法可以在finally块中或在tearDown方法中调用。

  
    
      

更新:       其他几点。       您不建议同时使用隐式和显式等待,请查看有关此问题do not mix implicit and explicit waits的更多详细信息。我更新了您的代码,使其仅使用显式代码,但可以轻松对其进行更改,因此我建议您使用。       我还将等待时间增加到30秒,查看第10行

    
  

OR

  

wait = ui.WebDriverWait(驱动程序,30)#等待30秒

我添加了评论,请阅读。

示例

from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import ui
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
import time

try:  
    driver = webdriver.Chrome(executable_path = '/usr/local/bin/chromedriver')
    #=======================================================================
    # Create a single instance for WebDriverWait. 
    # Defines how long to wait.
    #=======================================================================
    wait = ui.WebDriverWait(driver, 30) # wait for 30 seconds

    driver.get("https://www.instagram.com/accounts/login/?source=auth_switcher")

    #log in 
    time.sleep(1)
    usm = driver.find_element_by_name('username').send_keys("givcomomvrvglino")
    pwd = driver.find_element_by_name('password').send_keys("x")
    btnLog = driver.find_element_by_tag_name('form').submit()

    #disattiva le notifiche
    #=======================================================================
    # A successful return is for ExpectedCondition type is Boolean return true or not 
    # null return value for all other ExpectedCondition types.
    #=======================================================================
    element = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR,".aOOlW.HoLwm"))) 
    element.click() # click on element

    tag = "likeforfollow"
    url_to_search = "https://www.instagram.com/explore/tags/" + tag + "/"
    driver.get(url_to_search)

    contatore = 0
    for i in range(500):
        if i == 0:
            #=======================================================================
            # A successful return is for ExpectedCondition type is Boolean return true or not 
            # null return value for all other ExpectedCondition types.
            #=======================================================================
            element = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, ".v1Nh3.kIKUG._bz0w")))
            element.click() # click on element

            element = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, ".dCJp8.afkep.coreSpriteHeartOpen._0mzm-")))
            element.click() # click on element

            element = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, ".HBoOv.coreSpriteRightPaginationArrow")))
            element.click() # click on element
        else:
            element = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, ".dCJp8.afkep.coreSpriteHeartOpen._0mzm-")))
            element.click() # click on element

            element = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, ".HBoOv.coreSpriteRightPaginationArrow")))
            element.click() # click on element    
        contatore = contatore + 1
        print(contatore)
        time.sleep(3)
finally:
    driver.close() # close driver executable and chrome browser.

最后,我看到您正在使用CSS选择器来查找所有元素。我认为CSS选择器和ID是一个不错的选择。现在,关于应始终尝试使用哪些选择器,网上有很多争论,因此您可以简单地进行搜索,但是如果您有兴趣,那是我发现对选择哪种选择器有所帮助的特定讨论。请参考堆栈溢出答案。 selectors

答案 1 :(得分:0)

正如您提到的, shell有时会在点赞之后(一次14次,一次50次,一次64次)给出此错误,因此实际上似乎没有确定/特定的错误。

如果您查看 Instagram DOM Tree

  • css 包含对 react-root

    的引用
    <style type="text/css" data-isostyle-id="786433">#react-root,article,div,footer,header,main,nav,section{-webkit-box-align:stretch;-webkit-align-items:stretch;-ms-flex-align:stretch;align-items:stretch;border:0 solid #000;-webkit-box-sizing:border-box;box-sizing:border-box;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0;margin:0;padding:0;position:relative}</style>
    
  • <body><span>标记开头,其中包含 react-root ,如下所示:

    <span id="react-root">
    

因此您的Locator Strategies基于这些动态类,例如v1Nh3kIKUG_bz0w_0mzm-等,在 Test Execution < / em>。


解决方案

一种适当的解决方案是根据HTML DOM中存在的 satic元素使用定位策略

例如,在 Instagram弹出通知上以文本为不立即的元素上click()的示例,您可以使用以下解决方案:

WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//button[contains(.,'Not Now')]"))).click()

您可以在Click ''Not now" on Instagram notifications ask using Selenium and Python

中找到详细的讨论