Skip to content

怎么自定义新的站点规则

PureDark edited this page May 27, 2017 · 6 revisions

先说在前面,不要光看这篇wiki,光看很难明白的,复制一份写好的规则来作为基础进行修改,然后再参照这里的内容,这样理解起来要快得多

基本类型介绍

一个站点规则是由三部分组成的:Site, Rule, Selector ,先不说站点规则具体应该怎么写,先来了解这些结构都包含哪些数据,有什么作用

Rule其实就是Selector的集合,其中规定了取不同的数据要使用哪个Selector

而Site就是由多个Rule构成的,其中包括indexRule(用于获取列表), galleryRule(用于获取画册目录)等

public class Site{
    int sid;
    String title;
    String indexUrl, galleryUrl, searchUrl, loginUrl;
    Rule indexRule, galleryRule, searchRule, extraRule;
    List<Category> categories;
    String flag;
}
public class Rule{
    public Selector item, idCode, title, uploader, cover, category, datetime, rating, tags, description;
    public PictureRule pictureRule;
    public VideoRule videoRule;
    public TagRule tagRule;
    public CommentRule commentRule;
}
public class PictureRule {
    public Selector item, id, thumbnail, url, highRes;
}
public class VideoRule {
    public Selector id, item, thumbnail, content;
}
public class CommentRule {
    public Selector item, avatar, author, datetime, content;
}
public class TagRule {
    public Selector item, title, url;
}
public class Selector {
    public String selector, fun, param, regex, replacement;
}

先详细介绍最基本的数据类型:

Selector属性详解

Selector包含5个属性:

Selector → selector

jQuery选择器,支持任何jQuery支持的选择器语法

不过为了兼容可能以后会有的iOS和UWP版,建议使用css3标准的伪类

另外特殊情况有一种:this 意味着选中当前元素

(如果不知道什么是jQuery选择器或者css选择器的,你大概不适合继续往下看,如果仍然很有兴趣想学,可以百度jquery选择器,进入w3cschool的页面学习)

Selector → fun

对选中的元素使用的方法,目前只支持4种情况:

1.html

效果等同$.html(),即得到元素的内部所有html字符串

2.text

效果等同$.text(),即得到元素的内部字符串去除html标签

3.attr

效果等同$.attr(param),即得到元素的对应属性值

4.null(即不在json中包含这个属性)

效果等于得到包含元素自身的html字符串

Selector → param

仅在fun为attr时起效,作为attr方法的参数

Selector → regex

正则表达式,应用于使用上述选择器最终得到的字符串上,至少包含一个Group,即使用()包含起来的部分,最终取()中匹配到的值作为最后结果

可为null,即不使用正则表达式

Selector → replacement

与regex成对使用,单独无效

将经过regex取到的数值,填到replacement里对应的地方,使用 $1 $2 等代表regex里取到的不同组,如:

"rating": {
    "selector": "td.itd div div.it4 div",
    "fun": "attr",
    "param": "style",
    "regex": "background-position:-(\\d+)px -(\\d+)px",
    "replacement": "5-$1/16-($2-1)/40"
}
最终得到的是一个表达式(rating得到的表达式会最终计算出一个结果)

讲了这么多,我们来看一个例子

<div class="manga_items">
   <div class="manga_item">
     <img src="http://xxx.com/1.jpg" />
   </div>
</div>

我们想要取得img标签的src中的图片地址,那么selector应该怎么写呢?

{
     "selector": "div.manga_item > img"
     "fun": "attr",
     "param": "src"
}
这样取出来的就是 http://xxx.com/1.jpg

但是假设,我们需要获取缩略图,但是缩略图网址在html中没有

而你知道这个网站的缩略图格式应该是这样: http://xxx.com/thumbnail/1.jpg

那么怎么办呢?就要使用到正则表达式和替换式了

{
    "selector": "div.manga_item > img"
    "fun": "attr",
    "param": "src",
    "regex": "(http://xxx.com)/(\\d+\\.jpg)",
    "replacement": "$1/thumbnail/$2"
}
这样最终得到的就是http://xxx.com/thumbnail/1.jpg

Rule属性详解

