Skip to content

写源语法

了解语法才能更好的配合工具完成开发流程。

1. 深入浅出

1.1. 基本认识

1.1.1. dom基础

js
<div class="items">
  <a class="item" id="1">first item</a>
  <span class="item" id="2">second item</span>
  <li class="item" id="3" data-id="123">third item</li>
</div>
  • div a span li: 通用的容器标签
  • class id data-id: 属性
    • class用于为元素添加类名
    • id用于为元素提供唯一的标识符
    • data-id用于为元素提供自定义数据
  • 子元素和父元素
    • 父元素: 包含其他元素的元素。例如<div class="items">
    • 子元素: 被其他元素包含的元素。例如<a class="item">

1.1.2. js基础

js
// 变量
var name = "zy"; // 局变量, 可重复定义
let age = 25; // 局变量, 不可重复定义
const PI = 3.14; // 声明常量,一旦赋值不能改变

// 数据类型
typeof 123; // number
typeof "123"; // string
typeof true; // boolean
typeof null; // object
typeof undefined; // undefined
typeof { name: "zy" }; // object
typeof [1, 2, 3]; // object
typeof function () {}; // function

// 运算符
let a = 5;
let b = 2;
console.log(a + b); // 加法 输出 7
console.log(a - b); // 减法 输出 3
console.log(a * b); // 乘法 输出 10
console.log(a / b); // 除法 输出 2.5
console.log(a % b); // 取余 输出 1
console.log(a ** b); // 幂运算 输出 25

// 比较运算符
console.log(a == b); // 等于 输出 false
console.log(a != b); // 不等于 输出 true
console.log(a > b); // 大于 输出 true
console.log(a < b); // 小于 输出 false
console.log(a >= b); // 大于等于 输出 true
console.log(a <= b); // 小于等于 输出 false

// 字符串
let str = "Hello World!";
console.log(str.length); // 长度 输出 12
console.log(str.indexOf("World")); // 查找第一个字母下标 输出 6
console.log(str.slice(6, 11)); // 截取字符串(开始位置, 长度) 输出 World
console.log(str.replace("World", "zy")); // 替换字符串 输出 Hello zy!
console.log(str.toUpperCase()); // 转大写 输出 HELLO WORLD!
console.log(str.toLowerCase()); // 转小写 输出 hello world!
console.log(str.split(" ")); // 字符串分割(分隔字符) 输出 ["Hello", "World!"]

// 数组
let cars = ["BMW", "Volvo", "Saab"];
console.log(cars.length); // 长度 输出 3
console.log(cars[0]); // 访问第一个元素 输出 BMW
cars.push("Audi"); // 添加元素到数组末尾 输出 ["BMW", "Volvo", "Saab", "Audi"]
cars.pop(); // 删除数组末尾元素 输出 ["BMW", "Volvo", "Saab"]
cars.shift(); // 删除数组第一个元素 输出 ["Volvo", "Saab"]
cars.unshift("Audi"); // 添加元素到数组第一个元素 输出 ["Audi", "Volvo", "Saab"]

// 对象
let person = { name: "zy", age: 25, city: "Shanghai" };
console.log(person.name); // 访问对象属性 输出 zy
person.age = 26; // 修改对象属性值 输出 { name: "zy", age: 26, city: "Shanghai" }
delete person.city; // 删除对象属性 输出 { name: "zy", age: 26 }

// 函数
function sayHello() {
  console.log("Hello World!");
}
sayHello(); // 输出 Hello World!

function add(a, b) {
  return a + b;
}
console.log(add(3, 5)); // 输出 8

// 条件语句
let age = 25;
if (age >= 18) {
  console.log("成年人");
} else if (age >= 12) {
  console.log("青少年");
} else {
  console.log("儿童");
} // 输出 成年人

// 循环语句
for (let i = 0; i < 5; i++) {
  console.log(i);
} // 输出 0 1 2 3 4

// 异常处理
try {
  throw "An error!";
} catch (error) {
  console.log(error);
} // 输出 An error!

1.2. Cheerio

1.2.1. CSS选择器

js
const cheerio = require('cheerio');
const html = `
<div id="container">
  <ul class="list">
    <li class="item-0">first item</li>
  </ul>
</div>
`;
const $ = cheerio.load(html);
console.log($('#container .list li').text()); // 输出嵌套的 <li> 元素的内容

// 输出内容
// first item

1.2.2. 查找子元素

