详情页智能解析算法简介

本节中我们来了解一下详情页提取算法的基本思路,主要包括如下内容。

  • 我们定义的详情页是指怎样的页面。

  • 详情页中的哪些信息是需要我们提取的关键信息。

  • 介绍标题、正文、发布时间的提取算法。

怎样的页面属于详情页

先划定一个大的范围。我们处理的网站属于资讯类网站,如新闻网站、博客网站等。这类网站通常包含两种页面:一种是包含导航信息的列表页,如新浪新闻的首页;另一种是从列表页点击导航信息后进入的页面,如一篇新闻的页面。例如,新浪新闻的首页如图 14-7 所示,我们称这类页面为列表页。

图14-7列表页的示例

凤凰网的一篇新闻的页面如图14-8所示,我们称这类页面为详情页

图14-8 详情页的示例

可以看到,这两类页面有很大不同,列表页通常包含许多详情页的标题和链接,而不会呈现具体的内容,布局样式也是千变万化,而且可能分多个区块。详情页则是某个内容的展示页面,通常包含醒目的标题、发布时间和占据版面最大的正文部分。另外,详情页的侧栏通常会有一些关联或推荐的内容列表、页面头部的导航链接、评论区、广告区等。

到现在,相信大家对分辨列表页和详情页有了基本的概念。

提取内容

这里主要了解一下我们要在详情页中提取的内容。

一般来说,详情页包含的信息非常多,例如标题、发布时间、发布来源、作者、正文、封面图评论数目、评论内容等,不过由于其中一些内容并不常用,而且提取算法大同小异,因此本节主要介绍 3 个关键信息的提取算法—标题、正文、发布时间。

还是以 14.1 节开始的新闻页为例,我们需要提取图 14-9 中框选出来的内容。

图14-9详情页中需要提取的内容

下面来分析这三部分内容的特点。

  • 标题:上方矩形框选的内容,是页面的主标题,通常字号比较大,比较醒目,能概括本页面的内容。

  • 正文:下方矩形框选的内容,是页面的核心,这里由于篇幅所限,因此未在图14-9中将正文内容展现完整。

  • 发布时间:中间矩形框选的内容,通常在页面标题的下方或者正文的下方,格式大多为常见的时间格式,代表本页面内容的发布时间。

后面会分别介绍这三部分内容的提取思路。

准备工作

现在很多网页是由JavaScript谊染而成的,导致通过请求获取的页面源代码不一定是我们在浏览器看到的页面源代码,这里要求我们提取的必须是煊染完整的HTML代码。

首先把示例详情页的HTML代码保存下来。在浏览器中打开这个页面,打开开发者工具并切换到 Elements选项卡,如图14-10所示。

图14-10找到页面的HTML代码

然后右击 html 节点,在弹出菜单中选择 Copy→Copyelement,复制整个页面的源代码,如图14-11 所示。

图14-11复制页面源代码

接着新建一个 HTML 文件,命名为 detail.html,并格式化源代码,14.3节会用到这个文件。

提取标题

一般来说,标题是相对比较好提取的,根据几个关键信息就能完成绝大多数标题的提取。详情页的标题一般包含在 title 节点中,例如:

<title>故宫,你低调点!故宫:不,实力已不允许我继续低调_风凰网资讯_风凰网</title>

此时如果直接进行提取,那么得到的标题内容如下:

故宫,你低调点!故宫:不,实力已不允许我继续低调凤凰网资讯凤鼠网

但真实的标题的内容应该为:

故宫,你低调点!故宫:不,实力已不允许我继续低调

所以,一味提取title节点内的内容并不准确,因为网站会额外增加一些信息,例如这里网站本 身的信息。此时怎么办呢?在绝大部分情况下,标题是由h节点表示的,一般为h1、h2、h3、h4等,其内部的文本就是完整的标题,那么问题又来了,html里面有那么多h节点,怎么确定哪个是标题对应的h节点呢?

答案你应该也想到了,把title节点和h节点的内容结合起来不就好了吗?于是可以初步总结出下面两步提取思路。

  1. 提取页面的h节点(如h1、h2等),将其内容和title节点的文本做比对,和后者相似度最高的内容很可能就是详情页的标题。

  2. 如果未在页面中找到h节点,则只能使用title节点的文本作为结果。

