【问题标题】:WebDriverException: Message: {"errorMessage":"null is not an objectWebDriverException:消息:{“errorMessage”:“null 不是对象
【发布时间】:2018-02-13 17:55:08
【问题描述】:

this HTML page 执行以下代码时出现错误,但此错误仅发生在/html/body/div[3]/div[1]/div[1]/div[1]/div/div[10]/a/div[1]/div[2]

WebDriverException: Message: {"errorMessage":"null 不是对象 (靠近 '...ull).singleNodeValue.click();...')","re​​quest":{"headers":{"Accept":"application/json","Accept-Encoding":"identity", "Connection":"close","Content-Length":"223","Content-Type":"application/json;charset=UTF-8","Host":"127.0.0.1:34955","User -代理“:”Python http auth"},"httpVersion":"1.1","method":"POST","post":"{\"sessionId\": \"ddd5e2d0-10e4-11e8-8645-3d3d785f60f2\", \"args\": [], \"script\": \"window.document.evaluate('/html/body/div[3]/div1/div1/div1/div/div[10]/a/div1/div[ 2]', 文档,空,9, null).singleNodeValue.click();\"}","url":"/execute","urlParsed":{"anchor":"","query":"","file":"execute", "directory":"/","path":"/execute","re​​lative":"/execute","port":"","host":"","password":"","user" :"","userInfo":"","authority":"","protocol":"","source":"/execute","queryKey":{},"chunks":["execute"] },"urlOriginal":"/session/ddd5e2d0-10e4-11e8-8645-3d3d785f60f2/execute"}} 屏幕截图:可通过屏幕获得

这是代码:

driver = webdriver.PhantomJS()
driver.implicitly_wait(20)
driver.set_window_size(1120, 550)
driver.get("https://topicolist.com/ongoing-ico")

num_options = len(driver.find_elements_by_class_name("w-dyn-item"))
for i in range(num_options):
    xpath = "/html/body/div[3]/div[1]/div[1]/div[1]/div/div[" + str(i+1) + "]/a/div[1]/div[2]"
    print xpath
    execute_script(driver, xpath)

    project_title = driver.find_elements_by_class_name("heading-49")[0].text.strip()
    print project_title

    time.sleep(10)
    driver.back()

driver.quit()


def execute_script(driver, xpath):
    execute_string = "window.document.evaluate('{}', document, null, 9, null).singleNodeValue.click();".format(xpath)

    return driver.execute_script(execute_string)

【问题讨论】:

  • 我的猜测是只有 9 个 DIV 元素满足 xpath。但是,如果没有页面的 HTML,我无法证明或反驳它...
  • @GalAbra:页面 HTML 在第 4 行给出driver.get("https://topicolist.com/ongoing-ico")

标签: python html selenium phantomjs


【解决方案1】:

一个简单的解决方案

您使用一个查询进行计数,另一个进行迭代,从而产生不同的结果。解决这个问题的简单方法是使用相同的查询进行计数和迭代。

哪个查询?这取决于你想要什么,因为你的查询选择了不同的东西(因此你看到的错误):

  1. 您的 CSS 查询获取所有 .w-dyn-item 元素;但这些元素分布在三个.w-dyn-list 容器中——一个用于.gold,一个用于.silver,一个用于.bronze——就目前而言,
  2. 您的 XPath 查询仅从第一个容器 .gold 获取 .w-dyn-item 元素。

如果您只需要 .gold 项目,则必须调整计数查询:

num_options = len(driver.find_elements_by_css_selector(".w-dyn-list.gold .w-dyn-item"))
# ...

如果您想要所有项目,则必须调整迭代查询:

for i in range(num_options):
    xpath = "/html/body/div[3]/div[1]/div[1]/div/div/div[" + str(i+1) + "]/a/div[1]/div[2]"
    # ...

更好的解决方案

但是你做很多工作只是为了点击一个元素。你不需要使用 JavaScript; Selenium 提供WebElement#click() 就是为了这个目的:

items = driver.find_elements_by_class_name("w-dyn-item")
for item in items:
    item.find_element_by_xpath("./a/div/[1]/div[2]").click()

这样比较好,但是 XPath 查询仍然非常具体且不灵活;如果列表项中 DOM 树的排列发生任何变化,您的查询就会中断。此外,XPath 查询也不会告诉我您尝试单击的什么,因此无法告诉我为什么您尝试单击它。

相反,由于您不再向浏览器发送 XPath,您可以使用另一个 CSS 查询以更有弹性的方式更好地表达自己:

items = driver.find_elements_by_class_name("w-dyn-item")
for item in items:
    item.find_element_by_class_name("description").click()
    # ...

现在很明显,您正在尝试单击每个项目的描述。而且由于您没有指定描述出现的位置,因此网站可以(在合理范围内)更改而不会破坏您的脚本。

最佳解决方案

通过更仔细地查看您的脚本,您可以看到您单击项目描述的唯一原因是您可以导航到详细信息页面以提取项目标题。但是该信息已经存在于初始列表中:在每个项目的 <h4> 元素中。

除非列表页面上不存在您需要的其他信息,否则您无需导航到详细信息页面。相反,只需找到 <h4> 元素并提取它们的文本:

item_headings = driver.find_elements_by_css_selector(".w-dyn-item h4")
project_titles = [item_heading.text for item_heading in item_headings]

【讨论】:

  • 赞成强调一个简单的事实 Selenium 提供 WebElement#click() 就是为了这个目的
  • @DebanjanB 虽然它简单且“易于”使用 selenium click()。在许多情况下,你应该避免它(除非它的 E2E 测试,即使那样......)。它比JS慢得多。另一个很大的缺点是,元素必须暴露,否则点击将不起作用。
  • 此代码不返回所有项目标题的列表:items = driver.find_elements_by_class_name("w-dyn-item") for item in items: item.find_element_by_class_name("description").click()
  • @Urban48 如果您查看WebElement#click() 的源代码,它不仅简单且“易于”使用,而且功能强大、有效且经过验证。因此,在使用 Selenium-JavaSelenium-Python 客户端时,首要的试验应该是使用 WebElement#click()。粗略的WebElement#click() 有时会Fail,而我们总是可以求助于JS Click
  • @Markus 对。该代码是您有关错误的问题的答案。您将需要其余代码来完成您的目标。 (但如果您真正需要的只是项目标题,我添加了另一个解决方案,可以更好地获取它们。)
【解决方案2】:

您可以在页面的 HTML 中看到只有 10 个带有 xpath 的 div 元素

/html/body/div[3]/div[1]/div[1]/div[1]/div/div

虽然w-dyn-item 类有 73 个元素(没有元素只有这个类)。

结果是您尝试迭代 10 个数组中的 73 个元素。

【讨论】:

  • 那么,如何提取所有这 73 个项目的标题?
  • 我假设我应该使用num_options = len(driver.find_elements_by_class_name("div-block-26")),我也应该更改这个"/html/body/div[3]/div[1]/div[1]/div[1]/div/div[" + str(i+1) + "]/a/div[1]/div[2]"
  • 我会使用 xpath //*[contains(@class, \"w-dyn-item\")] 来获取所有相关的 div
  • 好的,但是我如何迭代它呢?
  • 与其遍历动态 xpath,不如尝试遍历 WebElement 列表:driver.find_elements_by_class_name("//*[contains(@class, \"w-dyn-item\")]")
猜你喜欢
  • 1970-01-01
  • 2021-10-05
  • 2013-10-31
  • 2018-01-12
  • 2017-12-29
  • 1970-01-01
  • 1970-01-01
  • 2019-08-24
  • 2013-05-11
相关资源
最近更新 更多