Fathom:理解网页的框架

是时候超越仅仅渲染网页的浏览器了。在现代网络上,尝试完成一项简单的任务可能会让你被弹出窗口困扰,眯着眼睛查看塞进狭窄列中的内容,并试图弄清楚另一个网站自定义小部件的行为。为了恢复力量平衡并夺回用户效率,我们需要一个更智能的浏览器。

想象一下,如果 Firefox 像人类一样理解网页

  • 繁琐的登录可能会成为过去。浏览器可以识别“登录”链接,在后台跟踪它并为你登录,所有这些都不会丢失你的位置。这些链接可以从页面中消失并移动到标准的浏览器 UI 中。
  • 产品可以被识别为产品,并作为凝聚的块进行操作。你可以将它们拖到购物车中,包括图片和价格,以便进行跨站点比较购物。你可以享受易于扫描的列,而不是一堆标签。
  • 低效且不一致的 UI 最终可以被熨平。我们可以为浏览器提供热键来关闭弹出窗口、导航到下一个逻辑页面、标准化界面元素的外观或识别并展平不必要的分段幻灯片。
  • 在小屏幕或窗口上,即使在不使用响应式设计的页面上,也可以隐藏多余的导航或标题部分。我们可以在没有打印样式表的情况下智能地确定要打印的内容。

这些可能的未来都假设浏览器可以识别页面中有意义的部分。几十年来,人们做了很多尝试来简化这一过程。但是微格式、语义标签、RDF 和 link/rel 头元素未能占领世界,这既是因为网站有动力保持不被抓取,也是因为它们代表了额外的工作。因此,现代搜索引擎和浏览器的阅读模式采用了另一种方法:它们通过拥抱混乱来提取意义,使用装满启发式方法的工具带直接穿过无意义的标记。

但问题仍然存在:这些项目是单一用途的,并且生产成本很高。Readability(Safari 和 Firefox 阅读模式的基础)有 1800 行 JavaScript 代码,最近已停止服务。Chrome 的 DOM Distiller 有 23000 行 Java 代码。这些命令式方法陷入 DOM 遍历和状态累积的机制中,模糊了“理解者”的操作部分,使它们难以编写和理解。它们还与它们需要包含的临时模糊评分系统和特定于站点的启发式方法纠缠在一起。从一开始,经济因素就不利于它们,因此很少有人创建它们,尤其是在大型组织之外。

但是,如果理解者编写起来很便宜呢?如果 Readability 只需 4 条简单的规则就能实现呢?

const rules = ruleset(
    rule(dom('p,div,li,code,blockquote,pre,h1,h2,h3,h4,h5,h6'),
         props(scoreByLength).type('paragraphish')),
    rule(type('paragraphish'),
         score(fnode => (1 - linkDensity(fnode,
                                         fnode.noteFor('paragraphish')
                                              .inlineLength))
                        * 1.5)),
    rule(dom('p'),
         score(4.5).type('paragraphish')),
    rule(type('paragraphish')
            .bestCluster({splittingDistance: 3,
                          differentDepthCost: 6.5,
                          differentTagCost: 2,
                          sameTagCost: 0.5,
                          strideCost: 0}),
         out('content').allThrough(domSort))
);

这在 Readability 自己的一组测试用例中获得了 7% 以内的分数,这是通过莱文斯坦距离1测量的。支持此功能的框架是 Fathom,它将编写理解者的成本降到最低。

