ivan_boring / readability.php
Drupal/AI Interpolator 的 Readability.js 的 PHP 版本
Requires
- php: >=7.4.0
- ext-dom: *
- ext-mbstring: *
- ext-xml: *
- league/uri: ~7
- masterminds/html5: ^2.0
- psr/log: ^1.0 || ^2.0 || ^3.0 || ^4.0 || ^5.0
Requires (Dev)
- monolog/monolog: ^2.3
- phpunit/phpunit: ^9
Suggests
- monolog/monolog: Allow logging debug information
This package is auto-updated.
Last update: 2024-09-30 02:10:52 UTC
README
这是一个为 Drupal/AI Interpolator 适配的分支。仅做最小化修改。
PHP 版本的 Mozilla 的 Readability.js。解析 HTML 文本(通常是新闻和其他文章),并返回 标题、作者、主要图片 和 文本内容,不包含导航栏、广告、页脚等非文本主体内容。分析每个节点,给予评分,并确定哪些是相关的,哪些可以丢弃。
项目的目标是与 Mozilla 的版本保持 1:1 的兼容,并紧跟那里的所有变化,但在结构上存在一些重大差异。大部分代码是 1:1 复制的——甚至注释也被导入——但一些函数和结构被调整以更好地适应 PHP 语言。
原始开发者: Andres Rey
开发者/维护者: FiveFilters.org
代码移植
主分支 - 截至 2021 年 8 月 26 日最新,但有一个 代码片段 在 PHP 中的结果与 JS 版本不同。可能存在错误,或者底层代码中的某些差异影响了这一点。如果您知道哪里出了问题,请随时告诉我们或提交一个 pull request。 :)
版本 2.1.0 - 与 Readability.js 保持更新,直到 2018 年 11 月 19 日。
要求
PHP 7.4+,ext-dom,ext-xml 和 ext-mbstring。为了安装这些依赖(在您的系统尚未安装的情况下),您可以在类似 *nix 的环境中尝试以下操作
$ sudo apt-get install php7.4-xml php7.4-mbstring
如何使用
首先,您需要使用 composer 引入库
composer require fivefilters/readability.php
然后,创建一个 Readability 类并传入一个 Configuration 类,用您的 HTML 喂入 parse()
函数,并输出变量
<?php require __DIR__ . '/vendor/autoload.php'; use fivefilters\Readability\Readability; use fivefilters\Readability\Configuration; use fivefilters\Readability\ParseException; $readability = new Readability(new Configuration()); $html = file_get_contents('http://your.favorite.newspaper/article.html'); try { $readability->parse($html); echo $readability; } catch (ParseException $e) { echo sprintf('Error processing text: %s', $e->getMessage()); }
您的脚本将输出解析后的文本或通知任何错误。您应该在 try/catch 块中包装 ->parse
调用,因为如果 HTML 无法正确解析,将抛出 ParseException
。
如果您想更精细地控制输出,只需逐个调用属性,并用您自己的 HTML 包装它。
<h1><?= $readability->getTitle(); ?></h1> <h2>By <?= $readability->getAuthor(); ?></h2> <div class="content"><?= $readability->getContent(); ?></div>
以下是可以用的属性的列表
- 文章标题:
->getTitle();
- 文章内容:
->getContent();
- 摘要:
->getExcerpt();
- 主要图片:
->getImage();
- 所有图片:
->getImages();
- 作者:
->getAuthor();
- 文本方向(ltr 或 rtl):
->getDirection();
如果您需要调整最终的 HTML,可以通过调用 ->getDOMDocument()
获取结果的 DOMDocument。
选项
您可以通过 Configuration 对象更改 Readability 的行为。例如,如果您想修复相对 URL 并声明原始 URL,您可以设置配置如下
$configuration = new Configuration(); $configuration ->setFixRelativeURLs(true) ->setOriginalURL('http://my.newspaper.url/article/something-interesting-to-read.html');
您还可以将配置参数数组传递给构造函数
$configuration = new Configuration([ 'fixRelativeURLs' => true, 'originalURL' => 'http://my.newspaper.url/article/something-interesting-to-read.html', // other parameters ... listing below ]);
然后,您将此配置对象传递给Readability。以下是一些可用的选项。请记住,在使用原生设置器调用它们时,要预先添加set
。
- MaxTopCandidates:默认值
5
,顶级候选者的最大数量。 - CharThreshold:默认值
500
,表示文章解析成功的最小字符数。 - ArticleByLine:默认值
false
,通过行搜索文章,并将其从文本中删除。它将被移至文章元数据。 - StripUnlikelyCandidates:默认值
true
,删除不太可能包含相关信息的节点。这对于调试或解析复杂或非标准文章很有用。 - CleanConditionally:默认值
true
,解析后删除某些节点以返回更干净的结果。 - WeightClasses:默认值
true
,在评分阶段进行权重分类。 - FixRelativeURLs:默认值
false
,将相对URL转换为绝对URL。例如,将/test
转换为http://host/test
。 - SubstituteEntities:默认值
false
,禁用libxml的substituteEntities
标志。将避免替换HTML实体。例如,将á
转换为á。 - NormalizeEntities:默认值
false
,将UTF-8字符转换为其HTML实体等效项。这对于解析具有混合编码的HTML很有用。 - OriginalURL:默认值
http://fakehost
,用于修复相对URL的文章原始URL。 - KeepClasses:默认值
false
,移除HTML元素中所有class="..."
属性值。 - Parser:默认值
html5
,使用HTML5-PHP进行解析。将其设置为libxml
以使用它(不建议用于现代HTML文档)。 - SummonCthulhu:默认值
false
,通过正则表达式删除所有<script>
节点。这不是理想的解决方案,因为它可能会破坏某些东西,但如果您已将解析器设置为libxml(如上所述),这可能是唯一的解决方案,以解决libxml处理未转义JavaScript的问题。
调试日志
日志记录是可选的,您需要注入自己的记录器以保存所有调试消息。为此,使用实现PSR-3日志接口的记录器,并将其传递给配置对象。例如
// Using monolog $log = new Logger('Readability'); $log->pushHandler(new StreamHandler('path/to/my/log.txt')); $configuration->setLogger($log);
在日志中,您可以找到有关解析节点、为什么删除它们以及为什么认为它们与最终文章相关联的信息。
局限性
当然,主要局限性是PHP。通过懒加载、AJAX或任何类型的JavaScript调用加载内容的网站将被忽略(实际上,没有运行),并且生成文本将不正确,与readability.js的结果相比。您想用readability.php解析的所有文章都必须是完整的,并且所有内容都应该在HTML中。
已知的libxml解析问题
从版本3.0.0开始,readability.php使用HTML5解析器。早期版本使用libxml。以下问题适用于libxml解析,因此如果您使用的是readability.php的早期版本(低于3.0.0),或者您在配置中已将解析器设置为libxml,请继续阅读...
JavaScript溢出到文本体中
DOMDocument在解析具有未转义HTML的字符串时存在一些问题。考虑以下代码
<div> <!-- Offending div without closing tag --> <script type="text/javascript"> var test = '</div>'; // I should not appear on the result </script>
如果您想删除HTML中的脚本(如readability所做的那样),您会期望在最终的HTML中只留下一个div和一个注释。问题是libxml将关闭的div标签视为HTML标签,实际上关闭了未关闭的标签,并将剩余的javascript作为字符串放在p标签内。如果保存该节点,最终的HTML将变成这样
<div> <!-- Offending div without closing tag --> <p>'; // I should not appear on the result </p></div>
这是一个libxml问题,而不是Readability.php的bug。
有一个解决方案:使用summonCthulhu
选项。这将通过正则表达式删除所有脚本标签,这并不是理想的做法,因为您可能会召唤出黑暗之神。
 实体消失
 
实体会被libxml自动转换为空格,而且没有方法可以禁用这个功能。
自闭合标签渲染为完全展开的标签
自闭合标签,如<br />
会被自动展开为<br></br
。在libxml中无法禁用此功能。
依赖关系
Readability.php使用
待办事项
- 跟踪Readability.js的变化
- 为__toString()方法添加一个小型模板引擎,而不是使用硬编码的。
- 将所有的
iterator_to_array
调用替换为自定义PHP生成器,该生成器会跟踪删除或修改的节点。
工作原理
Readability使用DOMDocument解析所有文本,扫描文本节点并根据单词数量、链接和元素类型给出分数。然后它选择得分最高的元素,并创建一个新的DOMDocument,包含所有其兄弟节点。每个兄弟节点都会被评分,以丢弃无用的元素,如导航栏、空节点等。
安全
如果您打算使用Readability处理不受信任的输入(无论是HTML还是DOM形式),我们强烈建议您使用如HTML Purifier之类的清理库,以避免在读取Readability输出时发生脚本注入。我们还建议使用CSP来进一步限制允许的最终内容所能执行的操作。Firefox阅读模式的集成本身使用了这两种技术。明确来说,清除输入中的不安全内容不是Readability本身的目标 - 现在有其他好的清理库,请使用它们!
测试
本地安装7.4及以上的任何版本PHP都足以开发新功能和添加新测试用例。如果您想确保您的更改不会与其他版本的PHP创建任何问题,您可以使用提供的Docker容器测试目前7.4、8.0、8.1。
如果您使用composer下载此包,请确保传递--prefer-source
标志,否则test/
文件夹不会下载。
您需要Docker和Docker Compose来完成此操作。要运行以上三个PHP版本的测试,只需输入以下命令
make test-all
这将启动所有容器并在每个支持的PHP版本上运行所有测试。如果您想针对特定版本进行测试,可以使用make test-7.4
、make test-8.0
或make test-8.1
。
不同版本的libxml
如果您想针对支持的PHP版本以及多个libxml版本进行测试,请运行test-all-versions
。这将针对PHP版本7.4到8.1以及libxml版本2.9.10、2.9.13和2.9.14进行测试。通常情况下,除非您认为您在特定的libxml版本上发现了一个错误,否则您不需要这样做。
更新预期的测试
如果您对代码进行了改进,您可能会想检查这里的测试用例的Readability.php输出。为此,首先从项目文件夹的根目录运行以下命令
docker-compose up -d php-7.4-libxml-2.9.10
现在您应该有一个运行中的Docker镜像,项目根文件夹映射到Docker实例上的/app/(参见docker-compose.yml
)。从现在起,对这些文件的任何更改都将可通过Docker实例访问。
接下来,在tests/文件夹中创建一个名为/changed的文件夹,然后运行以下命令来运行测试套件
docker-compose exec -e output-changes=1 -e output-diff=1 php-7.4-libxml-2.9.10 php /app/vendor/phpunit/phpunit/phpunit --configuration /app/phpunit.xml
两个环境变量(output-changes=1
和output-diff=1
)将导致任何失败的测试(以及更改的diff)的新输出被写入changed/文件夹。
如果您对更改感到满意,请设置output-diff=0
,diff文件将不再写入,这使得将新的预期输出文件复制到test-pages中相应的位置更容易。
许可证
基于Arc90的readability.js(1.7.1)脚本,可在以下位置找到:[http://code.google.com/p/arc90labs-readability](http://code.google.com/p/arc90labs-readability)
Copyright (c) 2010 Arc90 Inc
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://apache.ac.cn/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.