一般来说,使用以上方法可以应对90%以上的标题提取问题。另外,有些网站为了使SEO效果比较好,会添加一些meta标签,如url、title、keywords、category等,这些信息也可以成为参考依据,用它们进一步校验或补充网站的基本信息。

在上面的例子中,就有一个meta节点:

<meta property="og:title" content="故宫,你低调点!故宫:不,实力已不允许我继续低调">

可以看到其中指定了 property 为 og:title,这是一种常见写法,其内容正好是标题信息,于是我们能通过它提取标题。

综合以上内容,借助title节点、h节点和meta节点,我们已经可以应对绝大多数的标题提取了。

提取正文

正文可以说是详情页中最难提取且最为重要的部分,如果不能有效地把正文内容提取出来,那么这次解析相当于失败了一大半。

观察正文内容的特征,能够发现一些规律。

  • 正文内容通常被包含在body节点的p节点中,而且p节点一般不会独立存在,而是存在于div 等节点内。

  • 正文内容所在的p节点中也不一定全是正文内容,可能掺杂噪声,如网站的版权信息、发布人、文末广告等,这些都属于噪声。

  • 正文内容所在的p节点中会夹杂style、script等节点,这些并非正文内容。

  • 正文内容所在的p节点内可能包含code、span等节点,这些内容大部分属于正文中的特殊样式字符,往往也需要归类到正文内容中。

受开源项目 GeneralNewsExtractor 和论文《基于文本及符号密度的网页正文提取方法》(以下简称论文)的启发,我得到了一个比较有效的正文文本提取依据指标一一文本密度。

文本密度是什么呢?简单理解就是单位标签内包含的文字个数。例如一个p节点内包含100个字,那么可以简单地计算出文本密度为100;如果包含5个字,那么文本密度为5。一般来说,正文区域以一个p节点为一个段落,而一个段落包含的字通常比较多,文本密度可能上百;对于其他区域,例如页面导航区域,通常会包含多个a节点,这些链接可能总共也就十几二十个字,因此文本密度要低很多。综上,文本密度可以作为判断正文内容的重要参考指标。

当然,论文本身不仅局限于纯文本和节点的大小比例,还考到了文本中包含的超链接。论文中定义,如果i为HTMLDOM树中的一个节点,那么该节点的文本密度为:

\$\text{TD}_i = \frac{\text{T}_i - \text{LT}_i}{\text{TG}_i - \text{LTG}_i}\$

如下为其中各个符号的含义。

  • TDi:节点 i 的文本密度

  • Ti:节点中字符串的字数。

  • LTi:节点中带链接的字符串的字数。

  • TGi:节点 i 中标签的数量。

  • LTGi:节点 i 中带链接的标签的数量。

以上各项需要好好理解一下,其实文本密度基本上等同于单位标签内包含的文字个数,这里额外考虑了节点内包含超链接的情况。因为一般而言,正文区域带超链接的情况是比较少的,而侧边栏页面导航等区域,带超链接的概率非常高,所以这些地方的文本密度就会低下来,上面那么算能够更好地排除这些内容的于扰。

另外,论文中还提到了一个指标,叫作符号密度。研究发现,正文中一般会带标点符号,而网页链接、广告信息由于文字比较少,通常是不包含标点符号的,因此我们还可以借助符号密度排除一些内容。

论文中对于符号密度的定义如下:

\$\text{SbD}_i = \frac{\text{T}_i - \text{LT}_i}{\text{Sb}_i + 1}\$

如下为其中各个符号的含义。

  • SbDi:节点 i 的符号密度。

  • Ti:节点 i 中字符串的字数。

  • LTi:节点 i 中带链接的字符串的字数。

  • Sbi:节点 i 中符号的数量(分母另外加 1 是为了确保除数不为 0)。

可以看出,符号密度为文字数量和符号数量的比值。

论文的作者经过多次实验,发现利用文本密度和符号密度相结合的方式提取正文信息能取得很不错的效果,可以结合二者为每个节点分别计算一个分数,分数最高的节点就为正文内容所在的节点。分数计算公式如下:

