NodeJS 中寻找可用的 HTMLParser
NodeJS 中寻找可用的 HTMLParser
NodeJS 中寻找可用的 HTMLParser
原文地址:http://huangx.in/2012/5/nodejs_for_available_htmlparser.html
简介
项目中需要实现对一个HTML页面解析的情况,开发环境是MacOSX lion,NodeJS v0.6.14。
本次实践,分别对**libxmljs, libxmljs-easy, jsdom, node-htmlparser, node-jquery,Apricot** 五类框架进行测试,最终采用node-jquery实现了对不规范的HTML文档的兼容,能够正常解析。
试错
最初延续Python中的经验,找libxml相关的类库,因为libxml支持XPath,可以很方便的解析HTML。
在node modules wiki页面中,找到了有两款,libxml和libxml-easy,后者是对前者API的一个再封装。使用npm安装后,发现无法解析页面,报错Error: Start tag expected, '<' not found
,发现页面不是标准的HTML。
于是尝试jsdom,采用Javascript原生实现的W3C DOM操作类库。使用时发现他对抓取页面的逻辑封装还是挺到位的,能够直接通过网址抓取,不过使用中还是报错 SyntaxError: Unexpected token ILLEGAL
。仍然无法解析。
再找到一个对HTML格式很"宽容"的解析器html-parser,编译一番API调用后,发现能够解析,虽然API很不友好,都是围绕DOM的属性进行操作,没有提供CSS selector,如果要检索页面内容会很麻烦,于是找到基于html-parser和jsdom的封装Apricout,部署一会儿部署不上,要求x86系统以及macos系统,感觉是作者粗心,将源码clone下来后,发现版本较老,一些系统类库都改名了,于是手工修改,改动如下:
diff --git a/lib/apricot.js b/lib/apricot.js
index 9e0251c..5cc3546 100644
--- a/lib/apricot.js
+++ b/lib/apricot.js
@@ -4,7 +4,7 @@ var http = require('http'),
url = require('url');
exports.Apricot = Apricot;
-sys = require(‘sys’);
+sys = require(‘util’);
function Apricot(content,live) {
diff --git a/package.json b/package.json
index 18cbdbd…fd8790b 100644
— a/package.json
+++ b/package.json
@@ -31,16 +31,18 @@
}
],
“dependencies”: {
-
"jsdom": "= 0.1.2",
-
"htmlparser": "= 1.6.2"
-
"jsdom": ">= 0.1.2",
-
"htmlparser": ">= 1.6.2"
},
“os”: [
“linux”,
“macos”,
-
"darwin",
"win"
],
“cpu”: [
“x86”,
-
"x64",
"ppc",
"x86_64"
],
安装成功后,测试的时候发现报错innerHTML
无法写入。查看源码后发现是Apricout调用sizzle构造DOM时,报错,没有正常返回document,所以找不到innherHTML,于是再去找其他类库。
最终使用node-jquery,简单的例子一下就返回了如预期的结果(CoffeeScript):
dom = jquery(body)
for i in dom.find(".targetCssName")
console.log i.innerHTML
思考
数据挖掘中,一般有一个数据格式化的过程,这个步骤就包含了上述的内容,针对各个平台可能使用的方法有所差异,不过大体都是对互联网上未经处理的HTML内容,进行格式化处理。而处理的方式又有多种,下面列举一些常见的HTML格式化信息方法,以及他们的优缺点:
-
进行前后边界查找后,定位内容区域,进行字符串的检索。优点:速度快,缺点:面对复杂的HTML可能需要很繁重的边界定位工作,我是指完成编码时的人工定位。
-
正则表达式,属于上面的加强版,不过采用了更容易描述的正则表达式,不过也有人持不同的观点。优点:速度不慢,缺点:构造表达式很耗时。
-
构造DOM然后采用CSS selector或者XPath进行检索。优点:检索方便,能够避免DOM顺序调整之类的页面变动,缺点:速度慢,开销大,需要构造DOM
对于发展中的nodeJS生态圈表示仍然很乐观,因为本文也从一个侧面反映了基于Javascript的开发环境,基础框架层出不穷,很容易找到契合自己业务相关的实现,而且有一个活跃的社区,从事相关开发是一个不错的选择。
参考
NodeJS 中寻找可用的 HTMLParser
简介
在项目中需要解析HTML页面,开发环境为MacOSX Lion,NodeJS版本为v0.6.14。本次实践中,我测试了以下几种HTML解析库:
- libxmljs: 使用libxml的JavaScript绑定。
- libxmljs-easy: libxmljs的简化版本。
- jsdom: 基于JavaScript的W3C DOM操作库。
- node-htmlparser: 一个对HTML格式非常宽容的解析器。
- node-jquery: jQuery的NodeJS版本。
- Apricot: 基于html-parser和jsdom的封装。
最终,选择node-jquery来解析非标准的HTML文档,并且能够正常解析。
试错
最初尝试使用libxml相关的库,因为libxml支持XPath,便于解析HTML。但发现这些库无法解析非标准的HTML,报错Error: Start tag expected, '<' not found
。
接下来尝试了jsdom,它能够通过网址抓取页面,但仍然无法解析,报错SyntaxError: Unexpected token ILLEGAL
。
然后尝试了node-htmlparser,虽然能够解析非标准的HTML,但其API不够友好,没有提供CSS选择器,使用起来不方便。因此,又尝试了Apricot,但在部署时遇到了一些问题,最终未能成功。
最后,选择了node-jquery,因为它能够很好地解析非标准的HTML文档,并且使用简单。以下是一个简单的示例代码:
const $ = require('jquery');
const html = `
<html>
<body>
<div class="targetCssName">Hello World</div>
</body>
</html>
`;
// 解析HTML
const dom = $(html);
// 查找所有目标CSS名称的元素并打印内容
dom('.targetCssName').each((i, elem) => {
console.log($(elem).text());
});
思考
在数据挖掘中,通常需要对HTML内容进行格式化处理。这可以通过以下几种方式实现:
-
前后边界查找:
- 优点:速度快。
- 缺点:对于复杂的HTML结构需要大量的边界定位工作。
-
正则表达式:
- 优点:速度较快,表达式易于编写。
- 缺点:构造表达式耗时。
-
构造DOM并使用CSS选择器或XPath:
- 优点:检索方便,能避免DOM顺序调整等问题。
- 缺点:速度较慢,开销较大。
对于NodeJS生态圈来说,有许多基础框架不断涌现,很容易找到适合自身需求的实现。活跃的社区也使得NodeJS成为一个很好的开发选择。
参考
希望以上内容对你有所帮助!
我的小经验是:
1、先用正则粗略匹配出有用的html片段,因为对于抓取的页面,为很多没用的信息付出构造DOM的
开销很不值得~
2、把粗略HTML片段parse为DOM对象来进一步细提取有用信息~~
我是使用phantomjs作为基础采集的,因为目前采集的站点集中在一个上面,所以效率上到还不是问题。打算用下老兄介绍的方法试验下,多谢
您的思路非常的好,也比较实用。
可以查查 UC web 和 Opera 是怎么做的,他们的页面压缩都需要想进行页面分析,而且效率要非常的高才行。
就是需要这种类型的文章,NodeClub很少有这么好的文章。 赞!
不明白 你所指UC web 或者Opera 的网页浏览提速,不是他们自己提供的服务器代理吗?和数据抓取的关系是? 按照我的理解,他们无法解析的东西,比如插入的flash都是直接过滤掉的,也就不去渲染,不去请求,自然浏览速度提升了。 这是他渲染时干的事情,解析仍然会碰到我的问题,而且这种问题极其平台相关,放到Java,Csharp,Python,Ruby可能不会是问题,但在NodeJS这方面可能类库仍然还是很欠缺。
好东西,正寻找一款html parser,楼主提供了很好的建议,不用再试啦
mark!
在Node.js环境中,解析HTML是一项常见任务。以下是几种常用的HTML解析库及其使用示例。
libxmljs
libxmljs
是一个基于libxml2的XML和HTML解析器。它支持XPath查询,但可能对非标准HTML不那么友好。
npm install libxmljs
const libxml = require('libxmljs');
const html = '<html><body><div class="example">Hello World!</div></body></html>';
const xmlDoc = libxml.parseHtml(html);
const divs = xmlDoc.find('//div[@class="example"]');
console.log(divs[0].text()); // 输出 "Hello World!"
jsdom
jsdom
是一个纯JavaScript的浏览器DOM实现,可以让您在Node.js中使用jQuery或类似的库。
npm install jsdom
const { JSDOM } = require("jsdom");
const html = '<html><body><div class="example">Hello World!</div></body></html>';
const dom = new JSDOM(html);
const document = dom.window.document;
const divs = document.querySelectorAll('.example');
console.log(divs[0].textContent); // 输出 "Hello World!"
node-htmlparser
node-htmlparser
是一个比较旧的HTML解析器,但仍然有用。
npm install htmlparser
const HtmlParser = require('htmlparser').HtmlParser;
const html = '<html><body><div class="example">Hello World!</div></body></html>';
const handler = new HtmlParser.DefaultHandler((error, dom) => {
if (error) throw error;
const divs = dom.filter(node => node.type === 'tag' && node.name === 'div' && node.attribs.class === 'example');
console.log(divs[0].children[0]); // 输出 "Hello World!"
});
const parser = new HtmlParser(handler);
parser.parseComplete(html);
node-jquery
node-jquery
是一个非常友好的库,允许你在Node.js中使用jQuery。
npm install node-jquery
const $ = require('jquery');
const cheerio = require('cheerio');
const html = '<html><body><div class="example">Hello World!</div></body></html>';
const $html = cheerio.load(html);
$html('.example').each((i, elem) => {
console.log($(elem).text()); // 输出 "Hello World!"
});
总结
每种库都有其特点,选择哪个取决于您的具体需求。如果您需要强大的XPath查询功能,libxmljs
是一个好选择。如果您习惯于使用jQuery语法,node-jquery
或 jsdom
更合适。对于更简单的场景,node-htmlparser
可能就足够了。