一尘不染

使用Node.js和XPath对页面进行性能分析

node.js

我正在使用Node.js进行一些Web抓取。我想使用XPath,因为我可以使用几种GUI半自动生成它。问题是我找不到有效的方法。

  1. jsdom非常慢。它会在一分钟左右的时间内解析500KiB文件,并具有完整的CPU负载和大量内存。
  2. 流行的HTML解析库(例如cheerio)既不支持XPath,也不公开W3C兼容的DOM。
  3. 很明显,有效的HTML解析是在WebKit中实现的,因此可以使用phantomcasper将其作为一种选择,但这些解析必须以一种特殊的方式运行,而不仅仅是node <script>。我不能依靠此更改所隐含的风险。例如,它更难以找到如何运行node-inspectorphantom
  4. Spooky是一个选项,但是它有很多问题,因此它根本无法在我的机器上运行。

那么用XPath解析HTML页面的正确方法是什么?


阅读 266

收藏
2020-07-07

共1个答案

一尘不染

您可以分几个步骤进行操作。

  1. 使用解析HTML parse5。不好的部分是结果不是DOM。尽管速度足够快且与W3C兼容。
  2. 将其序列化为XHTML,xmlserializer并接受类似DOM的结构parse5作为输入。
  3. 使用再次解析该XHTML xmldom。现在,您终于有了该DOM。
  4. xpath库基于构建xmldom,允许您运行XPath查询。请注意,XHTML具有自己的名称空间,并且类似之类的查询//a将不起作用。

最终,您得到了类似的内容。

const fs = require('mz/fs');
const xpath = require('xpath');
const parse5 = require('parse5');
const xmlser = require('xmlserializer');
const dom = require('xmldom').DOMParser;

(async () => {
    const html = await fs.readFile('./test.htm');
    const document = parse5.parse(html.toString());
    const xhtml = xmlser.serializeToString(document);
    const doc = new dom().parseFromString(xhtml);
    const select = xpath.useNamespaces({"x": "http://www.w3.org/1999/xhtml"});
    const nodes = select("//x:a/@href", doc);
    console.log(nodes);
})();
2020-07-07