js
const cheerio = require('cheerio');
const html = `
<div id="container">
  <ul class="list">
    <li class="item-0">first item</li>
    <li class="item-1"><a href="link2.html">second item</a></li>
    <div class="item-2 active"><a href="link3.html"><span class="bold">third item</span></a></div>
  </ul>
</div>
`;
const $ = cheerio.load(html);
const items = $('.list');
// 查找所有 <li> 子元素
items.find('li').each((index, element) => console.log($(element).html()));
// 查找所有子元素
items.children().each((index, element) => console.log($(element).html()));
// 查找所有子元素中带有 class="active" 的元素
items.children('.active').each((index, element) => console.log($(element).html()));
// 查找第二个子元素
items.children().eq(1).each((index, element) => console.log($(element).html()));

// 输出内容
// first item
// <a href="link2.html">second item</a>

// first item
// <a href="link2.html">second item</a>
// <a href="link3.html"><span class="bold">third item</span></a>

// <a href="link3.html"><span class="bold">third item</span></a>

// <a href="link2.html">second item</a>

1.2.3. 查找父元素

js
const cheerio = require('cheerio');
const html = `
<div id="container">
  <ul class="list">
    <li class="item-0">first item</li>
    <li class="item-1"><a href="link2.html">second item</a></li>
    <li class="item-2 active"><a href="link3.html"><span class="bold">third item</span></a></li>
    <li class="item-3 active"><a href="link4.html">fourth item</a></li>
    <li class="item-4"><a href="link5.html">fifth item</a></li>
  </ul>
</div>
`;
const $ = cheerio.load(html);
const items = $('.list');
console.log(items.parent().html()); // 查找父元素

// 输出内容
// <div id="container">
//  <ul class="list">
//    <li class="item-0">first item</li>
//    <li class="item-1"><a href="link2.html">second item</a></li>
//    <li class="item-2 active"><a href="link3.html"><span class="bold">third item</span></a></li>
//    <li class="item-3 active"><a href="link4.html">fourth item</a></li>
//    <li class="item-4"><a href="link5.html">fifth item</a></li>
//  </ul>
// </div>

1.2.4. 查找祖先元素

js
const cheerio = require('cheerio');
const html = `
<div class="wrap">
  <div id="container">
    <ul class="list">
      <li class="item-0">first item</li>
      <li class="item-1"><a href="link2.html">second item</a></li>
      <li class="item-2 active"><a href="link3.html"><span class="bold">third item</span></a></li>
      <li class="item-3 active"><a href="link4.html">fourth item</a></li>
      <li class="item-4"><a href="link5.html">fifth item</a></li>
    </ul>
  </div>
</div>
`;
const $ = cheerio.load(html);
const items = $('.list');
console.log(items.parents().html()); // 查找所有祖先元素
console.log(items.parents('.wrap').html()); // 查找带有 class="wrap" 的祖先元素

// 输出内容
// <ul class="list">
//   <li class="item-0">first item</li>
//   <li class="item-1"><a href="link2.html">second item</a></li>
//   <li class="item-2 active"><a href="link3.html"><span class="bold">third item</span></a></li>
//   <li class="item-3 active"><a href="link4.html">fourth item</a></li>
//   <li class="item-4"><a href="link5.html">fifth item</a></li>
// </ul>

// <div class="wrap">
//   <div id="container">
//     <ul class="list">
//       <li class="item-0">first item</li>
//       <li class="item-1"><a href="link2.html">second item</a></li>
//       <li class="item-2 active"><a href="link3.html"><span class="bold">third item</span></a></li>
//       <li class="item-3 active"><a href="link4.html">fourth item</a></li>
//       <li class="item-4"><a href="link5.html">fifth item</a></li>
//     </ul>
//   </div>
// </div>

1.2.5. 兄弟元素

js
const cheerio = require('cheerio');
const html = `
<div class="wrap">
  <div id="container">
    <ul class="list">
      <li class="item-0">first item</li>
      <li class="item-1"><a href="link2.html">second item</a></li>
      <li class="item-2 active"><a href="link3.html"><span class="bold">third item</span></a></li>
      <li class="item-3 active"><a href="link4.html">fourth item</a></li>
      <li class="item-4"><a href="link5.html">fifth item</a></li>
    </ul>
  </div>
</div>
`;
const $ = cheerio.load(html);
const li = $('.list .item-2.active');
// 查找所有兄弟元素
li.siblings().each((index, element) => console.log($(element).html()));
// 查找带有 class="active" 的兄弟元素
li.siblings('.active').each((index, element) => console.log($(element).html()));

// 输出内容
// first item
// <a href="link2.html">second item</a>
// <a href="link4.html">fourth item</a>
// <a href="link5.html">fifth item</a>

