使用PHP在任意HTML中查找重要文本?

4

我有一些包含重要文本的随机HTML布局需要提取。我不能只使用strip_tags(),因为这会留下来自侧边栏/页脚/页眉等的大量额外垃圾。

我在Python中找到了一个方法,想知道PHP中是否有类似的东西。

概念相当简单:使用文本与HTML代码密度的信息来确定是否值得输出一行文本。(这不是一个新颖的想法,但它有效!)基本过程如下:

  1. 解析HTML代码并跟踪处理的字节数。
  2. 按行或段落存储文本输出。
  3. 将每个文本行与描述它所需的HTML字节数相关联。
  4. 通过计算文本t> o字节的比率来计算每行的文本密度。
  5. 然后使用神经网络决定该行是否属于内容。

仅通过检查行的密度是否高于固定阈值(或平均值),您就可以获得相当不错的结果,但如果使用机器学习,则系统会犯更少的错误-更不用说实现起来更容易了!

更新:我为可以从随机HTML模板中提取主要内容的答案发起了悬赏。由于我无法分享我将使用的文档-只需选择任何随机博客网站并尝试从布局中提取正文文本。请记住,页眉、侧边栏和页脚也可能包含文本。有关想法,请参见上面的链接。


“提取”是什么意思 - 是提取包含完整HTML(如<b><i><a>)的内容,还是只提取文本? - Pekka
1
我不会重新实现这个。要么直接使用Python模块 $text = exec("python -m ..."),要么使用在线服务http://boilerpipe-web.appspot.com/。 - mario
@Pekka,我更喜欢将标记元素(如代码块或对象嵌入)与文本一起使用——但仅使用纯文本也可以。 @mario - 谢谢!那看起来是个好的开始——但我真的需要一个可以在本地运行的东西,如果可能的话,我宁愿不向我的服务器应用程序添加Java。 - Xeoncross
1
你可能正在寻找类似可读性算法的东西,有关更多信息和实现,请参见此问题:https://dev59.com/T3M_5IYBdhLWcg3w9oaG - Richard M
如果你只想查看“主要”内容并排除侧边栏、标题和导航块等,你需要提供一些更具体的要求,而不仅仅是:“随便选择任何博客网站并尝试从布局中提取正文文本”(如果你想得到一个好的答案的话...) - ridgerunner
显示剩余4条评论
5个回答

5
  • phpQuery 是基于 jQuery JavaScript 库的一种服务器端可链接、CSS3 选择器驱动的文档对象模型 (DOM) API。

更新2

  1. 许多博客使用 CMS
  2. 博客的 HTML 结构几乎总是相同的。
  3. 避免使用常见的选择器,如 #sidebar, #header, #footer, #comments, 等等..
  4. 避免使用任何标记名称为 script, iframe 的小部件
  5. 清除已知的内容,如:
    1. /\d+\scomment(?:[s])/im
    2. /(read the rest|read more).*/im
    3. /(?:.*(?:by|post|submitt?)(?:ed)?.*\s(at|am|pm))/im
    4. /[^a-z0-9]+/im

搜索常见的类和id:

  • typepad.com .entry-content
  • wordpress.org .post-entry .entry .post
  • movabletype.com .post
  • blogger.com .post-body .entry-content
  • drupal.com .content
  • tumblr.com .post
  • squarespace.com .journal-entry-text
  • expressionengine.com .entry
  • gawker.com .post-body

  • 参考: 前100个博客使用的博客平台


$selectors = array('.post-body','.post','.journal-entry-text','.entry-content','.content');
$doc = phpQuery::newDocumentFile('http://blog.com')->find($selectors)->children('p,div');

我可以帮您进行翻译。以下是需要翻译的内容:

基于常见的HTML结构进行搜索,如下所示:

<div>
<h1|h2|h3|h4|a />
<p|div />
</div>

$doc = phpQuery::newDocumentFile('http://blog.com')->find('h1,h2,h3,h4')->parent()->children('p,div');

2
非常棒,我可能不会用到它 - 但是我另外开了一个赏金来感谢你的工作,因为我相信其他人会能够使用它。 - Xeoncross

3

Domdocument 可以用于解析 HTML 文档,然后可以通过 PHP 进行查询。

编辑:wikied


