使用Crawlee的Cheerio解析XML时部分节点文本无法获取
问题:使用Crawlee的Cheerio解析Google News RSS时,link和published_by无法获取的原因
问题背景
正在学习通过Crawlee使用Cheerio解析XML,以Google News的RSS feed为例,其item节点结构如下:
<item> <title>Test Like a Dragon Ishin...</title> <link>https://news.google.com/rss/articles/CBMie2....</link> <guid isPermaLink="false">CBMie2h0dHB...</guid> <pubDate>Fri, 17 Feb 2023 15:00:03 GMT</pubDate> <description>Test Like a Dragon Ishin...</description> <source url="https://www.jeuxvideo.com">jeuxvideo.com</source> </item>
编写的CheerioCrawler代码如下:
const crawler = new CheerioCrawler({ async requestHandler({ request, response, body, contentType, $ }) { $("item").each(function (i, ref) { const el = $(ref); const title = el.find("title").text(); const link = el.find('link').text(); const published_on = el.find('pubdate').text(); const published_by = $("source").text(); const snippet = el.find("description").text(); console.log("TITLE: ", title); console.log("LINK: ", link); // 无法获取内容 console.log("PUBLISHED_ON: ", published_on); console.log("PUBLISHED_BY: ", published_by); // 无法获取正确内容 console.log("SNIPPET: ", snippet ) console.log("AUTHOR: ", author); }); }, });
运行后title、published_on、snippet可正常获取,但link和published_by无法获取正确内容。
原因分析及解决方法
1. published_by无法获取正确内容的原因
代码中使用$("source")是全局选择器,会匹配整个RSS文档中所有的<source>标签,而非当前遍历的<item>节点下的子元素。这会导致每次循环都拿到文档中第一个<source>的内容,而非当前item对应的来源,看起来像是无法获取正确值。
解决方法:将选择器限定在当前<item>节点范围内,改为:
const published_by = el.find("source").text();
如果需要获取来源的URL,还可以读取source标签的url属性:
const source_url = el.find("source").attr("url");
2. link无法获取内容的原因
Cheerio默认以HTML模式解析内容,而RSS是XML格式,<link>在HTML中属于特殊自闭合标签,XML模式下的解析逻辑不同。未启用XML模式时,可能导致<link>标签的内容无法被正确提取。
解决方法:在Crawlee的CheerioCrawler配置中启用XML解析模式:
const crawler = new CheerioCrawler({ cheerioOptions: { xmlMode: true, // 启用XML解析模式 }, async requestHandler({ request, response, body, contentType, $ }) { $("item").each(function (i, ref) { const el = $(ref); const title = el.find("title").text(); const link = el.find('link').text(); // 现在可正常获取 const published_on = el.find('pubDate').text(); // 建议与XML标签名大小写保持一致 const published_by = el.find("source").text(); // 修正后的选择器 const snippet = el.find("description").text(); console.log("TITLE: ", title); console.log("LINK: ", link); console.log("PUBLISHED_ON: ", published_on); console.log("PUBLISHED_BY: ", published_by); console.log("SNIPPET: ", snippet ); }); }, });
XML标签理论上区分大小写,启用xmlMode后建议将pubdate改为pubDate,与原XML标签名保持一致,避免后续出现匹配异常。
内容的提问来源于stack exchange,提问作者charnould
相关产品推荐
相关产品推荐

