在Selenium中,无法点击通过点击某个按钮显示的菜单中的按钮
我在用Selenium自动点击一个菜单,这样就能抓取一些价格。下面是我的一段代码:
import sched, time
from selenium import webdriver
from selenium.webdriver import Chrome
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
def petjunior(driver):
driver.implicitly_wait(15)
petages = driver.find_element(By.CLASS_NAME, "_container_1dlh7_1._size__xl_1dlh7_72")
petmenu = petages.find_element(By.XPATH, '//*[@title="Select age"]').click()
time.sleep(2)
junclick = petmenu.find_element(By.XPATH, '//*[text()="Junior"]').click()
time.sleep(5)
options = Options()
options.add_argument('--window-size=1296,1115')
options.add_argument("--lang=en-US")
driver = webdriver.Chrome(options=options)
driver.get("https://starpets.gg/adopt-me/shop/pet/hot_doggo/17996")
driver.implicitly_wait(5)
cookiedecl = driver.find_element(By.CLASS_NAME, "cookie__button._button_1fum3_1._button__secondary_1fum3_413._button_mm_1fum3_134._button_fullWidth_1fum3_268._button__text_upper_1fum3_73._button__text_ellipsis_1fum3_76.cookie__button").click()
time.sleep(5)
petjunior(driver)
# A piece of code that I'll be using as example, since this kind of code is repeated several times in my program for all the different buttons and pages
然而,我似乎无法在点击按钮“All”后让它识别菜单,这个按钮是通过以下操作得到的:
petages = driver.find_element(By.CLASS_NAME, "_container_1dlh7_1._size__xl_1dlh7_72")
petmenu = petages.find_element(By.XPATH, '//*[@title="Select age"]').click()
当尝试点击任意按钮,在这个例子中是junior,使用: junclick = petmenu.find_element(By.XPATH, '//*[text()="Junior"]').click(),我得到以下回溯信息和错误:
Traceback (most recent call last):
File "c:\Users\OneDrive\Desktop\testing\test.py", line 25, in <module>
petjunior(driver)
~~~~~~~~~^^^^^^^^
File "c:\Users\OneDrive\Desktop\testing\test.py", line 12, in petjunior
junclick = petmenu.find_element(By.XPATH, '//*[text()="Junior"]').click()
^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'find_element'
如果把petmenu换成driver,如下所示: junclick = driver.find_element(By.XPATH, '//*[text()="Junior"]').click(),它会点击页面上同名的按钮,这会导致页面跳转到一个带有我需要信息的不同链接,而不是简单地把信息加载到预先存在的页面上。通常这没问题,但我需要程序在多个页面上点击所有年龄段,这导致大约一分钟后出现ERR_CONNECTION_TIMED_OUT,尽管我在所有线程中加入time.sleep() 的间隔(各自之间大约10-60秒),只有在重置我的WiFi之后才能访问该网站。
我也尝试让它去寻找下拉菜单中所有按钮的容器,并尝试从那里执行按钮的点击,但得到的结果与上述两种情况类似。
有没有办法阻止它点击不在菜单中的按钮,或在它点击会跳转到不同链接的按钮时防止ERR_CONNECTION_TIMED_OUT?
解决方案
-
implicitly_wait(n) 对动态应用来说已不再那么有效。相反,你需要使用 WebDriverWait。
-
The classname attribute values like
_button_1fum3_1,_button__secondary_1fum3_413are dynamically generated and is bound to change sooner/later. They may change next time you access the application afresh or even while next application startup. So those aren't reliable be used in locators. -
While webscrapping you should always
ACCEPTcookies notification rather declining them. -
click()doesn't returns anything, sononeis assigned back to cookiedecl。 -
Your optimized minimal working code to select Junior is as follows:
``` from selenium import webdriver from selenium.webdriver.chrome.options import Options from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC import time
def petjunior(driver): WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "button[title='Select age']"))).click() WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, "//div[@role='listitem']//div[normalize-space()='Junior']"))).click() time.sleep(5) # time to observe Junior being selected
# -- main -- Usage options = Options() options.add_argument("start-maximized") driver = webdriver.Chrome(options=options) driver.get("https://starpets.gg/adopt-me/shop/pet/hot_doggo/17996") WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, "//div[@class='cookies-notification']//button[contains(@class, 'cookie__button')]//div[contains(., 'Accept')]"))).click() time.sleep(5) petjunior(driver) ```
To click and select each of the list items Newborn, Junior, Pre-Teen, Teen, Post-Teen and Full-Grown one after another your optimized minimal working code is as follows:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time
def petjunior(driver, age_range):
WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "button[title='Select age']"))).click()
WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, f"//div[@role='listitem']//div[normalize-space()='{age_range}']"))).click()
# -- main -- Usage
options = Options()
options.add_argument("start-maximized")
driver = webdriver.Chrome(options=options)
driver.get("https://starpets.gg/adopt-me/shop/pet/hot_doggo/17996")
WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, "//div[@class='cookies-notification']//button[contains(@class, 'cookie__button')]//div[contains(., 'Accept')]"))).click()
time.sleep(5)
petjunior(driver, "Newborn")
time.sleep(5) //time span to observe Newborn being selected
petjunior(driver, "Junior")
time.sleep(5) //time span to observe Junior being selected
petjunior(driver, "Pre-Teen")
time.sleep(5) //time span to observe Pre-Teen being selected
petjunior(driver, "Teen")
time.sleep(5) //time span to observe Teen being selected
petjunior(driver, "Post-Teen")
time.sleep(5) //time span to observe Post-Teen being selected
petjunior(driver, "Full-Grown")