使用Node.js和XPath对页面进行性能分析
我进入了一些网站与Node.js刮。 我想使用XPath,因为我可以用几种GUI自动生成它。 问题是,我无法find有效的方法。
-
jsdom
非常慢。 它在一分钟左右parsing500KiB文件,全部CPU负载和大量内存占用。 - 用于HTMLparsing的stream行库(例如
cheerio
)既不支持XPath,也不公开W3C兼容的DOM。 - 有效的HTMLparsing显然是在WebKit中实现的,所以使用
phantom
或casper
将是一种select,但是这些parsing需要以特殊的方式运行,而不仅仅是node <script>
。 我不能依靠这种变化所暗示的风险。 例如,要find如何用phantom
运行node-inspector
困难多了。 -
Spooky
是一个选项,但是它有足够的bug ,所以它在我的机器上根本没有运行。
然后用XPathparsingHTML页面的正确方法是什么?
你可以通过几个步骤来完成。
- 用
parse5
parsingHTML。 不好的部分是结果不是DOM。 虽然速度够快,并且符合W3C标准。 - 使用
xmlserializer
将其序列parse5
XHTML,它接受parse5
的类DOM结构作为input。 - 再次用
xmldom
parsingXHTML。 现在你终于有了这个DOM。 -
xpath
库build立在xmldom
,允许您xmldom
XPath查询。 请注意,XHTML有它自己的命名空间,像//a
这样的查询将不起作用。
最后你得到这样的东西。
var fs = require('fs'); var xpath = require('xpath'); var parse5 = require('parse5'); var xmlser = require('xmlserializer'); var dom = require('xmldom').DOMParser; fs.readFile('./test.htm', function (err, html) { if (err) throw err; var document = parse5.parse(html.toString()); var xhtml = xmlser.serializeToString(document); var doc = new dom().parseFromString(xhtml); var select = xpath.useNamespaces({"x": "http://www.w3.org/1999/xhtml"}); var nodes = select("//x:a/@href", doc); console.log(nodes); });
Libxmljs是目前最快的实现( 类似于基准testing ),因为它只绑定到支持XPath 1.0查询的LibXML C库:
var libxmljs = require("libxmljs"); var xmlDoc = libxmljs.parseXml(xml); // xpath queries var gchild = xmlDoc.get('//grandchild');
但是,您需要先清理HTML,然后将其转换为正确的XML。 为此,您可以使用HTMLTidy命令行实用程序( tidy -q -asxml input.html
),或者如果您希望它只保留节点,那么像xmlserializer这样的应用程序就可以做到这一点。
我刚刚开始使用npm install htmlstrip-native
,它使用本机实现来parsing和提取相关的html部分。 它声称比纯js实现快50倍(我还没有证实这一说法)。
根据您的需要,您可以直接使用html-strip,或者解除代码和绑定,使您自己在内部使用的htmlstrip-native
如果你想使用xpath,那么使用已经在这里包装的包装; https://www.npmjs.org/package/xpath
我认为渗透是你正在寻找的。
- 使用本机libxml C绑定
- 支持CSS 3.0和XPath 1.0select器混合
- 嘶嘶声select器,Slickselect器,等等
- 没有像jQuery,cheerio或jsdom这样的大型依赖关系
HTMLparsing器function
- 快速parsing
- 非常快的search
- 小内存占用
HTML DOMfunction
- 加载并searchajax内容
- DOM交互和事件
- 执行embedded式和远程脚本
- 执行DOM中的代码
这是一个例子:
osmosis.get(url) .find('//div[@class]/ul[2]/li') .then(function () { count++; }) .done(function () { assert.ok(count == 2); assert.done(); });
可能从来没有正确的方法来parsingHTML页面。 网上抓取和爬行的第一次审查表明, Scrapy可以成为您的需要的一个很好的候选人。 它接受CSS和XPathselect器。 在Node.js的领域,我们有一个漂亮的模块节点渗透 。 这个模块是build立在libxmljs之上的,所以它应该支持CSS和XPath,尽pipe我没有find任何使用XPath的例子。