使用Scrapy抓取网页时无法获取隐藏表格内容的求助
我之前也碰到过类似的坑——用Scrapy直接爬CME Group这个页面的表格时,明明浏览器里能看到表格,右键检查也能定位到元素,但Scrapy Shell里用response.xpath('//*[@table]')(哦对了,你这个xpath写法其实也有问题,应该是//table或者带id/class的精准选择器)却拿不到任何结果。
核心原因很简单:这个表格是通过JavaScript动态渲染出来的。Scrapy默认获取的是服务器返回的静态HTML,而浏览器里看到的是JS执行后生成的DOM,两者完全不一样。你右键看到的==$0是浏览器渲染后的元素,自然不在Scrapy拿到的原始响应里。
那怎么解决呢?最靠谱的办法就是结合Selenium来完成这个Scrapy任务——Selenium可以模拟真实浏览器的行为,等待页面上的JS完全执行、元素加载完成后,再去抓取内容,特别适合处理这种动态渲染甚至有JS加密的表格。
给你一个简单的实现思路和示例代码:
- 先安装依赖:
pip install selenium,同时下载对应浏览器的驱动(比如ChromeDriver,要和你的Chrome版本匹配)。 - 在Scrapy的Spider里集成Selenium,模拟浏览器访问页面,等待表格加载:
from scrapy import Spider from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC class CMEBlockDataSpider(Spider): name = 'cme_block_data' start_urls = ['http://cmegroup.com/clearing/operations-and-deliveries/accepted-trade-types/block-data.html/#contractTypes=FUT&exchanges=XNYM&assetClassId=0'] def __init__(self): # 初始化浏览器驱动,记得把ChromeDriver的路径配置好,或者放在环境变量里 self.driver = webdriver.Chrome() def parse(self, response): self.driver.get(response.url) # 等待表格元素出现,超时时间设为10秒,可以根据实际加载速度调整 try: table = WebDriverWait(self.driver, 10).until( EC.presence_of_element_located((By.XPATH, '//table')) ) # 提取表格里的每一行和每一列内容 rows = table.find_elements(By.TAG_NAME, 'tr') for row in rows: cols = row.find_elements(By.TAG_NAME, 'td') # 跳过表头(如果表头用<th>标签,也可以单独处理) if not cols: continue # 把每一行的内容整理成item yield { 'contract_type': cols[0].text.strip(), 'exchange': cols[1].text.strip(), 'asset_class': cols[2].text.strip(), # 其他列根据实际表格结构调整字段名 } finally: # 不管成功失败,最后一定要关闭浏览器 self.driver.quit()
另外补个小提醒:你之前用的response.xpath('//*[@table]')是错误的选择器写法——@table是找带有table属性的元素,而不是找<table>标签,正确的写法应该是//table或者//table[@class="xxx"]这类精准定位,但即使写法对了,静态爬取还是拿不到内容,因为表格是JS生成的。
总之,Selenium对于处理这类依赖前端渲染的内容非常实用,社区里也有很多关于Scrapy和Selenium结合的详细教程,可以多参考调整。
内容的提问来源于stack exchange,提问作者Gin