Rule是Selector的集合,其中规定了取不同的数据要使用哪个Selector

先看看这个html,下面的举例都基于它

<div class="manga_items">
   <div class="manga_item">
     <a class="title" href="http://xxx.com/gallery/10000-1">标题1</a>
   </div>

   <div class="manga_item">
     <a class="title" href="http://xxx.com/gallery/10000-2">标题2</a>
   </div>
</div>

Rule实例包含以下 Selector

item

在indexRule中应该选中每一个独立的画册item,选出的应该是元素集合

在galleryRule中不需要包含此项

下面的每一个Selector都应用在选出的集合中的单例上

且galleryRule获取到的内容会覆盖indexRule获取的部分,例如,indexRule和galleryRule各有一个title的Selector,比如g.e-hentai的列表中标题是英文的,而点进去的详情页获取的是日文标题,则点开后获取到的日文标题会覆盖原标题

比如,按照上面的例子,应该写出的Selector应该是

"item": {
    "selector": "div.manga_items>div.manga_item"
}
其中div.manga_items>div.manga_item能确实地选到所有manga_item,但是只写div.manga_item也可以,写法不只一种,具体请参照css选择器

此处规定了父元素必须是div.manga_items,只是为了确保不会选中多余的元素

idCode

能标识出这个item的唯一标识,将会填在Site.galleryUrl的{idCode:}处

例如,如果Site.galleryUrl是 http://xxx.com/gallery/{idCode:}/page/{page:1}

那么这里要获取到的就是 http://xxx.com/gallery/10000-1 中的 10000-1

则要写出的Selector应该为:

"idCode": {
    "selector": "a",
    "fun": "attr",
    "param": "href",
    "regex": "gallery/(.*)"
}
注1:因为这里的表达式都是基于已取出的item的,所以只需要写a,就相当于在每个.manga_item内部取a标签元素了

注2:正则表达式取出来的只有一个Group时,不需要填写替换式为 "$1" ,会自动取用这个Group

title

item的标题,会显示在首页的列表中,可选,看到这的朋友可以试试写一个取出例子里的标题的Selector

uploader

item的上传者,会显示在首页的列表中,可选

cover

item的封面url,会显示在首页的列表中,可选

需要注意的是支持绝对URL和相对URL,如果获取到的是相对URL不需要使用正则进行更多处理

category

item的分类,会显示在首页的列表中,可选

datetime

item的发布时间,会显示在首页的列表中,可选

rating

item的评分,会显示在首页的列表中,可选

数值从0到5

注:经过处理最终得到的字符串如果是数字,会转成float,如果得到的是一个数学表达式,则会采用表达式计算结果,其他情况则使用字符串长度作为分数

description

item的文字介绍,当使用瀑布流且item没有封面时,会显示在瀑布流中封面的位置

还会显示在点开item后的详情Tab里

tags

item的标签,获取到的应该是元素集合,以期能得到复数个tag,如只能获取到一个元素,并最终得到一个包含了复数个tag,并以一定规则分隔的字符串,则使用正则表达式进行获取,所有符合regex的匹配都将加入tags列表,例如:

      "tags": {
          "fun": "html",
          "regex": "([a-zA-Z0-9 -]+)",
          "selector": "table.it tr:eq(3) td:eq(1)"
      }
lofi.e-hentai会得到类似于
bunny girl, fox boy, full color, furry, furry, judy hopps, nick wilde, zootopia, non-h, finnick
这样的以,为分隔符的字符串,经过regex的匹配,则能将其中所有匹配成功的单个tag取出,另外要注意的是每一个取出的tag会自动进行trim()操作

tagRule

新的获取Tag的方法,如果指定了tagRule则tags会被忽略 包含item、title、url三个Selector 例:

      "tagRule": {
          "item": {
              "selector": "div.info > p > span.genre"
          },
          "title": {
              "fun": "html",
              "selector": "a"
          },
          "url": {
              "fun": "attr",
              "param": "href",
              "regex": "(.*)",
              "replacement": "$1/page/{page:1}",
              "selector": "a"
          }
      }
其中要注意的是url如果有分页,需要用正则加上page参数

pictureRule

一般只在galleryRule中包含

