【问题标题】:UnexpectedTagNameException: Message: Select only works on <select> elements, not on <div> error selecting a country using Selenium and PythonUnexpectedTagNameException:消息:选择仅适用于 <select> 元素,不适用于 <div> 使用 Selenium 和 Python 选择国家/地区时出错
【发布时间】:2020-07-22 17:46:57
【问题描述】:

我想刮迭代散点图。 在此之前,我想更改国家/地区,但我没有选择我想要的国家/地区。

网站链接: https://vizhub.healthdata.org/tobacco/

错误是

---------------------------------------------------------------------------
UnexpectedTagNameException                Traceback (most recent call last)
<ipython-input-46-fa99f3a62600> in <module>
      1 cc=driver.find_element_by_xpath('//*[@id="location_id"]')
----> 2 select_English=Select(cc)
      3 #select_English.select_by_visible_text('English (GB)')

/Applications/anaconda3/lib/python3.7/site-packages/selenium/webdriver/support/select.py in __init__(self, webelement)
     37             raise UnexpectedTagNameException(
     38                 "Select only works on <select> elements, not on <%s>" %
---> 39                 webelement.tag_name)
     40         self._el = webelement
     41         multi = self._el.get_attribute("multiple")

UnexpectedTagNameException: Message: Select only works on <select> elements, not on <div>

我从网站上复制了 xpath,显示它是一个选择元素。

这是我的代码

import selenium
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.select import Select
from selenium.common.exceptions import NoSuchElementException
chrome_optionsme = Options()
chrome_optionsme.add_argument("--incognito")
chrome_optionsme.add_argument("--window-size=1920x1080")
driver = webdriver.Chrome(options=chrome_optionsme, 
                          executable_path="path/chromedriver")
url="https://vizhub.healthdata.org/tobacco/"
driver.get(url)
driver.find_element_by_xpath('//*[@id="data"]').click()
cc=driver.find_element_by_xpath('//*[@id="location_id"]')
select_English=Select(cc)

其次,如何使用 selenium 提取迭代图的数据?

【问题讨论】:

  • 还有&lt;div class="control" id="location_id"&gt;,位于您的选择元素之前。您可以随时使用//select[@id='location_id']
  • @JustinEzequiel 使用您提供的代码后,我尝试选择中国,但失败了。 select_English.select_by_visible_text('China') 出现错误:NoSuchElementException: Message: Could not locate element with visible text: China
  • 很可能是因为该元素不可见。其实select元素本身就有style="display: none"。这表明您通常需要通过单击某个其他元素(例如某处的选项卡或按钮)来使选择元素可见。
  • @JustinEzequiel 添加代码cc.click() 后显示错误ElementNotInteractableException: Message: element not interactable (Session info: chrome=84.0.4147.89) 当我手动单击它时,它是空白的。
  • 是的,因为选择元素是隐藏的(显示:无)。您需要与 //div[@id='s2id_location_id'] 中的元素进行交互

标签: python selenium google-chrome selenium-webdriver selenium-chromedriver


【解决方案1】:

选择元素是一个占位符。点击和其他事件由其他元素处理。

也许您可以完全绕过 HTML。下面返回一个相当大的 JSON。

import requests

import json

CHINA = 6

url = 'https://vizhub.healthdata.org/tobacco/php/getCountryData.php'

r = requests.post(url, data={'location_id': CHINA})

d = json.loads(r.content)

print(d)

【讨论】:

  • 行得通!但是如何在图形中获取实际值而不是坐标/轴值。谢谢。
【解决方案2】:

此错误消息...

UnexpectedTagNameException: Message: Select only works on <select> elements, not on <div>

...暗示您的程序在&lt;div&gt; 元素上调用了Select(),而Select() 仅适用于 标签。


解决方案

可以通过以下方式访问网站https://vizhub.healthdata.org/tobacco/ 中的国家/地区下拉菜单:

  • 使用css_selector:

    a.select2-choice>span
    
  • 使用xpath:

    //a[@class='select2-choice']/span
    

快照:

因此,从 Country 下拉列表中选择 China 可能的解决方案应该是:

driver.get("https://vizhub.healthdata.org/tobacco/")
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//img[@id='data']"))).click()
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//a[@class='select2-choice']/span"))).click()
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//ul[@class='select2-results']//div[@class='select2-result-label' and text()='China']"))).click()

tl;博士

但是,该解决方案在我最后没有起作用,当我继续检查 网页 的 DOM Tree 时,发现某些 &lt;script&gt; 标记指的是 JavaScripts 具有关键字 dist。举个例子:

  • &lt;script type="text/javascript" src="https://unpkg.com/react-dom@15.6.2/dist/react-dom.min.js"&gt;&lt;/script&gt;
  • &lt;script type="text/javascript" src="https://unpkg.com/ihme-ui@0.34.0/dist/ihme-ui.js"&gt;&lt;/script&gt;
  • &lt;script type="text/javascript" src="https://unpkg.com/clipboard@1.7.1/dist/clipboard.min.js"&gt;&lt;/script&gt;
  • &lt;link type="text/css" rel="stylesheet" href="https://unpkg.com/ihme-ui@0.34.0/dist/ihme-ui.css"&gt;

这清楚地表明该网站受到 Bot Management 服务提供商Distil Networks 的保护,并且导航由Selenium 驱动ChromeDriver 发起 发起浏览上下文 em> 被检测到并随后被阻止。


蒸馏

根据文章There Really Is Something About Distil.it...:

Distil 通过观察网站行为和识别抓取工具特有的模式来保护网站免受自动内容抓取机器人的攻击。当 Distil 在一个站点上识别出恶意机器人时,它会创建一个列入黑名单的行为配置文件,并部署到其所有客户。类似于 bot 防火墙,Distil 检测模式并做出反应。

进一步,

"One pattern with Selenium was automating the theft of Web content",Distil 首席执行官 Rami Essaid 在上周接受采访时表示。 "Even though they can create new bots, we figured out a way to identify Selenium the a tool they're using, so we're blocking Selenium no matter how many times they iterate on that bot. We're doing that now with Python and a lot of different technologies. Once we see a pattern emerge from one type of bot, then we work to reverse engineer the technology they use and identify it as malicious".


参考

您可以在以下位置找到一些详细的讨论:

【讨论】:

  • 您好 DebanjanB 先生,感谢您再次回复我的问题。所以它阻止了机器人抓取。 WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//ul[@class='select2-results']//div[@class='select2-result-label' and text()='China']"))).click()你能告诉我这条路是从哪里来的吗?使用请求回复此内容的其他人可以成功地从页面中抓取内容。这是否意味着 requests 的限制比 selenium 少?
  • @JoanMok 如果您手动浏览,您可以验证 DevTools 中的每个元素。我想避免对请求发表任何评论,但从 Selenium 的角度来看,导航由于 Distil 而被阻止。
猜你喜欢
  • 2020-10-30
  • 2020-10-18
  • 1970-01-01
  • 1970-01-01
  • 2013-11-30
  • 2021-04-14
  • 2021-05-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多