如何从网页内提取文章列表?

/ 0评 / 0

在“知微” RSS 阅读器中,有项功能是可以写规则,来抓取不支持 RSS 的网站。

对于不懂 Html, CSS Selector 的小白用户来说,该功能很有门槛。

那能否自动识别出用户想要抓取列表?就像识别文章全文的 Readability 一样?

最初我觉得不太可能,于是只支持用户点击页面元素来生成对应的规则,类似之前推荐的 RSS 烧制工具 kimonolabs 和 feedocean。

但是后来我看到 rss-proxy  项目基本达到该目标,于是决定尝试下。

 

我的思路是这样的:

  1. 使用 Jsoup 库解析网页文本获取到 document 对象,并做预处理(去掉会造成 CSS Selector 异常的 className)
  2. 从 document 中筛选出正常的 a 标签(href为JavaScript、文本为空等异常的不要)
  3. 将所有 a 标签,都向父层遍历,取出只有 tagName 的 CSS Selector。
  4. 将所有 a 标签按照 CSS Selector 分组,去掉只有一个 a 标签的分组。
  5. 各组内,将 a 标签不断向父层遍历,直到找到同一个祖元素,绘出支系族谱(Branch Genealogy)
    1. 遍历的同时,记录每层元素的 tagName、className、nth-child,并与上一轮遍历时记录的 CSS Selector 组合成最新的 CSS Selector 。
    2. 如果在 document  中 tagName.className 筛出的节点数 > 当前节点数则舍弃该 className。
    3. 剔除掉类似 post123 等只指向某一篇文章的 className。
    4. 如果当前层有多个元素,才则记录 nth-child。
    5. 找到祖元素时,取该祖元素的唯一 CSS Selector,并与之前遍历出来的 CSS Selector组合起来。
  6. 通过步骤5,我们得到了一列 CSS Selector,逐一从 document 中选出对应的元素集。
  7. 去掉只有一个元素的元素集。
  8. 根据元素集,来将 CSS Selector 分类,根据以下规则只保留一个 CSS Selector。
    1. 提早层级能确定列表项。
    2. nth-child少。
    3. class少。
    4. 文本字数少;
  9. 对每个元素集进行打分,分数最高的就是用户想要抓取的列表,对应 CSS Selector  则是该列表的抓取规则。
  10. 对 CSS Selector 进行拆分,以获取文章标题、文章时间、文章内容等具体抓取规则。
  11. 待续……

目前我只做到的第10步,已经能初步抓取出所有列表了。但是打分算法还是有问题,部分情况下不是能很完美的取出最合适的列表。

 

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注