Python中Scrapy框架使用XPath时匹配不到数据怎么办?

<table class="tabledataformat" cellspacing="0" >
	<tr>
		<td style="vertical-align:top;">Copper, Cu&nbsp;</td>
    	<td class="dataCell" style="vertical-align:top;"><= 0.03 %<span 		     class="dataCondition"></span></td>
    	<td class="dataCell" style="vertical-align:top;"><= 0.03 %<span class="dataCondition"></span></td>
    	<td class="dataComment" style="vertical-align:top;"></td>
    </tr>
</table>

response.xpath('//table[@class="tabledataformat"]/tr').extract() 只能获取到

<tr>
		<td style="vertical-align:top;">Copper, Cu&nbsp;</td>
    	<td class="dataCell" style="vertical-align:top;"></td>
    	<td class="dataCell" style="vertical-align:top;"></td>
    	<td class="dataComment" style="vertical-align:top;"></td>
    </tr>

<= 0.03 % 和 消失不见,为什么呢?


Python中Scrapy框架使用XPath时匹配不到数据怎么办?

5 回复

因为<=的写法不符合 xml 标准


遇到Scrapy用XPath匹配不到数据,先别急着怀疑人生,多半是这几个地方出了问题。我一般会按这个顺序排查:

1. 先确认网页结构 直接用浏览器开发者工具看源码不靠谱,因为JavaScript可能改变了DOM。在Scrapy的parse方法里加一行:

def parse(self, response):
    print(response.text)  # 或者保存到文件
    with open('debug.html', 'w', encoding='utf-8') as f:
        f.write(response.text)

看看你拿到的HTML是不是真的包含你要的数据。

2. 检查XPath语法 新手常犯的错:

  • 路径不对://div[@class="content"]//div[@class="content "](有空格)是两码事
  • 用text()取文本时://h1/text() 只取直接文本,子元素文本要用 //h1//text()//h1/string()
  • 属性值包含部分内容:用contains(),比如 //div[contains(@class, "item")]

3. 处理动态加载 如果数据是JS动态加载的,XPath肯定抓不到。这时候要么:

  • 找隐藏的API接口(Network面板看XHR请求)
  • 用Selenium或Playwright渲染页面
  • 用Splash(如果项目在用)

4. 试试CSS选择器 有时候XPath写起来复杂,CSS反而简单:

# XPath
response.xpath('//div[@id="main"]/ul/li/a/@href').getall()
# CSS等价写法
response.css('#main ul li a::attr(href)').getall()

5. 用scrapy shell调试 这是最实用的调试方式:

scrapy shell "http://example.com"
# 然后直接在里面试XPath
>>> response.xpath('//title/text()').get()

实际案例: 昨天我刚遇到一个,页面显示有数据,但XPath就是匹配不到。后来发现响应里有个<iframe>,数据在iframe里。解决方案:

# 先获取iframe的src
iframe_url = response.xpath('//iframe/@src').get()
yield scrapy.Request(iframe_url, callback=self.parse_iframe)

总结建议:从响应源码、XPath语法、动态加载三方面排查。

这部分数据可能是 javascript 异步请求显示的,也就是 ajax 内容, scrapy 是看不到的。

‘’’
<tr> <td style=“vertical-align:top;”>Copper, Cu&#160;</td> <td class=“dataCell” style=“vertical-align:top;”>&lt;= 0.03 %<span class=“dataCondition”></span></td> <td class=“dataCell” style=“vertical-align:top;”>&lt;= 0.03 %<span class=“dataCondition”></span></td> <td class=“dataComment” style=“vertical-align:top;”></td> </tr>
’’'

测试 lxml 能输出, scrapy 应该也没问题,查看 html 源码吧

scrapy 爬下来用 beautifulsoup 处理,我觉得方便些

回到顶部