rafael079 / readability.php
Readability.js 的 PHP 版本
Requires
- php: >=7.4.0
- ext-dom: *
- ext-mbstring: *
- ext-xml: *
- league/uri: ~6.7.2
- masterminds/html5: ^2.0
- psr/log: ^1.0 || ^2.0 || ^3.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-25 17:41:17 UTC
README
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 - 到 2018 年 11 月 19 日与 Readability.js 保持更新 为止。
要求
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 rafael079\Readability\Readability; use rafael079\Readability\Configuration; use rafael079\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 ]);
然后将此 Configuration 对象传递给 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解析问题
readability.php从版本3.0.0开始使用HTML5解析器。早期版本使用libxml。以下问题适用于libxml解析,因此如果您正在使用readability.php的早期版本(3.0.0之前),或者您已将解析器设置为libxml(见上文),请继续阅读...
JavaScript溢出到文本体
DOMDocument在解析包含未转义HTML的字符串中的JavaScript时有一些问题。考虑以下代码
<div> <!-- Offending div without closing tag --> <script type="text/javascript"> var test = '</div>'; // I should not appear on the result </script>
如果您想从HTML中删除脚本(如readability所做的那样),您期望最终只剩下单个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的错误。
有一个解决方案:使用summonCthulhu选项。这将通过正则表达式删除所有脚本标签,这并不理想,因为您可能会召唤 黑暗之主。
  实体消失
  实体由 libxml 自动转换为空格,无法禁用此功能。
自闭合标签渲染为完全展开的标签
自闭合标签,如 <br />,会自动展开为 <br></br。在 libxml 中无法禁用此功能。
依赖项
Readability.php 使用
- HTML5-PHP 解析和序列化 HTML。
- PSR Log 接口定义允许的日志记录器类型。
- Monolog 仅在开发安装中需要。(在
composer install期间使用--dev选项)。
待办事项
- 跟踪 Readability.js 的变更
- 为 __toString() 方法添加一个小型模板引擎,而不是使用硬编码的引擎。
- 将所有的
iterator_to_array调用替换为自定义的 PHP 生成器,该生成器会跟踪已删除或修改的节点。
工作原理
Readability 使用 DOMDocument 解析所有文本,扫描文本节点并根据单词数量、链接数量和元素类型给出分数。然后它选择得分最高的元素,并创建一个新的 DOMDocument,包含所有其兄弟元素。每个兄弟元素都会被评分,以删除无用的元素,如导航栏、空节点等。
安全
如果您打算使用 Readability 处理不受信任的输入(无论是 HTML 还是 DOM 形式),我们强烈建议您使用类似 HTML Purifier 的清理库,以避免在使用 Readability 输出时发生脚本注入。我们还建议使用 CSP 添加进一步的深度防御限制,以允许最终内容执行的操作。Firefox 阅读模式的集成本身也使用了这两种技术。明确来说,我们将清理输入中的不安全内容作为 Readability 本身的目标之外 - 有其他优秀的清理库,请使用它们!
测试
本地安装的 PHP 7.4 及以上版本足以开发新功能和添加新测试用例。如果您想确保您的更改不会与其他 PHP 版本产生任何问题,您可以使用提供的 Docker 容器在 7.4、8.0 和 8.1 上进行测试。
如果您使用 composer 下载此包,请确保传递 --prefer-source 标志,否则 test/ 文件夹将不会下载。
您需要 Docker 和 Docker Compose 来进行此操作。要运行 7.4、8.0 和 8.1 三个 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 图像,项目根文件夹映射到您的 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)会导致任何失败的测试的新输出(以及变化的差异)被写入到 changed/ 文件夹。
如果您认为这些更改是好的,设置 output-diff=0,差异文件将不再被写入,这会使得将新的预期输出文件复制到 test-pages 中对应的地点变得更加容易。
许可协议
基于 Arc90 的 readability.js(1.7.1)脚本,可在以下地址获取: 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.
