【问题标题】:Element Not Attached to page document when iterating through web elements遍历 Web 元素时元素未附加到页面文档
【发布时间】:2020-11-09 03:13:25
【问题描述】:

我正在尝试迭代点击 Uber 运动数据中的北美城市。

我已经设置了 Python 代码来选择所有城市的表 (cities_table),将其制成一个列表,并为每个要点击的城市识别按钮(该按钮的标签名称为“a”)。

我的问题是我可以选择表格中的第一个城市(亚特兰大),但是当我尝试返回包含所有城市表格的页面时,我无法点击下一个城市列表,应该是波士顿。

成功进入亚特兰大页面后,我设置了一个 driver.back() 以返回到 citys 表,但是当我尝试移动到列表中的下一个项目时,我收到以下错误消息:

Message: stale element reference: element is not attached to the page document

如何正确点击城市,返回城市表页面,点击NEXT项?

到目前为止,这是我的代码:

# Load Chrome driver and movement.uber.com/cities website
PATH = 'C:\Program Files (x86)\chromedriver.exe'
driver = webdriver.Chrome(PATH)
driver.get('https://movement.uber.com/cities?lang=en-US')

# City loop
cities_table = driver.find_element_by_xpath('/html/body/div[1]/div[1]/div[1]/div[2]/div[1]/div')
cities = cities_table.find_elements_by_tag_name('div')
for city in cities:
    city = city.find_element_by_tag_name('a') # Buttons have tags "a"
    city.click()
    time.sleep(3)
    driver.back()

完整的错误信息如下:

StaleElementReferenceException            Traceback (most recent call last)
<ipython-input-25-a148ef184a6b> in <module>
      6 cities = cities_table.find_elements_by_tag_name('div')
      7 for city in cities:
----> 8     city = city.find_element_by_tag_name('a') # Buttons have tags "a"
      9     city.click()
     10     time.sleep(3)

~\AppData\Roaming\Python\Python37\site-packages\selenium\webdriver\remote\webelement.py in find_element_by_tag_name(self, name)
    303             element = element.find_element_by_tag_name('h1')
    304         """
--> 305         return self.find_element(by=By.TAG_NAME, value=name)
    306 
    307     def find_elements_by_tag_name(self, name):

~\AppData\Roaming\Python\Python37\site-packages\selenium\webdriver\remote\webelement.py in find_element(self, by, value)
    657 
    658         return self._execute(Command.FIND_CHILD_ELEMENT,
--> 659                              {"using": by, "value": value})['value']
    660 
    661     def find_elements(self, by=By.ID, value=None):

~\AppData\Roaming\Python\Python37\site-packages\selenium\webdriver\remote\webelement.py in _execute(self, command, params)
    631             params = {}
    632         params['id'] = self._id
--> 633         return self._parent.execute(command, params)
    634 
    635     def find_element(self, by=By.ID, value=None):

~\AppData\Roaming\Python\Python37\site-packages\selenium\webdriver\remote\webdriver.py in execute(self, driver_command, params)
    319         response = self.command_executor.execute(driver_command, params)
    320         if response:
--> 321             self.error_handler.check_response(response)
    322             response['value'] = self._unwrap_value(
    323                 response.get('value', None))

~\AppData\Roaming\Python\Python37\site-packages\selenium\webdriver\remote\errorhandler.py in check_response(self, response)
    240                 alert_text = value['alert'].get('text')
    241             raise exception_class(message, screen, stacktrace, alert_text)
--> 242         raise exception_class(message, screen, stacktrace)
    243 
    244     def _value_or_default(self, obj, key, default):

StaleElementReferenceException: Message: stale element reference: element is not attached to the page document
  (Session info: chrome=84.0.4147.89)

【问题讨论】:

  • 您为什么要反复点击北美城市?你的用例是什么?
  • 在每个城市中,都有一个我要下载的数据集。所以计划是:点击城市,选择我要下载的数据的具体时间范围(这将完全是另一个循环,因为我必须每天下载单独的 csv 文件,因为 Uber 不提供时间序列数据,只有单时数据),下载 csv 数据并返回北美城市页面,这样我就可以为下一个城市重复该过程。
  • 您的相关代码试验?
  • 抱歉,“代码试验”是什么意思?城市循环是这个线程上的一个,我只是不明白为什么 python/Selenium 无法识别循环中的下一个城市。它说该元素未附加。抱歉,如果我没有正确回答您的问题。
  • 我的意思是代码试验选择我要下载的数据的具体时间范围

标签: python html list selenium loops


【解决方案1】:

出现此错误是因为您正在获取不再存在的 dom 元素的引用。 每次重新加载或刷新页面,或者 dom 发生了一些变化,你之前获得的每一个引用都是无用的。

因此,为了工作,您必须保留已处理内容的引用,并在每次页面更改时更新您的 dom 引用。

# City loop

managed_cities = []
while True:
    cities_table = driver.find_element_by_xpath('/html/body/div[1]/div[1]/div[1]/div[2]/div[1]/div')
    cities = cities_table.find_elements_by_tag_name('div')
    for city in cities:
        # Here you have to find and ID or some unique text that identifies the
        # already processed city in order to skip it
        if city.text in managed_cities:
            continue

        city = city.find_element_by_tag_name('a') # Buttons have tags "a"
        city.click()
        time.sleep(3)
        driver.back()
        break

    # Now, if you have managed all the cities, you can exit from the while
    # otherwise, keep loop until all cities have been processed
    if len(managed_cities) == len(cities):
        break

【讨论】:

猜你喜欢
  • 2018-04-30
  • 1970-01-01
  • 1970-01-01
  • 2018-10-16
  • 1970-01-01
  • 2020-07-03
  • 1970-01-01
  • 2021-12-15
  • 2021-11-25
相关资源
最近更新 更多