andreskrey/readability.php

此包已废弃,不再维护。作者建议使用fivefilters/readability.php包代替。

Readability.js的PHP端口

v2.1.0 2019-07-22 21:42 UTC

README

前往fivefilters/readability.php获取最新、维护良好的版本。

Readability.php

Latest Stable Version Build Status Coverage Status StyleCI Total Downloads Monthly Downloads

Mozilla的Readability.js的PHP端口。解析html文本(通常是新闻和其他文章),并返回无导航栏、广告、页脚等非正文内容部分的标题、作者、主图片和文本内容。分析每个节点,给它们打分,并确定哪些是相关的,哪些可以丢弃。

Screenshot

项目目标是与Mozilla版本实现1:1的端口,并密切跟踪那里的所有变更,但在结构上存在一些主要差异。大部分代码是1:1复制——甚至注释也被导入——但一些函数和结构被调整为更适合PHP语言。

主要开发者:Andres Rey

要求

PHP 7.0+、ext-dom、ext-xml和ext-mbstring。为了安装所有这些依赖项(在您的系统尚未安装的情况下),您可以在类似*nix的环境中尝试以下操作

$ sudo apt-get install php7.1-xml php7.1-mbstring

如何使用

首先,您必须使用composer引入库

composer require andreskrey/readability.php

然后,创建一个Readability类,传递一个配置类,将HTML传递给parse()函数,并输出变量

use andreskrey\Readability\Readability;
use andreskrey\Readability\Configuration;
use andreskrey\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。

选项

您可以通过配置对象来更改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实体。例如,将 &aacute; 转换为 á。
  • NormalizeEntities:默认值 false,将UTF-8字符转换为其HTML实体等效。用于解析具有混合编码的HTML。
  • OriginalURL:默认值 http://fakehost,用于修复相对URL的文章原始URL。
  • SummonCthulhu:默认值 false,通过正则表达式移除所有 <script> 节点。这并不是理想的,因为它可能会破坏某些东西,但它可能是解决 libxml与未转义JavaScript问题 的唯一解决方案。如果你不是在解析JavaScript教程,建议始终将此选项设置为 true

调试日志

记录是可选的,您需要注入自己的记录器以保存所有调试消息。为此,请使用实现 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中。

已知问题

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所做的那样),您期望最终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 选项。这将通过正则表达式移除所有脚本标签,这并不是理想的,因为您可能会召唤出 黑暗之主

&nbsp 实体消失

&nbsp 实体将由 libxml 自动转换为空格,无法禁用此功能。

自闭合标签渲染为完全展开的标签

自闭合标签如 <br /> 将自动展开为 <br></br。在 libxml 中无法禁用此功能。

依赖项

Readability.php 使用 PSR Log 接口来定义允许的日志记录器类型。仅需要在开发安装上使用 Monolog。(在 composer install 期间使用 --dev 选项)。

待办事项

  • 跟进 Readability.js 的更改
  • 为 __toString() 方法添加一个小的模板引擎,而不是使用硬编码的引擎。
  • 将所有 iterator_to_array 调用替换为跟踪已删除或更改的节点的自定义 PHP 生成器。

工作原理

Readability 使用 DOMDocument 解析所有文本,扫描文本节点并根据单词数量、链接和元素类型给出评分。然后它选择评分最高的元素,并创建一个新的 DOMDocument,其中包含所有其兄弟元素。每个兄弟元素都会被评分,以丢弃无用的元素,如导航栏、空节点等。

测试

本地安装的任何 PHP 版本都足以开发新功能和添加新测试用例。如果您想确保您的更改不会与其他 PHP 版本产生任何问题,可以使用提供的 Docker 容器来测试当前在 7.0、7.1、7.2 和 7.3 上的版本。

您需要 Docker 和 Docker Compose 才能这样做。要运行所有版本的所有测试,请键入以下命令

make test-all

这将启动所有容器并在每个受支持的 PHP 版本上运行所有测试。如果您想针对特定版本进行测试,可以使用 make test-7.0make test-7.1make test-7.2make test-7.3

如果您真的想针对每个受支持的 PHP 版本和每个受支持的 libxml 版本进行测试,请运行 test-all-versions。这将针对 PHP 版本 7 到 7.3 和 libxml 版本 2.9.4 到 2.9.9 进行测试。通常,除非您认为您在特定版本的 libxml 中发现了一个错误,否则您不需要这样做。

代码移植

截至 2018 年 11 月 19 日,与 readability.js 保持最新。

许可

基于 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.