【问题标题】:looping through a dropdown menu using Selenium and Python使用 Selenium 和 Python 遍历下拉菜单
【发布时间】:2019-02-27 19:17:54
【问题描述】:

我正在尝试循环浏览此网址上的下拉菜单:https://www.accuform.com/safety-sign/danger-danger-authorized-personnel-only-MADM006

因此,例如,第一个下拉菜单 - 在选项下 - 列出了不同的材料,我想依次选择每个材料,然后从网页中收集一些其他信息,然后再转到下一个材料。这是我当前的代码:

driver = webdriver.Firefox()
driver.get('https://www.accuform.com/safety-sign/danger-danger-authorized-personnel-only-MADM006')

time.sleep(3)

driver.find_element_by_id('x-mark-icon').click()

select = Select(driver.find_element_by_name('Wiqj7mb4rsAq9LB'))
options = select.options
optionsList = []

driver.find_elements_by_class_name('select-wrapper')[0].click()

element = driver.find_element_by_xpath("//select[@name='Wiqj7mb4rsAq9LB']")
actions = ActionChains(driver)
actions.move_to_element(element).perform()

# driver.execute_script("arguments[0].scrollIntoView();", element)


for option in options: #iterate over the options, place attribute value in list
    optionsList.append(option.get_attribute("value"))

for optionValue in optionsList:
    print("starting loop on option %s" % optionValue)
    # select = WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, "//select[@name='Wiqj7mb4rsAq9LB']")))
    # select = Select(select)
    select.select_by_value(optionValue)

我从循环开始,但得到了这个错误:

ElementNotInteractableException: Message: Element <option> could not be scrolled into view

然后我添加了 webdriverwait 并得到一个 TimeoutException 错误。

然后我意识到我可能应该单击保存下拉列表的包装器,所以我添加了单击,它确实弹出了菜单,但我仍然得到了 TimeoutException。

所以我想,也许我应该移动到元素,我用动作链线尝试过,我得到了这个错误

WebDriverException: Message: TypeError: rect is undefined

我试图通过使用此代码来避免该错误:

    # driver.execute_script("arguments[0].scrollIntoView();", element)

这又导致了超时异常。

我对 Python 和 Selenium 很陌生,基本上只是在修改类似问题的 SO 答案中的代码,但没有任何效果。

我正在使用 python 3.6 和当前版本的 Selenium 和 firefox webdriver。

如果有任何不清楚的地方或者您需要更多信息,请告诉我。

非常感谢!

编辑:根据 Kajal Kunda 的回答和 cmets,我已将代码更新为以下内容:

`material_dropdown = driver.find_element_by_xpath("//input[@class='select- 
dropdown']")

driver.execute_script("arguments[0].click();", material_dropdown)

materials=driver.find_elements_by_css_selector("div.select-wrapper 
ul.dropdown-content li")



for material in materials:

    # material_dropdown = 
    driver.find_element_by_xpath("//input[@class='select-dropdown']")

    # driver.execute_script("arguments[0].click();", material_dropdown)

    # materials=driver.find_elements_by_css_selector("div.select-wrapper ul.dropdown-content li")

    material_ele=material.find_element_by_tag_name('span')

if material_ele.text!='':

    material_ele.click()

    time.sleep(5)

    price = driver.find_element_by_class_name("dataPriceDisplay")

    print(price.text)`

结果是它成功打印了第一种材料的价格,但随后又返回: StaleElementReferenceException: Message: The element reference of &lt;li class=""&gt; is stale;...

我尝试了在循环内外添加散列线的变体,但总是得到 StaleElementReferenceException 错误的版本。

有什么建议吗?

谢谢!

【问题讨论】:

  • 你能解决这个问题吗?

标签: python selenium web-scraping


【解决方案1】:

您可以使用requests 完成所有操作。从下拉列表中列出的选项中获取下拉列表,然后将 value 属性连接到请求 URL 中,该 URL 检索包含页面上所有信息的 json。同样的原则适用于添加其他下拉值。每个下拉选择的 id 是下拉选项的 value 属性,并出现在我显示的每个下拉选择的 url 中,以 // 分隔。

import requests
from bs4 import BeautifulSoup as bs

url = 'https://www.accuform.com/product/getSku/danger-danger-authorized-personnel-only-MADM006/1/false/null//{}//WHFIw3xXmQx8zlz//6wr93DdrFo5JV//WdnO0RpwKpc4fGF'
startURL = 'https://www.accuform.com/safety-sign/danger-danger-authorized-personnel-only-MADM006'

