我曾经试图从一个URL中智能地提取“相关”的文本,消除与广告和其他杂乱无章的文本相关的信息。经过数月的研究,我发现这是一个无法准确确定的问题(我尝试过不同的方法,但都不可靠,因此放弃了)。
一周前,我偶然发现了Readability这个插件,可以将任何URL转换为易读的文本。我认为它看起来相当准确。我的猜测是,他们有一种算法可以智能地提取相关文本。
有人知道他们是如何做到的吗?或者我应该如何可靠地实现这一点?
我曾经试图从一个URL中智能地提取“相关”的文本,消除与广告和其他杂乱无章的文本相关的信息。经过数月的研究,我发现这是一个无法准确确定的问题(我尝试过不同的方法,但都不可靠,因此放弃了)。
一周前,我偶然发现了Readability这个插件,可以将任何URL转换为易读的文本。我认为它看起来相当准确。我的猜测是,他们有一种算法可以智能地提取相关文本。
有人知道他们是如何做到的吗?或者我应该如何可靠地实现这一点?
易读性主要由一些启发式规则组成,在许多情况下它们“某种方式很好地工作”。
我写过一些关于这个主题的研究论文,并想解释一下为什么容易想出一个效果良好的解决方案以及何时接近100%准确度会变得困难的背景。
人类语言中似乎存在一条语言定律,这也(但不仅仅)表现在网页内容中,已经相当明显地将两种文本分开了(全文文本与非全文文本或大致上的“主要内容”与“底版”)。
从HTML中获取主要内容,在许多情况下只需保留HTML文本元素(即未被标记打断的文本块),这些文本块具有超过约10个单词。看起来人们从两种文本类型(通过它们发出的单词数衡量,“短”和“长”)中选择用于书写文本的两种不同动机。我将它们称为“导航”和“信息”动机。
如果作者希望您快速了解所写内容,则使用“导航”文本,即少量单词(如“STOP”、“Read this”、“Click here”)。这是导航元素(菜单等)中最突出的文本类型。
如果作者希望您深入理解他/她的意思,则使用更多单词。通过这种方式,消除了歧义,但增加了冗余。文章类内容通常属于此类,因为它不仅仅有几个单词。
虽然这种分离似乎在大量情况下有效,但在标题、短句、免责声明、版权脚注等方面变得棘手。
还有更为复杂的策略和特征可以帮助区分主要内容和样板内容。例如链接密度(块中包含链接的单词数与块中所有单词数之比)、前/后文块的特征、特定块文本在“整个”网络中的频率、HTML文档的DOM结构、页面的视觉形象等。
您可以阅读我的最新文章“使用浅层文本特征进行样板检测”,从理论角度获得一些见解。您也可以在VideoLectures.net上观看我的论文演示视频。
“可读性”算法使用了其中一些特征。如果您仔细观察SVN更新日志,就会发现算法的策略数量随时间而变化,提取质量也随之改善。例如,在2009年12月引入链接密度的策略非常有助于提高提取质量。
因此,在没有提到确切版本号的情况下说“可读性”算法是这样工作的是没有意义的。
我发布了一个名为boilerpipe的开源HTML内容提取库,提供了几种不同的提取策略。根据用例,某个提取器可能更有效。您可以使用Google AppEngine上的boilerpipe-web应用程序在自己选择的页面上尝试这些提取器。
为了让数字说话,可以查看boilerpipe维基上的“基准测试”页面,其中比较了一些提取策略,包括boilerpipe、Readability和苹果Safari。
我应该提到这些算法假设主要内容实际上是完整文本。但也有一些情况下,“主要内容”可能是其他东西,例如图像、表格、视频等。对于这些情况,算法效果不佳。
可读性是一个JavaScript书签小工具,意味着它是在客户端操作DOM的代码。查看JavaScript代码,你应该能够看到正在发生什么。
可读性的工作流程和代码:
/*
* 1. Prep the document by removing script tags, css, etc.
* 2. Build readability's DOM tree.
* 3. Grab the article content from the current dom tree.
* 4. Replace the current DOM tree with the new one.
* 5. Read peacefully.
*/
javascript: (function () {
readConvertLinksToFootnotes = false;
readStyle = 'style-newspaper';
readSize = 'size-medium';
readMargin = 'margin-wide';
_readability_script = document.createElement('script');
_readability_script.type = 'text/javascript';
_readability_script.src = 'http://lab.arc90.com/experiments/readability/js/readability.js?x=' + (Math.random());
document.documentElement.appendChild(_readability_script);
_readability_css = document.createElement('link');
_readability_css.rel = 'stylesheet';
_readability_css.href = 'http://lab.arc90.com/experiments/readability/css/readability.css';
_readability_css.type = 'text/css';
_readability_css.media = 'all';
document.documentElement.appendChild(_readability_css);
_readability_print_css = document.createElement('link');
_readability_print_css.rel = 'stylesheet';
_readability_print_css.href = 'http://lab.arc90.com/experiments/readability/css/readability-print.css';
_readability_print_css.media = 'print';
_readability_print_css.type = 'text/css';
document.getElementsByTagName('head')[0].appendChild(_readability_print_css);
})();
如果你跟随上述代码引入的JS和CSS文件,你将获得整个图片:
http://lab.arc90.com/experiments/readability/js/readability.js(这是相当不错的注释,有趣的阅读)
http://lab.arc90.com/experiments/readability/css/readability.css
当然,没有100%可靠的方法来实现这一点。您可以在此阅读可读性源代码
基本上,他们正在尝试识别文本的积极和消极块。正面标识符(即div IDs)可能是以下内容:
负面标识符可能是:
然后他们有不太可能和可能的候选人。
他们要做的是确定网站的主要内容最有可能是什么,参见可读性源代码中的第678
行。这是通过分析段落的长度、它们的标识符(见上文)、DOM树(即如果段落是最后一个子节点)等来完成的,剥离所有不必要的内容,删除格式等。
代码共有1792行。这似乎是一个相当棘手的问题,因此您可以从中获得灵感。