// <a href="link4.html">fourth item</a>

1.2.6. 遍历-单个元素

js
const cheerio = require('cheerio');
const html = `
<div class="wrap">
  <div id="container">
    <ul class="list">
      <li class="item-0">first item</li>
      <li class="item-1"><a href="link2.html">second item</a></li>
      <li class="item-2 active"><a href="link3.html"><span class="bold">third item</span></a></li>
      <li class="item-3 active"><a href="link4.html">fourth item</a></li>
      <li class="item-4"><a href="link5.html">fifth item</a></li>
    </ul>
  </div>
</div>
`;
const $ = cheerio.load(html);
$('.list li').each((index, element) => {
  console.log($(element).html()); // 遍历所有 <li> 元素
});

// 输出内容
// first item
// <a href="link2.html">second item</a>
// <a href="link3.html"><span class="bold">third item</span></a>
// <a href="link4.html">fourth item</a>
// <a href="link5.html">fifth item</a>

1.2.7. 获取信息-获取属性

js
const cheerio = require('cheerio');

const html = `
<div class="wrap">
  <div id="container">
    <ul class="list">
      <li class="item-0">first item</li>
      <li class="item-1"><a href="link2.html">second item</a></li>
      <li class="item-2 active"><a href="link3.html">fourth-item<i>123</i><font>456</font></a></li>
      <li class="item-3 active"><a href="link4.html"><span class="bold">third item</span></a></li>
      <li class="item-4"><a href="link5.html">fifth item</a></li>
    </ul>
  </div>
</div>
`;
const $ = cheerio.load(html);
const a = $('.item-2.active a');
console.log(a.attr('href')); // 获取属性值
console.log(a.text()); // 获取文本内容
console.log(a.contents().filter(function () {
  return this.nodeType === 3; // 筛选文本节点
}).text()); // 获取纯文本内容,排除子元素
console.log(a.clone().find('font').remove().end().text()); // 移除 <font> 元素后获取文本内容
console.log(a.html()); // 获取内部 HTML 内容
console.log(a.prop('outerHTML')); // 获取外部 HTML 内容

// 输出内容
// link3.html
// fourth-item123456
// fourth-item
// fourth-item123
// fourth-item<i>123</i><font>456</font>
// <a href="link3.html">fourth-item<i>123</i><font>456</font></a>

1.3. pd规则

1.3.1. pdfh-获取属性

js
const html = `
<div class="wrap">
  <div id="container">
    <ul class="list">
      <li class="item-0">first item</li>
      <li class="item-1"><a href="link2.html">second item</a></li>
      <li class="item-2 active"><a href="link3.html">fourth-item<i>123</i><font>456</font></a></li>
      <li class="item-3 active"><a href="link4.html"><span class="bold">third item</span></a></li>
      <li class="item-4"><a href="link5.html">fifth item</a></li>
    </ul>
  </div>
</div>
`;
console.log(pdfh(html, '.item-2 a&&href')); // 获取属性值 href
console.log(pdfh(html, '.item-2&&Text')); // 获取文本内容 Text
console.log(pdfh(html, '.item-2--i--font&&Text')); // 获取纯文本内容,排除子元素 --i--font
console.log(pdfh(html, '.item-2--font&&Text')); // 移除 <font> 元素后获取文本内容 --font
console.log(pdfh(html, '.item-2 a')); // 获取内部 HTML 内容
console.log(pdfh(html, '.item-2')); // 获取外部 HTML 内容

// 输出内容
// link3.html
// fourth-item123456
// fourth-item
// fourth-item123
// <a href="link3.html">fourth-item<i>123</i><font>456</font></a>
// <li class="item-2 active"><a href="link3.html">fourth-item<i>123</i><font>456</font></a></li>

1.3.2. pdfa-遍历元素

js
const html = `
<div class="wrap">
  <div id="container">
    <ul class="list">
      <li class="item-0">first item</li>
      <li class="item-1"><a href="link2.html">second item</a></li>
      <li class="item-2 active"><a href="link3.html">fourth-item<i>123</i><font>456</font></a></li>
      <li class="item-3 active"><a href="link4.html"><span class="bold">third item</span></a></li>
      <li class="item-4"><a href="link5.html">fifth item</a></li>
    </ul>
  </div>
</div>
`;
console.log(pdfa(html, '#container ul.list li')); // 获取所有li元素