res = requests.get(startURL)
soup = bs(res.content, 'lxml')
materials = [item['value'] for item in soup.select('#Wiqj7mb4rsAq9LB option')]
sizes = [item['value'] for item in soup.select('#WvXESrTyQjM3Ciw option')]
languages = [item['value'] for item in soup.select('#WUYWGMePtpmpmhy option')]
units = [item['value'] for item in soup.select('#W91eqaJ0WPXwe9b option')]

for material in materials:
    data = requests.get(url.format(material)).json()
    soup = bs(data['dataMaterialBullets'], 'lxml')
    lines = [item.text for item in soup.select('li')]
    print(lines)
    print(data['dataPriceDisplay'])     
    # etc......

JSON 示例:

【讨论】:

  • 感谢 QHarr,虽然这似乎是一种有趣的方法,但我对转移到不同的软件包并不感兴趣。我已经学习 Selenium 一段时间了,不想从 beautifulsoup 重新开始。尽管它可能会更好,但我正处于这个项目的中间,似乎不是重新开始的好时机。
  • 不用担心。明天我会看到这里有什么答案,也许我会添加一个硒答案。
【解决方案2】:

试试下面的代码。它应该可以工作。

    driver = webdriver.Firefox()
    driver.get('https://www.accuform.com/safety-sign/danger-danger-authorized-personnel-only-MADM006')

    time.sleep(3)
    driver.find_element_by_id('x-mark-icon').click()

    material_dropdown = driver.find_element_by_xpath("//input[@class='select-dropdown']")
    driver.execute_script("arguments[0].click();", material_dropdown)

    #Code for material dropdown
    materials=driver.find_elements_by_css_selector("div.select-wrapper ul.dropdown-content li")


    material_optionsList = []
    for material in materials:
        material_ele=material.find_element_by_tag_name('span')
        if material_ele.text!='':
          material_optionsList.append(material_ele.text)

    print(material_optionsList)

    driver.execute_script("arguments[0].click();", material_dropdown)


    size_dropdown = driver.find_element_by_xpath("(//input[@class='select-dropdown'])[2]")
    driver.execute_script("arguments[0].click();", size_dropdown)

    #Code for size dropdown
    Sizes=driver.find_elements_by_css_selector("div.select-wrapper ul.dropdown-content li")
    size_optionsList = []
    for size in Sizes:
        size_ele=size.find_element_by_tag_name('span')
        if size_ele.text!='':
            size_optionsList.append(size_ele.text)



driver.execute_script("arguments[0].click();", size_dropdown)

输出:

[u'Adhesive Vinyl', u'Plastic', u'Adhesive Dura-Vinyl', u'Aluminum', u'Dura-Plastic\u2122', u'Aluma-Lite\u2122', u'Dura-Fiberglass\u2122', u'Accu-Shield\u2122']

希望你能完成剩下的工作。让我知道它是否适合你。

编辑代码循环并获取材料的价格值。

for material in range(len(materials)):
    material_ele=materials[material]

    if material_ele.text!='':
       #material_optionsList.append(material_ele.text)
       #material_ele.click()
       driver.execute_script("arguments[0].click();", material_ele)
       time.sleep(2)
       price = driver.find_element_by_id("priceDisplay")
       print( price.text)
       time.sleep(2)
       material_dropdown = driver.find_element_by_xpath("//input[@class='select-dropdown']")
       driver.execute_script("arguments[0].click();", material_dropdown)
       materials = driver.find_elements_by_css_selector("div.select-wrapper ul.dropdown-content li")
       material+=2

输出:

$8.31
$9.06
$13.22
$15.91
$15.91

【讨论】:

  • 而不是仅仅重写 OP 的整个脚本并将其放入答案中,如果您能解释您所做的更改以及为什么其他人可以从中学习,这对 OP 和未来的读者来说会很好。
  • @JeffC - 你是对的。我应该提到我所做的。我刚刚更改了定位器并将鼠标悬停在元素上,但我不确定它是否每次都能正常工作。
  • 您需要将该描述放在答案本身中。不是每个人都会阅读所有的 cmets,也不必完全理解您的答案。
  • 感谢 Kajal,但我正在尝试遍历材料、尺寸等下拉列表,而不是按类别分类的商店。我尝试修改您的代码以使用其中之一,但我不断收到此行的 nosuchelementexception:“element = driver.find_element_by_xpath("//span[class='caret']")"
  • 你的 xpath 是错误的。当你传递任何属性时,你应该使用 @ 。 element = driver.find_element_by_xpath("//span[@class='caret']")现在试试。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-12
  • 1970-01-01
  • 2020-07-30
  • 1970-01-01
相关资源
最近更新 更多