Hello World
Spiga

运行在.NET/Mono上的Readability

2010-11-26 11:30 by 老赵, 5514 visits

之前我在《改善自己的阅读体验》推荐使用Readability这个小工具。它是一段JavaScript脚本,通过在浏览器的页面上运行,提取出文章正文部分,并通过一种干净清爽的形式展示给用户。那么,如果我们在服务器端得到了一个HTML字符串,又该如何得到它的可读部分?直接在服务器端执行JavaScript不太可行,因为Readability依赖浏览器的DOM结构及相关API。如果调用WebKit和IE的浏览器内核又需要大动干戈,也很难跨平台。因此,我基于HtmlAgilityPack将Readability的部分算法移植到了C#上。

我们知道,把一个页面的HTML解析为DOM树并不是件容易的事情,因为HTML几乎不会是标准的XML,各种容错必不可少,否则寸步难行。HtmlAgilityPack是一个非常有用的类库,提供了近乎浏览器的解析功能以及各种DOM操作,只需简单补充几行代码便可以对应几乎浏览器上所有的DOM操作。更重要的是,它只是依赖了.NET 2.0中的XPath实现,完全不涉及MSHTML.dll,ActiveX或是COM等非托管代码,为我们移植Readability提供了良好的基础。

Readability的算法并不复杂,我主要移植了它的getArticleTitle及grabArticle两个方法,分别用于获取文章标题及页面内容。不过值得一提的是,我发现它的某些算法还是为英文内容服务的。例如在获取文章标题时,它会按照空格分割文档的标题,查看其中有多少个单词,并进行一些处理,而对于中文内容很显然是不合适的(因此对于中文页面,捕获到的标题往往就是页面标题)。同样,在计算某个节点是否是文章正文的时候,其中“英文逗号”的数量也是分值的一部分,我在移植的时候也添加了“中文逗号”。

目前我的移植成果放在了github上,称为NReadability,可以从一个HTML字符串中获得标题和正文内容。包括阅读Readability的代码在内,移植工作大约花了我三个小时的时间,其中的算法几乎和JavaScript代码完全对应,不过并不完整,还有些细微之处没有移植(甚至还没完全去除样式),有时间我会慢慢补上。从效果上看执行结果还是比较令人满意的,使用起来也非常简单,例如:

var documentHtml = new WebClient().DownloadString("http://...");
var readability = Readability.Create(documentHtml);
Console.WriteLine(readability.Title);
Console.WriteLine(readability.Content);

我写了个最最简单的示例程序部署在我的博客上(Mono 2.8,ASP.NET 4),您可以尝试一下。目前这个页面在下载URL内容时直接使用了UTF-8编码,因此对于某些腌臜泼皮的中文页面会得到乱码。您可以使用英文页面,或是比较正常的中文页面(例如InfoQ,博客园,CSDN等等)进行试验。如果结果与您的预期不符,也请在评论或是在推特上回复一下,谢谢。

Creative Commons License

本文基于署名 2.5 中国大陆许可协议发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名赵劼(包含链接),具体操作方式可参考此处。如您有任何疑问或者授权方面的协商,请给我留言

Add your comment