// 输出内容
[
  "<li class="item-0">first item</li>",
  "<li class="item-1"><a href="link2.html">second item</a></li>",
  "<li class="item-2 active"><a href="link3.html">fourth-item<i>123</i><font>456</font></a></li>",
  "<li class="item-3 active"><a href="link4.html"><span class="bold">third item</span></a></li>",
  "<li class="item-4"><a href="link5.html">fifth item</a></li>"
]

2. 模板规则说明

2.1. 属性说明

js
var rule = {
  title: "", // 规则标题,没有实际作用,但是可以作为cms类名称依据
  编码: "", // 默认utf-8
  搜索编码: "", // 默认utf-8, 优先于全局编码属性, 比如网页源码编码是gbk, 这里指定utf-8搜索独立编码
  host: "", // 网页的域名根, 包含http头如 https://www,baidu.com
  hostJs: 'print(HOST);let html=request(HOST,{headers:{"User-Agent":PC_UA}});let src = jsp.pdfh(html,"ul&&li&&a&&href");print(src);HOST=src.replace("/index.php","")', //网页域名根动态抓取js代码。通过HOST=赋值
  homeUrl: "/latest/", // 网站的首页链接, 可以是完整路径或相对路径, 用于推荐获取 fyclass是分类标签 fypage是页数
  url: "/fyclass/fypage.html[/fyclass/]", // 网站的分类页面链接, 可以是完整路径或相对路径, 用于分类获取 fyclass是分类标签 fypage是页数
  detailUrl: "https://yanetflix.com/voddetail/fyid.html", // 非必填, 二级详情拼接链接
  searchUrl: "", // 搜索链接 可以是完整路径或者相对路径, 用于搜索获取 **代表搜索词 fypage代表页数
  searchable: 0, // 是否启用全局搜索,
  quickSearch: 0, // 是否启用快速搜索,
  filterable: 0, // 是否启用筛选,
  filter: {}, // 筛选条件字典
  // 默认筛选条件字典(不同分类可以指定同样筛选参数的不同默认值)
  filter_def: {
    douyu: {
      area: "一起看",
      other: "..",
    },
    huya: {
      area: "影音馆",
      other: "..",
    },
  },
  // 筛选网站传参,会自动传到分类链接下(本示例中的url参数)-url里参数为fyfilter,可参考蓝莓影视.js
  filter_url: "style={{fl.style}}&zone={{fl.zone}}&year={{fl.year}}&fee={{fl.fee}}&order={{fl.order}}",
  // 注意,由于猫有配置缓存,搜索配置没法热加载,修改了js不需要重启服务器
  // 但是需要tv_box进设置里换源使配置重新装载
  headers: {
    //网站的请求头,完整支持所有的,常带ua和cookies
    "User-Agent": "MOBILE_UA",
    Cookie: "searchneed=ok",
  },
  timeout: 5000, // 网站的全局请求超时, 默认3000毫秒
  class_name: "电影&电视剧&动漫&综艺", // 静态分类名称拼接, &分隔
  class_url: "1&2&3&4", // 静态分类标识拼接, &分隔
  class_parse: "#side-menu:lt(1) li;a&&Text;a&&href;com/(.*?)/", // 动态分类获取 列表;标题;链接;正则提取 不需要正则的时候后面别加分号
  cate_exclude: "", // 除开全局过滤之外还需要过滤哪些标题不视为分类
  tab_exclude: "", // 除开全局动态线路名过滤之外还需要过滤哪些线路名标题不视为线路
  tab_remove: ["tkm3u8"], // 移除某个线路及相关的选集
  tab_order: ["lzm3u8", "wjm3u8", "1080zyk", "zuidam3u8", "snm3u8"], // 线路顺序, 按里面的顺序优先, 没写的依次排后面
  //线路名替换如: lzm3u8替换为量子资源
  tab_rename: {
    lzm3u8: "量子",
    1080zyk: "1080看",
    zuidam3u8: "最大资源",
    kuaikan: "快看",
    bfzym3u8: "暴风",
    ffm3u8: "非凡",
    snm3u8: "索尼",
    tpm3u8: "淘片",
    tkm3u8: "天空",
  },
  play_parse: true, // 服务器解析播放
  // play_json 传数组或者 类 true/false 比如 0,1 如果不传会内部默认处理 不传和传0可能效果不同
  // 效果等同说明: play_json:[{re:'*', json:{jx:0, parse:1}}], 等同于 play_json:0,
  play_json: [
    {
      re: "*",
      json: {
        jx: 1,
        parse: 1,
      },
    },
  ],
  pagecount: { "1": 1, "2": 1, "3": 1, "4": 1, "5": 1, "7": 1 }, // 控制不同分类栏目总页数, 默认999
  lazy: "", // 自定义免嗅
  limit: 6, // 首页推荐显示数量
  double: true, //是否双层列表定位,默认false
  图片来源: "@Referer=http://www.jianpianapp.com@User-Agent=jianpian-version350", // 对图片加请求头, 海阔专用, 普通规则请勿填写此键值
  图片替换: "https://www.keke6.app/=>https://vres.a357899.cn/", // 替换图片链接, 原文本=>目的文本
  // js写法,仅js模式1有效.可以用于代码动态获取全局cookie之类的
  // 可操作变量有 rule_fetch_params,rule,以及基础的网页访问request,post等操作
  预处理: 'rule_fetch_params.headers.Cookie = "xxxx";',
  // 类似海阔一级 列表;标题;图片;描述;链接;详情 其中最后一个参数选填
  // 如果是双层定位的话, 推荐的第2段分号代码也是第2层定位列表代码
  推荐: ".col-sm-6;h3&&Text;img&&data-src;.date&&Text;a&&href",
  一级: ".col-sm-6;h3&&Text;img&&data-src;.date&&Text;a&&href", // 类似海阔一级 列表;标题;图片;描述;链接;详情 其中最后一个参数选填
  二级访问前: 'let jump=request(MY_URL).match(/href="(.*?)"/)[1];log(jump);MY_URL=urljoin2(MY_URL,jump)', // 二级发起前处理逻辑。解决特殊情况一级给出的链接非二级真实源码而是前端重定向链接的源码
  // 二级 *表示规则无二级,直接拿一级的链接进行嗅探
  // 二级 title: 片名;类型
  // 二级 desc: 主要信息;年代;地区;演员;导演
  // 或者 { title:'',img:'',desc:'',content:'',tabs:'',lists:'',tab_text:'body&&Text',list_text:'body&&Text',list_url:'a&&href'} 同海阔dr二级
  二级: "*",
  搜索: "*", // 搜索可以是*,集成一级,或者跟一级一样的写法 列表;标题;图片;描述;链接;详情
  proxy_rule: `js:
    input = [200, 'text;plain', 'hello drpy']
  `, // 本地代理规则,可用于修改m3u8文件文本去广告后返回代理文件地址,也可以代理加密图片
  sniffer: 1, //是否启用辅助嗅探: 1,0
  isVideo: "http((?!http).){26,}\\.(m3u8|mp4|flv|avi|mkv|wmv|mpg|mpeg|mov|ts|3gp|rm|rmvb|asf|m4a|mp3|wma)", // 辅助嗅探规则
  // 辅助嗅探规则js写法
  isVideo: `js:
    if (/m3u8/.test(input)) {
      input = true
    } else {
      input = false
    }
  `,
};

