NodeJS 中寻找可用的 HTMLParser
发布于 12 年前 作者 dreampuf 29659 次浏览 最后一次编辑是 8 年前

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-jqueryApricot** 五类框架进行测试,最终采用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的开发环境,基础框架层出不穷,很容易找到契合自己业务相关的实现,而且有一个活跃的社区,从事相关开发是一个不错的选择。

参考

8 回复

我的小经验是: 1、先用正则粗略匹配出有用的html片段,因为对于抓取的页面,为很多没用的信息付出构造DOM的 开销很不值得~
2、把粗略HTML片段parse为DOM对象来进一步细提取有用信息~~

我是使用phantomjs作为基础采集的,因为目前采集的站点集中在一个上面,所以效率上到还不是问题。打算用下老兄介绍的方法试验下,多谢

您的思路非常的好,也比较实用。

可以查查 UC web 和 Opera 是怎么做的,他们的页面压缩都需要想进行页面分析,而且效率要非常的高才行。

就是需要这种类型的文章,NodeClub很少有这么好的文章。 赞!

不明白 你所指UC web 或者Opera 的网页浏览提速,不是他们自己提供的服务器代理吗?和数据抓取的关系是? 按照我的理解,他们无法解析的东西,比如插入的flash都是直接过滤掉的,也就不去渲染,不去请求,自然浏览速度提升了。 这是他渲染时干的事情,解析仍然会碰到我的问题,而且这种问题极其平台相关,放到Java,Csharp,Python,Ruby可能不会是问题,但在NodeJS这方面可能类库仍然还是很欠缺。

好东西,正寻找一款html parser,楼主提供了很好的建议,不用再试啦

回到顶部