包含item、id、thumbnail、url、highRes五个Selector

例:

      "pictureRule": {
          "item": {
              "regex": "\"http[^\"]*?_\\d{3,4}\\.(?:jpg|jpeg|png|gif|bmp)\"",
              "selector": ".photo > a > img"
          },
          "thumbnail": {
              "fun": "attr",
              "param": "src",
              "regex": "(http[^\"]*?)_\\d{3,4}(\\.(?:jpg|jpeg|png|gif|bmp))",
              "replacement": "$1_400$2",
              "selector": "this"
          },
          "url": {
              "fun": "attr",
              "param": "src",
              "regex": "(http[^\"]*?)_\\d{3,4}(\\.(?:jpg|jpeg|png|gif|bmp))",
              "replacement": "$1_1280$2",
              "selector": "this"
          }
      }
pictureRule.item

选中图册页的每一个图片,选出来的应该是一个集合,这里的regex的作用是筛选,选出的集合中不能匹配的元素会被舍弃

pictureRule.thumbnail

每个选出的图片item对应的缩略图URL

pictureRule.url

每个选出的图片的大图URL,或大图浏览页的跳转URL(需要一个Flag,下面说到Site时再解释)

pictureRule.highRes

可选

每个选出的图片的原图URL,如果网站默认显示的图片是中等分辨率的图,而你可以获取到更高分辨率的原图,则使用这个Selector,设置中的“优先浏览原图”和“优先下载原图”两个选项就是处理是否读取这个选择器获取到的图片地址

获取方法可以是在页面中就能直接得到高清地址,也可以是使用原来的图片地址进行正则替换,最后得到高清图片地址

videoRule

一般只在galleryRule中包含

包含item、thumbnail、content三个Selector

例:

          "videoRule": {
              "content": {
                  "fun": "attr",
                  "param": "src",
                  "regex": "(.*)",
                  "replacement": "https://hanime.tv$1",
                  "selector": "#video_element"
              },
              "item": {
                  "selector": "#video_container"
              }
          }
videoRule.item

选中详情页的每一个视频,选出来的应该是一个集合,这里的regex的作用是筛选,选出的集合中不能匹配的元素会被舍弃

videoRule.thumbnail

选出视频的预览图,如果没有定义这个Selector的话将会采用封面作为视频预览图

videoRule.content

选出视频的播放相关的数据,可以是完整的video标签、也可以是单独取video的源地址,鉴于现在的大部分网站定制html5播放器都需要js才能运行,大部分情况还是只能取源地址使用默认html5播放器进行播放

注意:comment相关的Selector已被commentRule取代

例如:commentItem替换成commentRule.item

commentRule.item

选中每一个独立的评论item,选出的应该是元素集合,可选

如果有评论的话可以通过这个Selector获取,没有也不影响,下面所有comment的Selector都是基于这个所选出的item

commentRule.avatar

评论者的头像地址,可选

commentRule.author

评论者的昵称,可选

commentRule.datetime

评论发布时间,可选

commentRule.content

评论主体内容,可以包含html代码,不需要取出纯字符串,会进行处理,表情图片也能显示

最后:解释一下indexRule和galleryRule的不同

indexRule中,item取的应该是列表中每一个画册item

idCode、title、uploader、cover、category、datetime、tags都是基于item选择器选出的每一个item的

galleryRule中,

title、uploader、cover、category、datetime、tags都需要基于整个html进行选择

Site属性详解

Site → title

站点名称,显示在侧边栏,选中站点后显示在顶部标题栏

Site → indexUrl, galleryUrl, searchUrl, loginUrl

  "indexUrl": "http://g.e-hentai.org/?page={page:0}",
  "galleryUrl": "http://g.e-hentai.org/g/{idCode:}/?p={page:0}",
  "searchUrl": "http://g.e-hentai.org/?f_search={keyword:}&page={page:0}",
  "loginUrl": "https://forums.e-hentai.org/index.php?act=Login"

分别是首页地址、画册目录地址、搜索地址和登录地址,其中登录地址将会在WebView中载入

searchUrl和loginUrl都是可选

其中{page:0}代表填入页数参数的地方,0代表起始数值,有些网站从0开始,有些从1开始