26 条回复

  1. waninlezu
    113.73.238.*
    链接

    waninlezu 2010-11-26 15:04:37

    chrome 插件 iReader 挺不错的。

  2. Arrix
    125.71.186.*
    链接

    Arrix 2010-11-26 19:09:08

    试了一下,效果不错!readability的port越来越丰富了。这里有个直接在服务器执行javascript的版本 https://github.com/arrix/node-readability

  3. Vincent
    60.255.202.*
    链接

    Vincent 2010-11-26 19:16:32

    w3c的这个网页解析不了,直接报错了,http://www.w3.org/TR/css3-2d-transforms/

  4. 老赵
    admin
    链接

    老赵 2010-11-26 19:58:01

    @Vincent

    挺奇怪的哈。

  5. 链接

    Ivony 2010-11-27 22:43:23

    HtmlAgilityPack解析出来的DOM问题蛮多的。。。。主要是可选结束标签支持上面。

    如果要说近乎浏览器的解析,我还真不服气,至少现在工作版本的Jumony Parser在模拟浏览器分析DOM行为上已经超越了HtmlAgilityPack。

    出于私心建议支持国货,,,,呃,,,,我的意思是说国产开源不易,,,,

    不知道老赵有没有兴趣来完整实现HTML DOM API,这其实是个体力活。但是完成后,可能借助JavaScript引擎就不用做移植工作了。

  6. 老赵
    admin
    链接

    老赵 2010-11-28 00:03:12

    @Ivony

    啊,最近我想搞的东西主要就是黑魔法那套……

  7. 陈维国博客
    59.57.218.*
    链接

    陈维国博客 2010-11-28 12:40:04

    很想装这个...

  8. glongzh
    218.240.1.*
    链接

    glongzh 2010-11-28 21:16:34

    之前就有人port过了,连名字都一样…… http://code.google.com/p/nreadability/

  9. 老赵
    admin
    链接

    老赵 2010-11-28 22:39:30

    @glongzh

    oh,shit。

  10. 掌握星光
    114.250.164.*
    链接

    掌握星光 2010-11-29 11:22:37

    正确率相当高呀,试过的几个页面都能能正确截取

  11. waynebaby
    210.22.108.*
    链接

    waynebaby 2010-11-29 15:35:47

    我记得以前有一个 依赖 xmlreader 实现的 sgmlreader.

    用reader比xpath 更脱离dom吧,似乎就可以更好的兼容了

  12. eD
    66.214.170.*
    链接

    eD 2010-12-04 17:36:41

    try Node.js and CommonJS, there are many server-side javascript solutions:

    http://en.wikipedia.org/wiki/Comparison_of_Server-side_JavaScript_solutions

  13. 老赵
    admin
    链接

    老赵 2010-12-04 21:07:05

    @eD

    我需要的是“JavaScript引擎”,不是“基于JavaScript引擎的类库/框架/工具”。还有Readability是依赖DOM库的,因此就算光有服务器端的JavaScript引擎也多大意义。此外,在我这里还要求是.NET的,因此我需要的还是托管平台的JavaScript引擎

  14. tudouxigua
    124.74.45.*
    链接

    tudouxigua 2010-12-07 17:35:21

    呵呵,没想到你也在移植,最近在看java方面的东西,练手也移植了个java版的。感觉移植这个关键是个好的dom解析器,解析器好移植起来时直接大段大段拷代码都可以。没办法用java自己写了个html解析器,写完倒是对java也稍微了解了点,感觉java语言本身没有C#给力啊

  15. driedbeef
    113.76.17.*
    链接

    driedbeef 2010-12-07 22:08:55

    老赵你是在什么操作系统上跑Mono?

  16. 老赵
    admin
    链接

    老赵 2010-12-08 09:12:38

    @tudouxigua

    Java语言比C#差太远了。

  17. 老赵
    admin
    链接

    老赵 2010-12-08 09:13:02

    @driedbeef

    服务器是Linode,Ubuntu Server 10.10。

  18. driedbeef
    113.106.106.*
    链接

    driedbeef 2010-12-08 20:31:00

    @老赵

    呵呵,我在CentOS上跑。目前感觉良好。

  19. 链接

    2011-06-30 09:09:23

    有些网页是解析不了的,应该加个方法来判断一下。

  20. 小桥流水
    125.39.132.*
    链接

    小桥流水 2011-10-07 10:39:35

    hi 老赵,你的那个github的链接失效了,https://github.com/JeffreyZhao/NReadability,能提供一下代码吗?

  21. silence
    114.83.100.*
    链接

    silence 2012-02-17 11:45:05

    请问你是用的什么数据库呢,既然在ubuntu上,是mysql吗?

  22. 老赵
    admin
    链接

    老赵 2012-02-17 14:36:09

    @silence

    博客用的是MongoDB。

  23. Rocky
    61.136.59.*
    链接

    Rocky 2012-03-08 12:55:37

    留名~ 多写点~

  24. RYAN
    221.3.133.*
    链接

    RYAN 2012-08-01 00:51:04

    https://github.com/JeffreyZhao/NReadability 不对呢,请问哪里能下到源代码呢??

  25. Lee
    222.211.223.*
    链接

    Lee 2014-09-15 10:17:29

    你好,请问源码链接还能提供吗?我想学习学习你的源码

  26. 上海装潢公司
    114.95.135.*
    链接

    上海装潢公司 2016-12-10 17:21:14

    失散18年后相认上海装饰公司 男子猥亵殴打女子上海装潢公司 2017节假日安排松江装潢公司 铝厂向黄河排污九亭装潢公司 外卖员强奸案告破上海松江装潢公司 持枪杀人逃12年松江装修公司 赴美嫁网友遭毒打泗泾装潢公司 协警遭狱警鄙视洞泾装潢公司 偷窥如厕反被拍松江装饰公司 阿富汗击毙塔利班上海松江装修公司 曝昆凌录节目呕吐上海装潢

    十大幸福城市出炉九亭装修公司 为偶像直播间炫富九亭装饰公司 老人赚骗子51万泗泾装饰公司 诺基亚手机回归洞泾装修公司 偷6只蓝孔雀吃掉洞泾装饰公司 去厕所需挂如厕牌洞泾办公室装潢 邓超被错认彭于晏公司装潢松江

    男童输血染艾滋新凯家园装潢公司 老人赚骗子51万润江花苑装潢公司 山东失联女已遇害同润菲诗艾伦装潢公司 杨利伟回应敲击声上海装潢设计公司 禁忌浪漫爱情电影《无法触碰的爱》上海装修设计公司 奥朗德宣布不连任上海装修公司 科长被情人举报上海装饰设计公司 曝陈妍希提前当妈同润菲诗艾伦装修公司 高院判聂树斌无罪同润菲诗艾伦装饰公司 孪生姐妹捐遗体金港花园装潢公司 北京公交起火冒烟佘山装潢公司 男学生求婚女老师松江办公室装修公司 退学后烧炭自杀松江厂房装修公司 特朗普提太空政策松江装潢设计公司 校长见证情侣表白漕河泾办公室装修 偷得Note7竟自燃漕河泾厂房装修 打537次110被拘漕河泾装潢公司 落井男童遗体找到漕河泾装饰公司

    新凯家园装修公司 西安约500名直播主播被欠薪 经纪人疑携款潜逃新凯家园装饰公司 润江花苑装修公司 润江花苑装饰公司 金港花园装修公司 金港花园装饰公司 员工被罚当众吃虫佘山装饰公司 北京公交起火冒烟佘山装潢公司 渔民捕到神秘龙虾洞泾办公室装修 宁泽涛奥运前遭罚漕河泾装修公司

发表回复

登录 / 登录并记住我 ,登陆后便可删除或修改已发表的评论 (请注意保留评论内容)

昵称:(必填)

邮箱:(必填,仅用于Gavatar

主页:(可选)

评论内容(大于5个字符):

  1. Your Name yyyy-MM-dd HH:mm:ss

使用Live Messenger联系我