跳转至

开源阅读内容提取

预计阅读时长 : 3 分钟

提取流程

Legado 通过配置的对应 url 的网络请求获取到响应内容后,下一步就是通过提取规则提取指定的内容,最终通过 书名封面目录等属性将内容展示给用户。

在 Legado 中,元素和属性的提取使用了 JSoup、 JSONPath 两种不同的解析器,同时也支持对纯文本使用正则方式提取内容。

  • HTML:JSoup
  • JSON:JSONPath
  • String:Regex

JSOUP

技术框架

对于最常见的 HTML 源文本,Legado 使用 JSoup 作为 HTML 解析器,详细说明文档见 jsoup.org, 还有一个线上测试工具 Try Oline ⧉

选择器语法

为了保持通用性,在本教程中我们将使用 CSS 语法 ⧉进行元素选择,使用时必须以 @css: 开头。

属性获取

在获取到指定元素后,使用 @ 可以获取相应的元素属性 ⧉

常见元素属性

  • @text 用于获取节点及其所有子节点的全部文本内容,并以集合的形式返回
  • @textNodes 获取节点直接包含的文本节点,并以集合的形式返回
  • @html 获取节点及其所有子元素的 HTML 内容
  • @href 获取节点属性中的链接地址
  • @alt 获取图片节点中的注释内容
  • @src 获取图片节点中的图片地址

自定义元素

在获取页面中的各类属性值时,可以重点看一下 <head> 中的代码。例如,腾讯新闻页面中的,可以通过 @css: head > meta[name="Description"]@content 获取到新闻的简介。

1
2
3
<head>
  <meta name="Description" content="每经编辑:李泽东据“赤坎发布”,广东省湛江市赤坎区2月19日发布《关于促进赤坎区房地产市场平稳健康发展倡议书》。倡议书指出,当前,房地产市场相对低迷,各级政府相继出台稳楼市政策,区委、区政府多渠道谋划,主动对接房地产企业让利于民,联手推出“一口价”特惠房源。希望广大干部职工带头消费、示范带动,...">
</head>

示例

CSS语法示例
"ruleSearch": { 
    "author": "@css:p:eq(2)>a@text",    
    "bookList": "@css:li.clearfix", 
    "bookUrl": "@css:.name>a@href", 
    "coverUrl": "@css:img@src", 
    "intro": "@css:.note.clearfix + p@text",  
    "kind": "@css:.note_text,p:eq(4)@text", 
    "lastChapter": "@css:p:eq(3)@text", 
    "name": "@css:meta[property=\"og:title\"]@content"
    }

JSONPath

同时,针对可以直接通过 API 以 JSON 格式获取的内容,开源阅读使用 JSONPath 作为 JSON 解析器,使用时请以 @json:$. 开头。

说明文档见 JSONPath - XPath for JSON, 还有一个线上测试工具 Try Oline ⧉

JSONPath 语法示例
1
2
3
4
5
6
7
8
9
"ruleBookInfo": {
    "name": "$.info.drama.name",
    "author": "$.info.drama.author",
    "kind": "$.info.drama.type",
    "lastChapter": "$.info.drama.newest",
    "intro": "$.info.drama.abstract",
    "coverUrl": "$.info.drama.cover",
    "tocUrl": "https://www.missevan.com/dramaapi/getdramaepisodedetails?drama_id={{$.info.drama.id}}&p=1&page_size=10"
}

规则运算符

JSoup 与 JSONPath 支持三种运算符:&&||%%。这些运算符只能在同种规则间使用,JSoup 与 JSONPath 之间不能混用。

  • && : 合并所有取到的值
  • || : 以第一个取到值的为准
  • %% : 依次取数,如三个列表
    • 先取列表1的第一个,再取列表2的第一个,再取列表3的第一个
    • 再取列表1的第二个,再取列表2的第二个,……

Regex

Regex (正则) 是一种强大的文本处理工具,详细介绍见 正则表达式教程 ⧉

与前面处理 HTML 和 JSON 这样的结构化数据不同,Regex 适用于处理无结构的文本数据,主要用在提取指定的文本内容,或者替换文本中的指定内容。

Legado 的正则底层是使用的 Java 的 Pattern 类,支持的语法是 Java 的正则语法,然后在配置规则中使用了 :## 语法糖来实现不同的修饰符效果。

除了源配置之外,正则还在 替换净化 规则中发挥着重要作用,可以以更加灵活的方式实现对文本内容的替换和净化。

AllinOne(提取)

  • 使用时必须以 : 开头
  • 可使用 -: 倒序输出存储匹配结果的数组
  • 只能在搜索列表、发现列表、详情页预加载和目录列表中使用,相当于通过正则方式提取对应供下一步使用的原始文本内容
  • 提取之后,整体匹配内容和括号指定的分组,将以捕获分组的形式传递,可在下一步规则中通过 $1$2 的格式被引用
列表提取
1
2
3
4
5
6
  "ruleToc": {  
      "chapterList": "-:href=\"(/read[^\"]*html)\">([^<]*)",    
      "chapterName": "$2",  
      "chapterUrl": "$1",   
      "nextTocUrl": ""
      },

OnlyOne(替换)

  • 使用时必须以 ## 开头
  • 可以在搜索列表、发现列表、详情页预加载、目录列表之外使用,相对于在获取的属性值原始文本内容中,进行替换操作
  • 也支持捕获分组,可以在替换内容中使用

循环替换语法格式为 ##正则表达式##替换内容,如果要实现无替换内容,相当于实现删除效果,可以直接使用 ##正则表达式

循环替换
1
2
3
4
"ruleContent": {    
  "content": "@css:.articleDiv p@text##搜索.*手机访问", 
    "nextContentUrl": ""
    }

单次替换语法格式为 ##正则表达式##替换内容###,只获取第一个匹配到的结果并进行替换

单个替换
1
2
3
4
5
6
7
8
9
"ruleBookInfo": {
    "author": "##:author\"[^\"]*\"([^\"]*)##$1###",
    "coverUrl": "##og:image\"[^\"]*\"([^\"]*)##$1###",
    "intro": "##:description\"[^\"]*\"([\\w\\W]*?)\"/##$1###",
    "kind": "##:category\"[^\"]*\"([^\"]*)##$1###",
    "lastChapter": "##:chapter_name\"[^\"]*\"([^\"]*)##$1###",
    "name": "##:book_name\"[^\"]*\"([^\"]*)##$1###",
    "tocUrl": ""
    }