注1:如果有一些网站每次翻页页数增加数值不为1,则参数为{page:起始数字:每次增加}

例如xbooru的URL:http://xbooru.com/index.php?page=post&s=list&pid={page:0:42}

注2:如果想在第一页时不填入page参数,例如绝对领域:

http://www.jdlingyu.moe/cosplay/page/1/ 则不能获取到数据

第一页必须是

则Url应该为

其中pageStr标明了page相关的字符串,有pageStr这个参数的url,在page等于起始页时会不填入pageStr参数

即,在page为1时,绝对领域得到的url是 http://www.jdlingyu.moe/cosplay/

{idCode:}就代表能唯一标识一个item的部分

{keyword:}搜索时填入关键词的地方,后面只加冒号因为不需要默认值

另外还有两个可在url中使用的参数:

{date:yyyy-MM-dd:-2} 基准为当前系统时间,yyyy-MM-dd为日期格式,-2为偏移量,单位为天,比如-2就是前天,其中最后一个参数可省略

{time:HH:mm:ss:-300} 基准为当前系统时间,HH:mm:ss为时间格式(不用担心使用了:),-300为偏移量,单位为秒,比如-300是5分钟前,其中最后一个参数可省略

Site → categories

站点分类,采用indexRule获取数据,具体看最后的站点规则总览

Site → indexRule, galleryRule, searchRule

indexRule是首页(和分类)使用的规则

galleryRule是图册目录页使用的规则

searchRule是搜索页使用的规则,此项为可选,如不填则搜索时采用indexRule

extraRule是配合flag使用的Rule

Site → flag

对该站点的item的显示做一些自定义,多个flag用|分隔

目前支持的flag有

noCover

隐藏封面

noTitle

隐藏标题,会将Tag的行数设为3行(默认为2行)

noRating

隐藏评分

noTag

隐藏标签,会将标题的最高行数设为2行(默认1行)

loginRequired

标记该网站要求登录,在第一次打开时会自动弹出登录界面

repeatedThumbnail

标记网站的图册目录的预览图是一张大图,通过background-position进行移位显示,比如g.e-hentai

使用该标记后应用内会进行相应处理

singlePageBigPicture

标记网站的大图是单页浏览的,图册目录获取到的pictureUrl只是大图浏览页的地址

那么获取大图浏览单页的图片地址的选择器应填入 extraRule→pictureRule→url

preloadGallery

预加载图册详情页,使用该flag会在列表中时就预先加载每个item的详情页,并把获取到的数据填入,刷新列表中item的显示

比如pixiv在列表中获取不到tag,tags的Selector是在galleryRule中的,则使用该flag后会预先加载详情页,获取到tag并刷新显示在列表中

secondLevelGallery

标记网站的点开每个item后,还可能要再进行一层跳转才能进入多图的页面,使用该flag后,galleryRule取到的picture的url应为跳转地址而不是图片地址,如果是图片地址则当成正常图片展示,对于跳转的页面的获取规则填入extraRule

onePicGallery

标记网站的每个item只有一张图片,只有拥有这个flag的站点,会对设置中的“单图直接浏览”生效,即画册只有一张图时点击直接打开浏览界面,跳过目录页

jsNeededIndex、jsNeededGallery、jsNeededPicture、jsNeededAll

前三个分别为标记每个阶段是否需要采用模拟浏览器的方式加载网页,即可以执行初始化js以生成页面,jsNeededAll则是包含前三项

注:使用模拟浏览器方式加载会导致读取速度变慢、并会占用更多资源,除非确定必须执行js才能生成页面,否则不要加这几个flag

jsScroll

标记网站翻页使用模拟滚动的方式,需要和jsNeeded的flag一起使用,标记此项以后URL中不要含有page参数,翻页时模拟的浏览器会模拟一次页面滚动到底部的操作

postIndex、postGallery、postPicture、postAll

标记网站请求是否需要使用POST方法

注1:一些网站必须用post,一些则是必须用get,用post反而得不到数据

注2:参数正常地像GET方法一样放在url后面就行了

网站cookie,填入的话会在进行请求时带上,用于一些需要登陆的网站,通过应用内的登录功能会自动获取到并填入,无特殊情况不需要手动修改

