1

我正在尝试抓取一个网站,但 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

我还通过 html w3 验证器运行该页面,并且有很多关于 doctype 不允许将元素放置在某个位置的错误,但没有关于无效标记的任何错误

4

2 回答 2

4

看起来您的输入 HTML 格式不正确。 $.html()序列化当前的 DOM 表示,除非输入的 HTML 语法正确,否则不会产生相同的 HTML。

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

当您调用 时$.html(),cheerio 必须将 DOM 数据结构转换回文档的文本表示形式。为此,它遍历 DOM 树并为每个节点生成 HTML。原始输入 HTML 字符串与输出 HTML无关,只是 DOM 填充了输入 HTML。

此时,您应该明白为什么如果输入的 HTML 格式错误,解析 HTML 的库不能在以后输出完全相同的 HTML。输入文本的解析和规范化必然是有损的:宽容的解析器必须抛出没有意义的 HTML 文本。

您甚至可以在 Chrome 中看到这一点:对页面的源代码和document.documentElement.outerHTML. 在这里,我们也看到了许多差异,尤其是在格式错误的表格周围。(一些差异是脚本运行和改变 DOM 的结果。)这些工件发生的原因与 Cheerio、jsdom 或任何其他 HTML 解析库相同。

于 2013-10-31T16:33:53.663 回答
1

我来这里是为了寻找同样的问题,而且(幸运的是)我还在 npm 上找到了一个名为 tidyHtml 的包。这个名字是不言自明的,这里是它的链接https://www.npmjs.com/package/htmltidy2。虽然它目前在 2 年前的最后一次提交中处于非活动状态,但它正在完成这项工作。

清理 HTML 就像运行以下函数一样简单:

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结合使用,结果非常好。希望它会帮助某人。

于 2017-01-12T12:04:33.790 回答