Scrapy使用xpath提取网页节点源码返回结果异常如何解决
问题原因
这个现象是Scrapy底层依赖的lxml解析库版本过低导致的已知序列化bug,和你写的XPath规则、调用的extract/get类方法没有关系。
lxml 4.3.0之前的版本存在明确缺陷:当解析包含换行、空白缩进的表格类节点时,对选中节点执行源码序列化操作(Scrapy的extract()、get()、getall()、extract_first()底层都依赖这个操作)会错误地从当前节点的起始标签开始,一直输出到整个HTML文档的末尾,和你遇到的输出完全一致。
你可以自行验证节点定位本身是正确的:执行len(selector.xpath("//td"))会返回4,和预期的td节点数量一致;//td/text()能正确提取每个td内的文本,也证明节点选择逻辑没有问题,故障仅出在节点源码转字符串输出的环节。
另外如果创建Selector时手动指定了type="xml",也可能触发同类解析异常,解析普通HTML内容用默认的HTML解析模式即可,不要强制使用XML解析模式。
解决方案
永久修复
直接升级lxml到4.3.0及以上版本即可解决bug,执行命令:
pip install --upgrade lxml
如果升级后存在依赖兼容问题,可以同步升级Scrapy到最新稳定版:
pip install --upgrade Scrapy
临时规避方案
如果暂时无法升级运行环境的依赖,可以通过字符串截取的方式手动截断多余内容,拿到独立的td标签源码,示例代码如下:
from scrapy import Selector html = ''' <html><head></head><body><table> <tr> <td>a1</td> <td>b1</td> </tr> <tr> <td>a2</td> <td>b2</td> </tr> </table></body></html> ''' def get_clean_node(node, tag): raw_content = node.get() close_tag = f'</{tag}>' return raw_content[:raw_content.index(close_tag) + len(close_tag)] selector = Selector(text=html) temp = [get_clean_node(td, 'td') for td in selector.xpath("//td")] print(temp)
运行后即可得到预期的输出:
['<td>a1</td>', '<td>b1</td>', '<td>a2</td>', '<td>b2</td>']
内容的提问来源于stack exchange,提问作者watfe
相关产品推荐
相关产品推荐