2.2. 模板继承

内置模板含mxpro mxone5 首图 首图2 默认 vfed 海螺3 海螺2 短视 短视2 采集1

2.2.1. 老

js
var rule = Object.assign(muban.mxpro,{
  title:'鸭奈飞',
  host:'https://yanetflix.com',
  url:'/index.php/vod/show/id/fyclass/page/fypage.html',
  class_parse:`.navbar-items li:gt(1):lt(6);a&&Text;a&&href;.*/(.*?).html`,
});

2.2.1. 新

js
var rule = {
  title:'cokemv',
  模板:'mxpro',
  host:'https://cokemv.me',
  class_parse:`.navbar-items li:gt(1):lt(7);a&&Text;a&&href;/(\\d+).html`,
}

2.3. 正则说明

  • 属性class_parse按;分隔后取[3]为分类的正则字符串。这里的正则跟js的/.*/这种写法相比, 由于是字符串, 需要实现字符串标准
    • 如想实现/(\d+)/那么字符串写法为(\\d+)
    • 原理是new RegExp('(\\d+)') = /(\d+)/
  • 属性lazy由于是纯js代码实现, 不存在正则转义问题。
  • 属性对应值如果是字符串, 可以反引号``包起来, 避免内部出现单双引号混用等需转义问题

2.4. js:内置变量

input html VODS VOD TABS LISTS MY_CATE MY_FL getProxyUrl

2.5. 本地代理

proxy_rule参数赋值格式为三元素列表[响应码, 响应头, 响应体]

js
input = [200, "application/vnd.apple.mpegurl", "m3u8分片"]

2.6. rsa加解密

js
if (typeof(rsaX) === 'function') {
  rsaX(mode, pub, encrypt, input, inBase64, key, outBase64)
}

Released under the MIT License.