站点规则JSON总览

下面是一个站点规则的具体JSON:

拿g.e-hentai作为示例,先看JSON,我相信任何一个程序员只需要看一下json就能大致了解每个元素的具体含义,如果有不明白的地方可以再详细看上面的解释:

{
    "categories": [
        {
            "cid": 1,
            "title": "首页",
            "url": "http://g.e-hentai.org/?page={page:0}"
        },
        {
            "cid": 2,
            "title": "同人志",
            "url": "http://g.e-hentai.org/doujinshi/{page:0}"
        },
        {
            "cid": 3,
            "title": "漫画",
            "url": "http://g.e-hentai.org/manga/{page:0}"
        }
    ],
    "title": "G.E-hentai",
    "indexUrl": "http://g.e-hentai.org/?page={page:0}",
    "galleryUrl": "http://g.e-hentai.org/g/{idCode:}/?p={page:0}&hc=1",
    "searchUrl": "http://g.e-hentai.org/?f_search={keyword:}&page={page:0}",
    "loginUrl": "https://forums.e-hentai.org/index.php?act=Login",
    "flag": "singlePageBigPicture|repeatedThumbnail|preloadGallery",
    "indexRule": {
        "item": {
            "selector": "table.itg tr.gtr0,tr.gtr1"
        },
        "idCode": {
            "fun": "attr",
            "param": "href",
            "regex": "/g/(.*)",
            "selector": "td.itd div div.it5 a"
        },
        "title": {
            "fun": "html",
            "selector": "td.itd div div.it5 a"
        },
        "cover": {
            "fun": "html",
            "regex": "(//|inits?~)(.*?org)[~/]([^~]*\\.jpg)[~\"]",
            "replacement": "http://$2/$3",
            "selector": "td.itd div div.it2"
        },
        "uploader": {
            "fun": "html",
            "selector": "td.itu div a"
        },
        "category": {
            "fun": "attr",
            "param": "alt",
            "selector": "td.itdc a img"
        },
        "datetime": {
            "fun": "html",
            "selector": "td.itd[style]"
        },
        "rating": {
            "fun": "attr",
            "param": "style",
            "regex": "background-position:-?(\\d+)px -?(\\d+)px",
            "replacement": "5-$1/16-($2-1)/40",
            "selector": "td.itd div div.it4 div"
        }
    },
    "galleryRule": {
        "commentRule": {
            "author": {
                "fun": "html",
                "selector": "div.c3 > a:first-child"
            },
            "content": {
                "fun": "html",
                "selector": "div.c6"
            },
            "datetime": {
                "fun": "html",
                "regex": "Posted on (.*?) UTC by",
                "selector": "div.c3"
            },
            "item": {
                "selector": "div#cdiv > div.c1"
            }
        },
        "pictureRule": {
            "item": {
                "selector": "div.gdtl,div.gdtm"
            },
            "thumbnail": {
                "regex": "(http://[^\"]*?\\.jpg)",
                "selector": "this"
            },
            "url": {
                "fun": "attr",
                "param": "href",
                "selector": "a"
            }
        },
        "tags": {
            "fun": "html",
            "selector": "div#taglist table tr td:eq(1) div a"
        },
        "title": {
            "fun": "html",
            "selector": "h1#gj"
        }
    },
    "extraRule": {
        "pictureRule": {
            "url": {
                "fun": "attr",
                "param": "src",
                "selector": "div.sni a img[style]"
            }
        }
    }
}

网页版测试工具

最后提供一个网页版测试工具:

第一个是测试获取列表的,第二个是测试点开后获取详情的

第一个粘贴站点规则后只需要填入这个规则解析的页面URL,可以用不同地址来测试首页和各个分类、搜索页是否都能成功获取,,只会获取第一页作为测试

第二个是粘贴站点规则后,把第一个站点测试获取到的随便哪个item粘贴进去,就能测试获取这个item的详情,同样只会获取第一页

为了最快掌握用法可以直接把我写好的一个站点的规则粘贴进去,然后粘贴首页地址(记得把page参数的位置改成数字),然后看看结果

Clone this wiki locally