跳转至

开源阅读配置说明

预计阅读时长 : 19 分钟

整体流程

graph LR
    A[基本 - 源域名] -->|二选一必填| B(搜索 - 地址)
    A -->|二选一必填| C(发现)
    B -->|必填| D{详情}
    C -->|必填| D
    D -->|选填| E[目录]
    E -->|必填| F[正文]
    F -->|必填| G(其他)

书源处理的流程,简而言之可以分为网络请求和内容提取两个环节。在整个流程中,这两个环节首尾相连持续循环。

前者是通过网络请求抓取原始内容,后者是在本地进行内容的提取和处理,整个配置界面中不同模块里的各个属性项,就是针对这两个环节一步一步制定相应的规则。

基础 Tab

源类型 (bookSourceType) 必填

  • 0: 文本
  • 1: 音频
  • 2: 图片
  • 3: 文档

源域名 (bookSourceUrl) 必填

  • 通常填写网站主页,在搜索 Tab 和发现 Tab 中作为 baseURL 调用,也可以在其他 Tab 中使用 source.key 调用
  • 源的唯一性标识,不可重复,与其他源相同会覆盖

源名称 (bookSourceName) 必填

  • 显示在源列表中的名称
  • 名字可重复

源分组 (bookSourceGroup) 选填

  • 描述源的特征信息
  • 用于分组源

源注释 (bookSourceComment) 选填

  • 描述源作者和状态

登陆地址/登录 URL (loginUrl) 选填

  • 默认使用内置 webView 访问 URL 登录网站,仅在需要登录的源有用
  • 如果使用自定义 登陆界面,则需要在这里通过 JS 代码实现登录逻辑,其中 login 函数必须实现

登陆界面/登录 UI (loginUi) 选填

  • 不使用内置 webView 登录网站时,可以在这里自定义登陆界面,然后使用 登录地址 中的 JS 代码实现登录逻辑,并使用 登录检测 中的 JS 代码检查登录结果
  • 实例详见 阿里云登陆模版详解 ⧉

登陆检测/登录检查 JS (loginCheckJs) 选填

  • 对登录后的响应内容进行判断,确定是否符合登录后规则结果的预期,并根据规则结果进行相应的处理

封面解密 (coverDecodeJs) 选填

  • 适用于封面需要二次解密的情况,直接填写 JavaScript
  • 部分变量说明:java(仅支持 js 扩展类),result 为待解密封面的 inputStream,src 为图片链接

链接验证/书籍 URL 正则 (bookUrlPattern) 选填

  • 书籍 URL 正则,当详情页 URL 与源 URL 的域名不一致时有效,用于添加网址
  • 只包括客户端信息的时候,可以直接使用 JSON 格式的内容,如:{"User-Agent":"Mozilla/5.0"}
  • 如果涉及到复杂的参数,需要使用 JSON.stringify() 方法将对象转换为字符串

变量说明 (variableComment) 选填

  • 关于书源的变量的说明文本

并发率 (concurrentRate) 选填

  • 并发限制,单位 ms,可填写两种格式
    • 1000 : 访问间隔 1s
    • 20/60000 : 60s 内访问次数 20

JS 库 (jsLib) 选填

  • 将 JavaScript 代码或者第三方线上库引入 RhinoJs 引擎中,支持两种格式,可实现函数共用

链接验证 (bookUrlPattern) 选填

  • 当详情页 URL 与源 URL 的域名不一致时有效,用于添加网址

搜索 Tab

搜索地址 (searchUrl) 必填

  • 支持 {{}} 变量调用,默认使用 JavaScript 语法,不需要 @js: 开头
    • key : 搜索关键词变量
      • 可以对 key 进行加密等操作,如:{{java.base64Encode(key)}}
    • page : 搜索结果页码变量
      • page 的默认值初始值为 1
      • 也可以对 page 进行计算,如:{{(page-1)*20}}
      • 有时会遇到第一页没有页数的情况,有两种方法处理:
        • 三元运算符:{{page-1==0?"":page}}
        • 字符串中的可选项:<,{{page}}>
  • 支持在源域名基础上使用相对 Url,但如果要向下级规则传递 baseUrl,则必须使用绝对 Url,否则会找不到正确的 url。因此,建议大多数情况下使用绝对 Url

校验文字/检索关键字 (checkKeyWord) 选填

  • 默认的搜索关键词

