Scrapy响应返回空数组

5lwkijsr  于 5个月前  发布在  其他
关注(0)|答案(2)|浏览(53)

我正在用scrappy抓取这个page,并试图提取主表的所有行。
下面的**表达式应该给予我想要的结果:

//div[@id='TableWithRules']//tbody/tr

字符串
使用scrap shell进行测试让我注意到这个表达式确实返回了一个空数组:

#This response is empty: []
response.xpath("//div[@id='TableWithRules']//tbody").extract()
#This one is not:
response.xpath("//div[@id='TableWithRules']//thead").extract()


我猜网站所有者试图限制对表数据的抓取,但有没有办法找到一个解决方案?

wa7juj8i

wa7juj8i1#

这是因为你试图查询一个不存在的元素。tbody元素通常被浏览器注入到html中,实际上在呈现之前并不存在于源html中。如果你检查页面源,你可以看到这一点。
获取所有行的一个可能的解决方法是简单地绕过tbody标记并直接查询行:
示例:scrapy shell https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=hp

In [1]: rows = response.xpath("//div[@id='TableWithRules']//tr")

In [2]: len(rows)
Out[2]: 3366

字符串
或者,如果你想跳过标题行,那么你可以这样做。

In [1]: rows = response.xpath("//div[@id='TableWithRules']//tr[td]")

In [2]: len(rows)
Out[2]: 3365

ldxq2e6h

ldxq2e6h2#

如果您在控制台中运行此JavaScript,它将从页面中提取所有名称和描述。

let trs = document.querySelectorAll('#TableWithRules tbody tr')

trs.forEach((el) => {
    let tds = el.querySelectorAll('td')
    let name = tds[0].innerText;
    let description = tds[1].innerText;
    console.log(name, description)
})

字符串
使用Selenium的相同代码,例如:

from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By

driver = webdriver.Firefox()
driver.get("https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=hp")

trs = driver.find_elements(By.XPATH, "//div[@id='TableWithRules']//tbody//tr")
for tr in trs:
    tds = tr.find_elements(By.XPATH, ".//td")
    name = tds[0].text
    description = tds[1].text
    print(name, description)

driver.close()

输出

...
CVE-1999-0016 Land IP denial of service.
CVE-1999-0014 Unauthorized privileged access or denial of service via dtappgather program in CDE.
CVE-1999-0011 Denial of Service vulnerabilities in BIND 4.9 and BIND 8 Releases via CNAME record and zone transfer.
CVE-1999-0010 Denial of Service vulnerability in BIND 8 Releases via maliciously formatted DNS messages.
CVE-1999-0009 Inverse query buffer overflow in BIND 4.9 and BIND 8 Releases.
...

代码说明

首先,从#TableWithRules表中的tbody中检索所有tr元素。然后,构造一个for循环来遍历这些tr元素,提取其中包含的所有td元素。通常,有两个td元素:一个用于name,另一个用于description。继续从td[0]td[1]获取文本。

什么是“头”?

THEAD的过程与上面描述的类似。主要区别在于目标是THEAD而不是TBODY,并且关注th元素而不是td

相关问题