Fathom 是一种用于编写语义提取器的迷你语言。构成其程序的规则集嵌入在 JavaScript 中,因此你可以根据隐私要求在客户端或服务器端使用它。Fathom 处理你所有的簿记工作,以便你专注于你的启发式方法。

  • 树遍历消失了。Fathom 是一种类似 Prolog 的数据流语言,因此数据在有适用的规则尚未看到它时会方便地“出现”。
  • 流控制消失了。Fathom 根据依赖关系确定执行顺序,只运行回答你的查询所需的内容并缓存中间结果。
  • 编写插件系统的诱惑消失了。Fathom 规则是无序的,因此可以像将新元素添加到 JavaScript 数组一样轻松地添加额外的规则。这使得 Fathom 程序(或规则集)本质上是可插拔的。它们像水流一样混合,只需要就类型名称达成一致,这使得它们适合协作实验或特殊情况处理,而不会造成混乱。
  • 无需维护与 DOM 平行的多个数据结构。Fathom 提供了你可以涂鸦的代理 DOM 节点,以及黑白的类型系统和灰度的评分系统来对节点进行分类并指导决策。
  • 无需为你的启发式方法找到最佳权重平衡,这要归功于基于模拟退火优化工具。上面代码中所有这些繁琐的数值常量都是通过让机器处理一组输入和正确的输出并离开来计算出来的。

最棒的是,Fathom 规则集是数据。它们看起来像 JavaScript 函数调用,但这些调用只是在某种语法树中进行注释,使整个过程易于机器操作。今天,这为我们提供了分数常数的自动调整。明天,它可以为我们自动生成规则本身!

Fathom 虽然年轻但很有活力。它已经在生产环境中为Firefox 的活动流提供支持,在那里它提取页面描述、主图像等。在 70 行代码中,它取代了一项知名的商业元数据解析服务。

我们现在需要的是想象力。收集所有你因为浏览器需要太多理解而抛弃的想法。我们现在可以做到。这很便宜。

有想法吗?太好了!查看完整文档以开始使用,获取npm 包提交补丁,并在 irc.mozilla.org 上加入 #fathom 频道以及邮件列表,在你构建的过程中。让我们创建一个以大胆的新方式成为用户代理的浏览器!


1示例的注意事项是可以管理的。它比 Readability 慢,因为聚类是 O(n2 log n)。但也有很多唾手可得的成果尚未采摘:我们在上面什么也没做来利用 CSS 类或<article>等语义标签,它们都是丰富的信号来源,我们也没有尝试使用阈值减少聚类候选者。最后,7% 的差异中的一些实际上代表了对 Readability 输出的改进。

关于 Erik Rose

Erik 通过 DXR(Mozilla 代码库的搜索和静态分析)、Fathom(网页的语义提取)、解析器、新语言以及一大堆 Python 库等项目,不断消弭人类认知与机器执行之间的障碍。

更多 Erik Rose 的文章…


6 条评论

  1. Steve Glick

    不确定 Firefox 阅读视图当前使用的解析器是什么,但我认为值得一提的是,无论使用什么解析器,它都不喜欢带有冒号的文章标题(例如本文)。它只显示冒号之后标题的一部分。

    2017 年 4 月 26 日 下午 5:05

    1. Taylor Hunt

      那是 https://github.com/mozilla/readability 。感谢您的错误报告!

      您的错误看起来已经有一个问题了,所以我添加了您的评论作为另一个示例:https://github.com/mozilla/readability/issues/295#issuecomment-297798459

      2017 年 4 月 27 日 上午 11:24

  2. Gerd Neumann

    Fathom 是 FOSS 吗?这篇博文及其文档都没有包含指向代码库的链接。

    2017 年 4 月 27 日 上午 2:27

    1. Erik Rose

      当然;Mozilla 做的一切都是开源的。感谢您指出遗漏之处!我在文章底部添加了更多链接,这里再次列出

      https://github.com/mozilla/fathom
      https://npmjs.net.cn/package/fathom-web

      2017 年 4 月 27 日 上午 5:12

      1. Gerd Neumann

        很高兴知道。仅供参考,您可能还想在文档页面上的代码库中添加一个“在 GitHub 上分叉”或类似的链接,以避免被忽视:https://mozilla.github.io/fathom/

        我个人在选择库时更喜欢查看 GitHub 星数和贡献者数量。如果我连代码库都难以找到,那么我对软件的状态就没有那么自信了。

        感谢您的回复。

        2017 年 4 月 28 日 上午 1:24

        1. Erik Rose

          已完成。添加了指向 GH 代码库的链接以及指向 npm 包的另一个链接。发现得好!

          2017 年 4 月 28 日 上午 10:45

本文的评论已关闭。