是的,我目前正在尝试使用它和正则表达式,并且运气不错。如果您在PHP中禁用了“E_WARNING”错误,并通过loadHTML()加载内容,则甚至可以相当好地解析无效的HTML。 - Xeoncross
在构建了一个正则表达式HTML解析器(75%成功率)和一个DOM解析器(90%成功率)之后,如果没有人提供解析HTML的示例,我将不得不授予这个基本答案赏金。对于任何关心的人,值得注意的是,使用我的约10个正则表达式规则解析HTML比使用PHP DOM快10倍。但是,由于我必须使用preg函数创建所有额外匹配数组,因此PHP DOM使用的RAM少25%。 - Xeoncross
请问您能否提供您编写的DOM解析器解决方案? - Alp

2

我之前曾经参与过一个类似的项目。虽然不如Python脚本复杂,但是它能很好地完成任务。你可以去看看"Simple HTML PHP Parser"。

http://simplehtmldom.sourceforge.net/


这只是一个简单的DOM解析器,需要你知道布局才能找到所需内容。我正在处理的是任意HTML文件,因此它们的结构通常非常不同。 - Xeoncross
@Xeon 不一定:您可以遍历每个元素并检查其 textNode 值(或者在 simpleHTMLDOM 中文本节点的名称是什么)。如果它与您的搜索模式匹配,则提取整个包括子元素的元素。这是我能想到的唯一方法...但是,还有其他替代 SimpleHTMLDOM 的方法,请参见 https://dev59.com/EnA65IYBdhLWcg3w4C-j#3577662 - Pekka
谢谢Pekka。没错,Xeoncross,你可以遍历整个文档,获取其子元素,甚至可能运行递归解析。 - Cogicero
SO链接中有很棒的替代方案列表,Pekka。 :) - Cogicero
@ Congicero 由于我无法分享我将要使用的文档 - 只需选择任何随机站点并尝试从布局中提取正文文本。我的文档通常具有非常不同的DOM模式,因此您想尝试的任何站点都可以。或者,如果您概述了深入研究DOM时要查找的内容,我可以尝试构建自己的内容。 - Xeoncross
显示剩余2条评论

1

我开发了一个HTML解析和过滤PHP包,可用于此目的。

它由一组类组成,可以链接在一起执行一系列HTML/XML代码的解析、过滤和转换操作。

它旨在处理真实世界中的页面,因此它可以处理格式不正确的标签和数据结构,以尽可能保留原始文档。

它附带的一个过滤器类可以进行DTD验证。另一个可以丢弃不安全的HTML标签和CSS,以防止XSS攻击。还有另一个简单地提取所有文档链接。

所有这些过滤器类都是可选的。您可以按照自己的想法将它们链接在一起,如果需要的话。

所以,为了解决您的问题,我认为PHP中没有特定的解决方案,但是可以为此开发一个特殊的过滤器类。看看这个包。它有详细的文档。

如果您需要帮助,请查看我的个人资料并给我发送邮件,我甚至可以开发出完全符合您需求的过滤器,或者借鉴其他语言中已有的解决方案。


1

根据您的HTML结构以及是否有ID或类别,您可以使用preg_match()来获取特定开始和结束标记之间的任何信息,这意味着您应该知道如何编写正则表达式。

您还可以查看浏览器仿真PHP类。我已经为页面抓取做过这个,并且它可以很好地工作,具体取决于DOM的格式化程度。我个人喜欢SimpleBrowser
http://www.simpletest.org/api/SimpleTest/WebTester/SimpleBrowser.html


用 PHP 写浏览器?有趣的想法。至于正则表达式,我遇到的问题是,在一些具有连续布局的文档中搜索文本很容易,而其他在各个章节之间都有大量垃圾内容的文档则更难捕捉。 - Xeoncross
如果你正在解析动态变化的文档,任何方法都无法捕获你想要的所有数据,所以你必须根据每个文档进行微调。如果你可以找到所有文档之间的共同点,比如一个id为#content,那么事情就会变得容易得多。使用preg_match的正则表达式可能会变得繁琐和需要不断地修改。SimpleBrowser可以让你找到任何元素并遍历其子元素,这样你就可以更轻松地进行微调,只要你知道文档的DOM。越具体越好,但即使没有类或id,你也可以定位到一个元素。 - Jamie Taniguchi
是的,文件之间有很多不同之处。但这里有几个我发现的相似点。所有文档在评论之前都有主要内容(如果存在评论)。当使用DOM解析时,所有内容通常是父div的大部分。文本内容的开始通常是HTML标记中文本的较高比率(当使用正则表达式解析时),尽管在文本段落之间可能会有示例、视频嵌入和代码。 - Xeoncross

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接