jsdom / cheerio大大改变HTML

我想刮一个网站,我有问题与jsdom和cheerio戏剧性地改变他们得到的html。 最值得注意的是,他们删除了一些标签,如table / tr / td标签等

只要有一个本地文件说1.html和做:

// with cheerio -> or equivalent with jsdom var $ = require('cheerio').load(fs.readFileSync(path)); fs.writeFileSync('2.html', $.html()); # bash $> diff 1.html 2.html ..... < <tr><td colspan="5"><a id="stats" name="stats"></a><div class="titlebar1" style="margin-top: 12px;margin-bottom: 4px;"><h2>Stats</h2><div class="element"><img src="img/element/10.png" /></div><div class="elementborder"><img src="img/elementborder.png" /></div></div></td></tr></table></td></div> --- > <tr><td colspan="5"><a id="stats" name="stats"></a><div class="titlebar1" style="margin-top: 12px;margin-bottom: 4px;"><h2>Stats</h2><div class="element"><img src="img/element/10.png"></div><div class="elementborder"><img src="img/elementborder.png"></div></div></div></td></tr> 54,57c53,56 < ..... 

编辑:我意识到,这很可能是由于无效的HTML,我的问题是有无论如何,我可以避免这种情况,如果您通常在浏览器中查看页面的元素在那里

更确切地说,我试图刮这个: http ://www.puzzledragonx.com/en/monster.asp?n = 1


编辑:我意识到,这也是某种浏览器的问题。 如果你用wget下载页面并且粘贴了带有cheerio的HTML,你将会得到不同的html yes,但是浏览器在parsingDOM的时候会去掉这些标签,这使我相信cheerio / jsdom会输出一些奇怪的html

我也通过html w3validation器运行该页面,并且有许多关于doctype的错误,不允许元素被放置在某个位置,但是关于无效标记

它看起来像你的inputHTML格式不正确。 $.html()序列化当前的DOM表示,除非input的HTML在语法上是正确的,否则不会产生相同的HTML。

要理解为什么会发生这种情况,请考虑一下发生了什么。 Cheerio HTML文本parsing为规范化的数据结构。 这个数据结构就是我们所说的DOM:文档对象模型 。 HTML只是这个模型的文本表示; 在cheerioparsingHTML之后,它放弃了input文本(因为它不再需要它)。

当您调用$.html() ,cheerio必须将DOM数据结构转换回文档的文本表示forms。 为此,它通过DOM树recursion并为每个节点生成HTML。 原始inputHTMLstring与输出HTML 无关 ,除了DOM填充了inputHTML。

在这一点上,你应该明白为什么分析HTML时,如果input的HTML格式错误,为了以后输出完全相同的HTML是不可能的。 input文本的parsing和规范化必然是有损的:一个宽容的parsing器必须丢弃没有意义的HTML文本。

你甚至可以在Chrome中看到这个:做你的页面的源代码和由document.documentElement.outerHTML返回的string的差异 。 我们也看到了很多不同之处,特别是在格式不正确的情况下。 (有些差异是脚本运行和变异DOM的结果)。这些工件出现的原因与cheerio,jsdom或任何其他HTMLparsing库相同。

我来到这里寻找同样的问题,(幸运的是)我也在名为tidyHtml的npm上find了一个包。 名字是自我解释,这里是它的链接https://www.npmjs.com/package/htmltidy2 。 尽pipe它在2年前的最后一次提交中处于非活动状态,但它正在做这项工作

清理HTML与运行以下function一样简单:

 var tidy = require('htmltidy2').tidy; tidy('<table><tr><td>badly formatted html</tr>', function(err, html) { console.log(html); }); 

它将标准化HTML并输出:

 <!DOCTYPE html> <html> <head> <title></title> </head> <body> <table> <tr> <td>badly formatted html</td> </tr> </table> </body> </html> 

我和cheerio一起使用,效果相当不错。 希望它能帮助别人。