[自动无缝翻页] `自定义翻页规则` 示例说明
XIU2 opened this issue · 4 comments
自动无缝翻页 脚本从 v4.8.8
版本开始,支持了自定义翻页规则。
不过当初仅为自用,压根没有考虑过这需求,我只能勉强实现自定义翻页规则,因此只适用于简单的静态加载内容网站,当然这类网站占大多数,我写的数百规则中大部分都是这类网站,因此一般是够用了~
# 自写规则 前提条件
- 了解 JSON 基本格式
( 主要是逗号、转义、双引号 )
- 了解 CSS 或 XPath 选择器用法
( 优先使用 CSS 选择器)
- 可能需要会一点 JavaScript 语言 / 正则表达式
( 依靠 URL 匹配规则 )
简单的来说,这就是提供给 懂一些技术 的用户自给自足制作规则用的~
大多数网站的规则一般都只需要这样:
// "aaa" 是规则名,唯一,自定义翻页规则 将覆盖同名的 外置翻页规则
// "url" 是用来控制哪些网站中页面适用该规则,省略后代表该规则应用于全站
// "scrollD" 是用来控制翻页敏感度的(越大就越早触发翻页,访问速度慢的网站需要调大,可省略(注意逗号),默认 2000)
"aaa": {
"host": "aaa.com",
"url": "/xxx/",
"pager": {
"nextL": "xxx",
"pageE": "xxx",
"replaceE": "xxx",
"scrollD": 2000
}
}
大家也可以在下面 提出改进建议 或 分享规则~
# 规则总览(只列出了目前 自定义翻页规则 能用的)
「 点击展开查看 」
host: 先匹配域名,可以是文本,也可以是正则表达式,也可以是数组(数组中也可以文本和正则表达式混合使用)
url: 匹配到域名后,再来匹配 URL,也可以用来执行一些 JS 代码
urlC: 对于使用 pjax 技术的网站,需要监听 URL 变化来重新判断翻页规则(需要放在 url: 中,自定义规则的话需要使用 fun.isUrlC())
noReferer: 获取下一页内容时,不携带 Referer(部分网站携带与不携带可能不一样)
hiddenPN: 不显示脚本左下角的页码
history: 添加历史记录 并 修改当前 URL(默认开启,对于不支持的网站要设置为 false)
thread: 对于社区类网站,要在 帖子内 的规则中加入这个,用于脚本的 [帖子内自动翻页] 功能(即用户可以选择开启/关闭所有社区类网站帖子内的自动翻页)
style: 要插入网页的 CSS Style 样式
retry: 允许获取失败后重试
blank: 强制新标签页打开链接(1 = <base> 方式,2 = 对 body 点击事件委托,3 = 仅对 pageE 的父元素点击事件委托,4 = 仅对 pageE 的父元素添加 target="_blank")
pager: {
type: 翻页模式
1 = 由脚本实现自动无缝翻页,可省略(适用于:静态加载内容网站,常规模式)
2 = 只需要点击下一页按钮(适用于:网站自带了 自动无缝翻页 功能)
nextText: 按钮文本,当按钮文本 = 该文本时,才会点击按钮加载下一页(避免一瞬间加载太多次下一页,下同)
nextTextOf: 按钮文本的一部分,当按钮文本包含该文本时,才会点击按钮加载下一页
nextHTML: 按钮内元素,当按钮内元素 = 该元素内容时,才会点击按钮加载下一页
interval: 点击间隔时间,对于没有按钮文字变化的按钮,可以手动指定间隔时间(单位 ms,默认 500,当指定上面三个时,会忽略 interval)
isHidden: 只有下一页按钮可见时(没有被隐藏),才会点击
3 = 依靠 [基准元素] 与 [浏览器可视区域底部] 之间的距离缩小来触发翻页(适用于:主体元素下方内容太多 且 高度不固定时)
scrollE: 作为基准线的元素(一般为底部页码元素),和 replaceE 一样的话可以省略
scrollD: 基准元素 - 可视区域底部
4 = 动态加载类网站(适用于:简单的动态加载内容网站)
insertE: 用来插入元素的函数
5 = 插入 iframe 方式来加载下一页,无限套娃(适用于:部分动态加载内容的网站,需要允许 iframe 且支持通过 GET/POST 直接打开下一页)
style: 加载 iframe 前要插入的 CSS Style 样式(比如为了悬浮的样式与下一页的重叠,隐藏网页底部间距提高阅读连续性)
iframe: 这个必须加到 pager{} 外面(这样才会在该域名的 iframe 框架下运行脚本)
6 = 通过 iframe 获取下一页动态加载内容插入本页,只有一个娃(适用于:部分动态加载内容的网站,与上面不同的是,该模式适合简单的网页,没有复杂事件什么的)
loadTime: 预留的网页加载时间,确保网页内容加载完成
nextL: 下一页链接所在元素
pageE: 要从下一页获取的元素
insertP: 下一页元素插入本页的位置(数组第一个是基准元素,第二个是基准元素的前后具体位置)
1 = 插入基准元素自身的前面
2 = 插入基准元素内,第一个子元素前面
3 = 插入基准元素内,最后一个子元素后面
4 = 插入基准元素自身的后面
5 = 插入 pageE 列表最后一个元素的后面(该 insertP 可以直接省略不写,等同于 ['pageE', 5] )
6 = 插入该元素自身内部末尾(针对小说网站等文本类的),附带参数 insertP6Br: true, 用来中间插入换行
// 小技巧:当基准元素是下一页主体元素的父元素时(或者说要将下一页元素插入到本页同元素最后一个后面时)是可以省略不写 insertP
例如:当 pageE: 'css;ul>li' 且 insertP: ['css;ul', 3] 时,实际等同于 ['css;ul>li', 5]
当 pageE: 'css;.item' 且 insertP: ['css;.item', 4] 时,实际等同于 ['css;.item', 5]
当 pageE: 'css;.item' 且 insertP: ['css;.page', 1] 时,实际等同于 ['css;.item', 5]
注意:如 pageE 中选择了多类元素,则不能省略 insertP(比如包含 `,` 与 `|` 符号),除非另外的选择器是 <script> <style> <link> 标签
replaceE: 要替换为下一页内容的元素(比如页码),省略则不进行替换,省力的话可以和 nextL 内容一样(但不能是 JS 代码)
scrollD: 翻页动作触发点([滚动条] 与 [网页底部] 之间的距离),数值越大,越早开始翻页,一般是访问网页速度越慢,该值就需要越大,省略后默认 2000
scriptT: 单独插入 <script> 标签
0 = 下一页的所有 <script> 标签
1 = 下一页的所有 <script> 标签(不包括 src 链接)
2 = 下一页主体元素 (pageE) 的同级 <script> 标签
3 = 下一页主体元素 (pageE) 的子元素 <script> 标签
interval: 翻页后间隔时间(单位 ms)
forceHTTPS: 下一页链接强制 HTTPS
},
function: {
bF = 插入前执行函数
bFp = 参数
aF = 插入后执行函数
aFp = 参数
}
## 内置函数
为了方便,规则中执行 JS 代码时可以使用脚本内置函数:
「 点击展开查看 」
// 返回当前网页的 URL 路径,等同于 location.pathname
fun.lp()
// 该 indexOF 默认不区分大小写,不过正则表达式除外,需要自己加上 /i 修饰符
// 当前网页的 URL 路径中如果包含指定文本则返回 true,等同于 location.pathname.indexOf('xxx') > -1
fun.indexOF('xxx')
// 也支持正则,对于一些需要复合/多个条件判断时才有必要用这个,否则直接正则写到 "url": "/xxx/" 更好
fun.indexOF(/xxx/)
// 加上 's' 参数,则匹配范围改为 URL 末尾的参数,等同于 location.location.search.indexOf('xxx') > -1
fun.indexOF('xxx', 's')
// 根据 UA 和屏幕大小判断是否为手机浏览器,是手机就返回 true,适用于手机版、电脑版网页域名一致但规则不一致的
fun.isMobile()
// 返回所有指定元素,支持 CSS、Xpath 选择器
fun.getAll('元素选择器', 目标节点(省略则为 document))
// 返回一个指定元素,支持 CSS、Xpath 选择器
fun.getOne()
// 返回所有指定元素,支持 Xpath 选择器
fun.getAllXpath()
// 返回一个指定元素,支持 Xpath 选择器
fun.getXpath()
// 返回所有指定元素,支持 CSS 选择器
fun.getAllCSS()
// 返回一个指定元素,支持 CSS 选择器
fun.getCSS()
// 通用型获取下一页地址(从 元素 中获取页码)
fun.getNextE()
// 通用型获取下一页地址(从 元素 中获取页码,URL 替换 page= 参数)
fun.getNextEP()
// 通用型获取下一页地址(从 元素 中获取页码,URL 替换 pathname 路径)
fun.getNextEPN()
// 通用型获取下一页地址(从 URL 中获取页码,URL 替换 pathname 路径)
fun.getNextUPN()
// 通用型获取下一页地址(从 URL 中获取页码,URL 替换 page= 参数)
fun.getNextUP()
// 通用型获取下一页地址(从 form input 中获取,返回 GET URL)
fun.getNextF()
// 插入 <Style> 自定义 CSS 样式
fun.insStyle()
// 插入前函数(加载图片)
fun.src_bF(pageE, [0, '图片元素选择器', '属性名'])
// 如果你要选择的是 img[data-original] 或 img[data-src] 且加载模式为 0,那么后面这个数组可以省略为 fun.src_bF(pageE)
// 插入前函数(正则过滤,主要针对小说站这种)
fun.xs_bF(pageE, [/正则/, '替换为该内容,可空'])
## URL 匹配 "url": "xxx",
相比于其他同类脚本,我当初为了方便及避免正则折磨,将 域名 和 URL 分开匹配了,毕竟大量复杂的正则匹配会很费时间,分开后就先匹配域名,再去匹配 URL,间接也提高了效率(而且域名大都是文本,非常快 ~
匹配 URL 路径示例(正则表达式匹配范围仅是域名后面的 路径 及 ? 参数):
注意:URL 匹配是从前往后按顺序匹配的,因此同一个网站有多个不同页面规则时,如果 URL 匹配规则有些许重复的地方就需要控制一下顺序。另外,对于正则表达式均不区分大小写(即脚本默认加上 /i 修饰符)。
「 点击展开查看 」
## URL 路径示例:/ (首页)
# 正则表达式
"url": "/^\\/$/",
# 脚本内置函数
"url": "return (fun.lp() == '/')",
# 上面这个等同于下面这个,只是有点长不好记写着不方便,所以我才搞了个内置函数
"url": "return (location.pathname == '/')",
## URL 路径示例:非 / (即不是首页)
"url": "/^\\/.+/",
"url": "return (fun.lp() != '/')",
"url": "return (location.pathname != '/')",
## URL 路径示例:/post (即位于根路径)
"url": "/^\\/post/",
"url": "return (fun.lp() == '/post')",
"url": "return (location.pathname == '/post')",
## URL 路径示例:/aaa/post/111 (即位于路径中间)
"url": "/\\/post\\//",
"url": "return fun.indexOF('/post/')",
"url": "return location.pathname.indexOf('/post')",
## URL 路径示例:/aaa?pid=233 (即只匹配路径参数)
"url": "/pid=/",
"url": "return fun.indexOF('pid=', 's')",
"url": "return location.search.indexOf('pid=')",
## URL 路径示例:/aaa/post/111?pid=233 (即需要同时匹配 /post/ 和 pid=)
## 中间的连接符 && 等于 且 的意思,即需要两边都满足条件才会返回 true
"url": "return (fun.indexOF('/post/') && fun.indexOF('pid=', 's'))",
"url": "return (location.pathname.indexOf('/post') && location.search.indexOf('pid='))",
## URL 路径示例:/aaa/post/111 或 /search (即只需要匹配 /post/ 或 /search)
## 中间的连接符 || 等于 或 的意思,继续只需要任意一个满足条件就会返回 true
"url": "return (fun.indexOF('/post/') || fun.indexOF('/search'))",
"url": "return (location.pathname.indexOf('/post') || location.pathname.indexOf('/search'))",
## 一些情况下,难以依靠 URL 特征来匹配页面,那么还能用网页元素
## 比如目标网页中含有一个 `#pager` 元素(常用页码元素),那么就可以这样写:
"url": "return fun.getCSS('#pager')",
# 规则示例
大家也可以参考我写的数百个翻页规则:https://github.com/XIU2/UserScript/blob/master/other/Autopage/rules.json
注意:因为自定义翻页规则的局限性以及格式的差别,因此不能完全照搬脚本内置规则!
以下是我从内置翻页规则中找的几个规则,并改成了自定义翻页规则的格式,大家可以自行对比理解差别。
注意:以下为了方便对每一条规则进行解释,我直接在规则旁边写了注释,但 JSON 是不存在注释的,因此添加到脚本中时记得移除所有注释内容,否则会报错!
当只有一个规则时,是这样的(示例):
{
"aaa": {
"host": "xxxx",
"xxxx": "..."
}
}
当有多个规则时,要这样连接到一起的(最后一个 }
不加逗号):
{
"aaa": {
"host": "xxxx",
"xxxx": "..."
},
"bbb": {
"host": "xxxx",
"xxxx": "..."
}
}
因此在写入自定义翻页规则的时候,记得包裹着所有规则的 { }
大括号,以及最容易犯错的逗号问题(最后一个 } 不能有逗号)。
## 同一个网站 不同页面 适用不同翻页规则
不同翻页规则的 host 是可以一样的,但是规则名不能一样,通过不同的 url 规则来进行匹配。
比如下面这个就是先从 URL 匹配 /a
如果没找到,那么再去匹配 /b
,如果还没找到那么就直接应用 aaa_3 规则(因为这个没有 url 规则,所以就变成兜底的规则了)。
{
"aaa": {
"host": "a.com",
"url": "/^\\/a/",
"xxxx": "xxxx"
},
"aaa_2": {
"host": "a.com",
"url": "return (fun.lp() == '/b')",
"xxxx": "xxxx"
},
"aaa_3": {
"host": "a.com",
"xxxx": "xxxx"
}
}
## 翻页模式 1
这个模式是最常见的,即网站是纯静态加载内容的。
// 规则名(唯一,不能重复,可以是中文、字母、数字什么的)
"百度搜索": {
// 单个域名
// 支持正则,格式示例如:"host": "/\\.baidu\\.com/", 也支持多个正则组成的数组
"host": "www.baidu.com",
// 当 URL 路径 = /s 时才应用该规则
// 不过为了方便自定义规则,所以这里也给改成了支持正则表达式,像这样:"url": "/^\/s$/",
"url": "return (fun.lp() == '/s')",
// 应用规则时,要插入的自定义 CSS 样式(比如用来隐藏广告什么的)
"style": "xxxx {display: none !important;}",
"pager": {
// 模式 1 的话,可以省略 "type": 1, 这条规则
// 这个是 Xpath 选择器,即在 id="page" 的元素下寻找一个内容包含 下一页的 a 元素
// 这里也可以执行 JS 代码来 return 返回下一页 URL,但要记得在开头加上 js; 标识
"nextL": "id('page')//a[contains(text(),'下一页')]",
// 这个是主体内容元素,即 id="content_left " 的元素下所有子元素
// 因为要向主体内容元素末尾插入,所以 insertP 可以省略
"pageE": "#content_left",
// 这个是将当前网页中的某些元素替换为下一页的同类元素(如页码),想省力的话可以和 nextL 内容一样(但不能是 JS 代码)
"replaceE": "#page",
// 这个是翻页动作触发点,即滚动条 与 网页底部之间小于 2000 时就会翻页,越大就意味着翻页越频繁
"scrollD": 2000
}
}
"在线之家": {
// 多个域名的话,就要写成数组了
"host": [
"www.zxzj.me",
"www.zxzj.fun"
],
"url": "return (fun.lp() != '/' && !fun.indexOF('/detail/') && !fun.indexOF('/video/'))",
"style": "div.stui-page__all {display: none !important;}",
"pager": {
"nextL": "//ul[contains(@class, 'stui-page__item')]//a[text()='下一页']",
"pageE": "ul.stui-vodlist > li",
"replaceE": "ul.stui-page__item",
"scrollD": 1000
},
// 这下面的就是翻页前/后,要做的事情了
"function": {
// 插入前执行的代码,在将主体元素插入网页之前,先处理一下(相比于插入后处理,会更快更好)
// 这个是脚本内置的函数,用来加载图片(一些网站是默认图片,只有浏览到时才会加载图片,而脚本翻页后就只能由脚本去加载图片了)
// 这个里面的 0 代表图片是 src 属性(1 代表是 background-image: url() 背景样式类的图片)
// 这个里面的 0 代表图片是 src 属性(1 代表是 background-image: url() 背景样式类的图片)
// 这个 "img[data-original]" 代表要寻找的图片 CSS 选择器
// 这个 "data-original" 代表要把图片的 data-original 属性内容设置为 src 属性
"bF": "return fun.src_bF(pageE, [1, 'a[data-original]', 'data-original'])"
}
}
"动漫花园": {
"host": [
"dmhy.org",
"share.dmhy.org",
"dmhy.anoneko.com"
],
"pager": {
"nextL": "//div[@class='nav_title']/a[contains(text(), '下一')]",
"pageE": "#topic_list > tbody > tr",
"replaceE": ".nav_title"
},
"function": {
// 插入后执行的代码
// 直接插入 script 标签是不会执行其内部代码的,只有这样插入后才行
"aF": "document.body.appendChild(document.createElement('script')).textContent = `xxx`"
}
}
## 翻页模式 2
这个算是第二常见的,即网站自带了自动无缝翻页功能,只需要点一下网页中相应按钮即可。
"discuz_forum": {
"host": "www.52pojie.cn",
// 没有 url 则代表该规则适用于全站,在规则不影响其他页面的情况下,可以偷懒不写
"pager": {
// 模式 2
"type": 2,
// 网页自带的无缝加载下一页/更多内容的元素
"nextL": "#autopbn",
// 上面元素包含 "下一页" 文字时,脚本才会点击,用来避免多次重复点击,不写的话则会有默认 500ms 的间隔,可以用 interval 规则指定间隔(例如 "interval": 1000, 就是点击下一页元素后最少间隔 1000 毫秒才会继续点击)
"nextTextOf": "下一页",
"scrollD": 2000
}
}
## 翻页模式 3
模式 1 的变种,对于部分网页主体内容与网页底部之间距离不固定的网站,需要把基准从网页底部改为页码等指定元素处。
"3DM": {
"host": "www.3dmgame.com",
"pager": {
// 模式 3
"type": 3,
"nextL": "li.next > a",
// 有些网站需要插入主体内容后,执行一些网页自身的 JS 文件,所以这里同时选择了 script 和网页主体元素
"pageE": ".news_warp_center > *, script[src*='common.js']",
"replaceE": ".pagewrap",
// 基准元素,当和 replaceE 一样时,可以省略
"scrollE": ".pagewrap",
// 如果要运行 pageE 里选择的 script 代码,那么就需要指定 2
"scriptT": 2,
// 为了避免翻页过快,而设置的翻页最小间隔(单位 ms)
"interval": 500,
"scrollD": 500
}
}
## 翻页模式 5
对于部分动态加载内容的网站,如果其支持 iframe 且可以通过 GET 直接打开下一页,那么就能用该模式。
插入 iframe 方式来加载下一页,无限套娃~
"知乎 - 用户主页/收藏夹": {
"host": "www.zhihu.com",
"url": "fun.isUrlC(); if (fun.indexOF(/\\/people\\/.+\\/.+/) || fun.indexOF('/collection/')) {if (self != top) {fun.insStyle('#ProfileHeader {display: none !important;}')}; return true;}",
// 强制新标签页打开链接
"forceTarget": true,
// 允许脚本在该网站的 iframe 中运行,模式 5 必须加上
"iframe": true,
"pager": {
// 模式 5
"type": 5,
// 如果要用 JS 代码生成下一页 URL,则记得在前面加上 js; 标识
"nextL": "js;let next = fun.getCSS('.Pagination .PaginationButton--current+button:not(.PaginationButton-next)');if (next) return (location.origin + location.pathname + '?page=' + next.textContent)",
// 如果要在插入下一页 iframe 后向本页插入自定义样式,则还可以在这里加个 "style" 规则(比如为了悬浮的样式与下一页的重叠,隐藏网页底部间距提高阅读连续性)
"scrollD": 2000
}
}
## 翻页模式 6
对于部分动态加载内容的网站,与上面不同的是,该模式适合简单的网页,没有复杂事件什么的。
插入 iframe 加载下一页,等其处理完后,获取下一页动态加载内容插入本页,只有一个娃~
"拷贝漫画 - 分类页": {
// 对于有规律的多域名,可以写成正则表达式
"host": "/copymanga\\./",
"url": "/\\/comics/",
"pager": {
// 模式 6
"type": 6,
"nextL": "li.next > a",
"pageE": ".exemptComicItem",
"replaceE": "ul.page-all",
// 预留的下一页 iframe 网页加载时间,确保网页内容加载完成
"loadTime": 1000,
"scrollD": 3000
},
"function": {
// 插入本页前,将懒加载图片改为直接加载
// 如果你要选择的是 img[data-original] 或 img[data-src] 且加载模式为 0,那么后面这个数组可以省略为 return fun.src_bF(pageE)
"bF": "return fun.src_bF(pageE, [0,'img[data-src]','data-src'])"
}
}
感觉这样搞还是有点不方便,就干脆又加了个 外置翻页规则列表
,把我最近这几天写的 自定义翻页规则 都给放进去了(后续也会把一些简单的网站规则都放进去),这样用户只需要 更新外置翻页规则
即可。
当然,自定义翻页规则依然保留,提供给有动手能力的人~
您好!版主大大,我以前一直用这个https://github.com/machsix/Super-preloader
, 这个最近更新很少了,感觉你这个自定义翻页规则真的棒,不知道能否添加分隔栏,因为不同页面连接得太完美了,导致我们很难分清哪些没看,那些看了!
@Yunuuuu 不会添加分隔栏,你看我脚本名字就知道了:自动“无缝”翻页
我就是因为不喜欢其他脚本的一些设计(特别是分隔栏我看着很别扭),所以我才专门按照我个人喜好写了这个脚本。
多谢回复!明白了,谢谢您!
你好 大佬 可以添加这个https://www.haoman8.com无缝翻页吗 看漫画的
@Viene0850 已添加支持~(阅读页、分类页
更新外置翻页规则
即可(浏览器右上角 Tampermonkey 扩展图标内的脚本菜单
另外,下次提交申请时,请新开 Issues,这个 Issues 下只讨论自定义翻页规则相关话题。