列表规则/书籍列表规则 (bookList) 必填

  • 选择书籍节点(规则结果为 List
  • 调用规则的时候,先对搜索地址进行网络请求,然后从返回的响应内容中的 HTML/JSON/String 里提取相应元素组成列表数组,供下一步规则提取元素属性值
  • 支持 JSoup/JSONPath/Regex AllinOne 语法,特别复杂的需求还可以使用 JS 脚本,只要保证规则结果是一个数组即可
  • 其他的列表规则也是同样的操作逻辑,也支持同样的语法规则

书名规则 (name) 选填

  • 选择书名节点(规则结果为 String)

作者规则 (author) 选填

  • 选择作者节点(规则结果为 String)

分类规则 (kind) 选填

  • 选择分类节点(规则结果为 String)

字数规则 (wordCount) 选填

  • 选择字数节点(规则结果为 String)

最新章节/最新章节规则 (lastChapter) 选填

  • 选择最新章节节点(规则结果为 String)
  • 如果 目录 Tab 中获取的目录列表不为空,则会被最后一个目录的属性值覆盖

简介规则 (intro) 选填

  • 选择书籍简介节点(规则结果为 String)

封面规则 (coverUrl) 选填

  • 选择书籍封面节点(规则结果为 String 类型的 Url)

详情地址/详情页 URL 规则 (bookUrl) 必填

  • 选择书籍详情页网址节点(规则结果为 String 类型的 Url)
  • 规则结果将传递给 详情 Tab 作为 baseUrl,还可以继续传递给 目录 Tab 和 正文 Tab 作为 baseUrl

发现 Tab

发现地址/发现地址规则 (explorerUrl) 必填

发现页地址支持两种格式:

  • <name>::<url> : 多个发现链接,用换行符或者 && 连接
  • [{url:<url>,title:<name>,style:...},...] : 数组格式,调用时用 JavaScript 动态生成,支持样式定制

其他规则

其他规则参见 搜索 Tab 中的相关规则说明,如果不填则直接使用搜索规则

详情 Tab

预处理/预处理规则 (bookInfoInit) 选填

  • 对于非 HTML/JSON 格式的纯文本响应内容,可以使用正则 AllinOne 语法进行预处理,并通过捕获分组在下一步提取需要的属性值

书名规则 (name) 选填

  • 选择书名节点(规则结果为 String)

作者规则 (author) 选填

  • 选择作者节点(规则结果为 String)

分类规则 (kind) 选填

  • 选择分类节点(规则结果为 String)

字数规则 (wordCount) 选填

  • 选择字数节点(规则结果为 String)

最新章节/最新章节规则 (lastChapter) 选填

  • 选择最新章节节点(规则结果为 String)
  • 如果 目录 Tab 中获取的目录列表不为空,则会被最后一个目录的属性值覆盖

简介规则 (intro) 选填

  • 选择书籍简介节点(规则结果为 String)

封面规则 (coverUrl) 选填

  • 选择书籍封面节点(规则结果为 String 类型的 Url)

目录地址/目录页 URL 规则 (tocUrl) 选填

  • 选择目录页网址节点(规则结果为 String 类型的 Url)
  • 与详情页相同时可省略,会使用 baseUrl

修改书籍 (canReName) 选填

  • 允许修改书名作者(规则结果为 String 类型,默认不允许

下载 URL/下载 URL 规则 (downloadUrls) 选填

  • 文档类书源下载地址(规则结果为 String 类型的 Url,多个链接返回数组)

baseUrl 的复用

  • 如果没有单独的目录页,即目录信息就在详情页中时,可以省略 详情 Tab 中的 目录地址 规则,直接在 目录 Tab 中复用 详情 Tab 的 baseUrl。
  • 如果详情页中也没有目录信息,那么 目录 Tab 中的 章节地址 可以继续为空,继续复用 详情 Tab 的 baseUrl 传递给 正文/章节 Tab。但是,必须在 列表规则 + 章节名称 中,组合出一个目录的信息基础,这样才能保证网络请求链条的完整和畅通。

目录 Tab

更新之前 JS (preUpdateJs) 选填

  • 更新目录前调用 JS 动态更新目录链接

列表规则/目录列表规则 (chapterList) 必填

  • 选择目录列表的章节节点(规则结果为 List
  • 首字符使用负号 (-) 可使列表数组反序

章节名称/章节名称规则 (chapterName) 必填

  • 选择章节名称节点(规则结果为 String)

章节地址/章节 URL 规则 (chapterUrl) 选填

  • 选择章节链接节点(规则结果为 String 类型的 Url)
  • 如果为空,则使用 baseUrl

标题处理/格式化规则 (formatJS) 选填

  • 遍历去重后的章节列表的回调,提供 index(章节序号从 1 开始)、title(章节标题)变量,额外提供 gInt(初始值 0),返回值作为新的标题

卷名标识/Volume 标识 (isVolume) 选填

  • 章节名称是否是卷名(规则结果为 Bool 类型)

章节信息/更新时间 (ChapterInfo) 选填

  • 选择章节节点(规则结果为 String)

收费标识/VIP 标识 (isVip) 选填

  • 章节是否为 VIP 章节(规则结果为 Bool 类型)

购买标识 (isPay) 选填

  • 章节是否为已购买章节(规则结果为 Bool 类型)

翻页规则/目录下一页规则 (nextTocUrl) 选填

  • 选择目录下一页链接(规则结果为 List或 String)

正文 Tab

正文规则 (content) 必填

  • 选择正文内容节点(规则结果为 String)
  • 建议使用正文所在元素的 @html 属性值,可以保留网页展示效果

标题规则/章节标题规则 (title) 选填

  • 选择章节标题节点(规则结果为 String)
  • 获取的结果将会覆盖章节标题

翻页规则/下一分页 URL 规则 (nextContentUrl) 选填

  • 选择下一分页(不是下一章)的链接(规则结果为 String 类型的 Url)

脚本注入/WebView JS (webJs) 选填

  • 注入 javascript,用于模拟鼠标点击等,必须有返回值,一般为 String 类型

资源正则 (sourceRegex) 选填

  • 匹配资源的 url 特征,用于嗅探页面上的资源

替换规则 (replaceRegex) 选填

  • 在多页内容合并之后进行替换,用于正文净化,可以使用正则之 OnlyOne 语法

图片样式 (imageStyle) 选填

  • FULL: 铺满;不填: 默认样式

图片解密 (imageDecode) 选填

  • 填写 JavaScript 返回解密图片的 bytes
  • 适用于图片需要二次解密的情况,直接填写 JavaScript,返回解密后的 ByteArray
  • 部分变量说明:java(仅支持 js 扩展类),result 为待解密图片的 ByteArray,src 为图片链接

购买操作/购买链接 (payAction) 选填

  • 填写 JavaScript 返回购买链接或者调用购买接口
  • 如果执行结果是网络链接将会自动打开浏览器,js 返回 true 将会自动刷新目录和当前章节

其他

启用搜索 (enabled)

  • 是否开启搜索

启用发现 (enabledExplore)

  • 是否开启发现
  • 启用后会自动保存每次返回头中的 Set-Cookie 中的值,适用于验证码图片一类需要 session 的网站

搜索权重 (weight)

  • 必填

排序编号 (customOrder)

  • 必填

示例

JSoup 示例

CSS 语法
{
    "bookSourceGroup": "CSS; 正则",
    "bookSourceName": "🔥小说2016",
    "bookSourceType": 0,
    "bookSourceUrl": "https://www.xiaoshuo2016.com",
    "bookUrlPattern": "",
    "customOrder": 0,
    "enabled": true,
    "enabledExplore": false,
    "exploreUrl": "",
    "lastUpdateTime": 0,
    "loginUrl": "",
    "searchUrl": "/modules/article/search.php?searchkey={{key}}&submit=&page={{page}}",
    "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:.name@text"
        },
    "ruleExplore": {},
    "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": ""
        },
    "ruleToc": {
        "chapterList": "-:href=\"(/read[^\"]*html)\">([^<]*)",
        "chapterName": "$2",
        "chapterUrl": "$1",
        "nextTocUrl": ""
        },
    "ruleContent": {
        "content": "@css:.articleDiv p@textNodes##搜索.*手机访问|一秒记住.*|.*阅读下载|",
        "nextContentUrl": ""
        },
    "weight": 0
}

JSONPath 示例

JSONPath 语法
{
  "bookSourceUrl": "https://www.missevan.com",
  "bookSourceType": 1,
  "bookSourceName": "猫耳FM",
  "bookSourceGroup": "",
  "bookSourceComment": "",
  "loginUrl": "",
  "loginUi": "",
  "loginCheckJs": "",
  "concurrentRate": "",
  "header": "",
  "bookUrlPattern": "",
  "searchUrl": "/dramaapi/search?s={{key}}&page={{page}}",
  "exploreUrl": "",
  "enabled": false,
  "enabledExplore": false,
  "weight": 0,
  "customOrder": 0,
  "lastUpdateTime": 1706691666738,
  "ruleSearch": {
    "bookList": "$.info.Datas",
    "name": "name",
    "author": "author",
    "kind": "{{$.type_name}},{{$.catalog_name}}",
    "lastChapter": "newest ",
    "intro": "abstract",
    "coverUrl": "cover ",
    "bookUrl": "/dramaapi/getdrama?drama_id={{$.id}}"
  },
  "ruleExplore": {},
  "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"
  },
  "ruleToc": {
    "chapterList": "$.info.Datas",
    "chapterName": "soundstr",
    "chapterUrl": "https://www.missevan.com/sound/player?id={{$.id}},{\"webView:true}",
    "updateTime": "intro"
  },
  "ruleContent": {
    "content": "@css:result@html"
  }
}