\$Sc\o\re_i = \ln(\text{SD}) \times \text{TD}_i \times \lg(\text{PNum}_i + 2) \times \ln(\text{SbD}_i)\$

如下为其中各个符号的含义。

  • Scorei:节点 i 的分数。

  • SD:所有节点的文本密度标准差。

  • TDi:节点 i 的文本密度。

  • PNumi:节点 i 包含的 p 节点的数量。

  • SbDi:节点 i 的符号密度。

遍历各个节点,利用该公式为每个节点计算分数,然后根据最终得分确定正文节点,提取正文内容。通过对比实验数据,可知一些中文新闻网站的正文内容提取正确率能达到 90% 以上,甚至部分可以达到 99%。另外,论文作者还在不同网站上对该算法进行了评测,计算出了 P(Precision)、R(Recall)、Score(F1-Score) 值,结果如表 14-1 所示。

网 站

P

R

Score

cleanEval-Eng

93.88%

77.43%

73.11%

cleanEval-Zh

81.62%

69.18%

62.16%

凤凰网新闻

97.51%

98.18%

95.76%

参考信息

98.80%

99.88%

98.68%

可以看到,该算法在凤凰网新闻上的正确率可达 95% 以上。

我们已经可以借助以上算法得到不错的正文内容提取效果了,满足一般需求可以说没问题。如果想追求更高的正确率,还可以结合视觉信息。因为在多数情况下,正文所占的版面是最大的,所以可以通过计算节点所占区域的大小来排除一些干扰,例如找到了两块内容都疑似正文,而它们所占的网页面积一个很大,一个很小,那么面积大的是正文内容的可能性会更大。

提取发布时间

对于发布时间,也有一些线索可以利用。

和标题类似,一些正规的网站为了使 SEO 效果比较好,会把时间信息放到 meta 节点内,例如我们的例子中就有这样一个 meta 节点:

<meta name="og:time " content="2019-02-20 02:26:00">

这个 meta 节点指定了 name 为 og:time,这是一种常见写法,其内容正好就是发布时间,我们可以通过这部分信息提取发布时间。注意,不同网站的 meta 节点中 name 属性的值大概率不一样,根据经验和调研,我得到了一些写法,如:

可以看到,不同网站的写法差异还是蛮大的,我们可以总结常见的写法,一旦匹配成功,那么其 content 属性值极有可能就是发布时间。

但是,并不是所有网站都会加上这样的 meta 节点,如果碰到没有 meta 节点的网站,该怎么办呢?

我们知道,时间有一些固定的写法,如 2019-02-2002:26:00。而且发布时间通常会包含一些关键的字符,例如 “发布”、“发表于” 等,它们可以作为重要的参考依据。因此,一些固定的匹配模式往往也能起到不错的效果。例如,定义一些正则表达式,或者基于某种特定的模式来提取时间信息。

这时可能有人会说,如果正文内容本身包含时间,或者侧栏、底栏部分包含时间,不会提取错吗?

  • 对于正文内容本身包含时间的情况,根据提取的正文结果过滤即可,例如直接将正文从提取目标中册删除。

  • 对于侧栏或底栏部分包含时间的情况,可以根据节点距离算得结果。发布时间往往和正文距离较近,甚至紧贴着,而侧栏或底栏的时间常常分布在其他区块,其日期节点和正文节点的距离相对较远,这样就能找到权重最高的时间节点了。

综上所述,发布时间的提取标准如下。

  • 根据meta节点的信息提取时间,提取结果大概率就是真实的发布时间,可信度较高。

  • 根据正则表达式提取时间,如果匹配到一些置信度比较高的规则,那么可以直接提取:如果匹配到置信度不高的规则或者提取到多个时间信息,则可以进行下一步的提取和筛选。

  • 针对上面的第二种情况,通过计算节点和正文的距离,再结合其他相关信息筛选出最优节点作为结果。

按照以上标准,可以提取出绝大部分的发布时间。

总结

本节中我们介绍了详情页的 3 个关键信息——标题、正文、发布时间的提取思路,了解了基本原理之后,我们在 14.3 节会用代码实现其中的一些解析算法。