plugin/yunsou/html结构分析.md
yunsou.xyzhttps://yunsou.xyz/s/{关键词}.html云搜影视提供两种搜索源:
本插件实现本地搜功能,因为:
搜索结果直接内嵌在HTML的JavaScript代码中,以JSON格式存储:
<script type="text/javascript" charset="utf-8">
function linkBtn(element) {
const index = element.getAttribute('data-index');
var jsonData = '[{"id":51199,"source_category_id":3,"title":"凡人修仙传 真人版 [2025][奇幻 古装 大陆][杨洋 金晨]","is_type":4,"code":null,"url":"https://pan.xunlei.com/s/VOW9WQT6nyFBDjHwYjjGj13YA1?pwd=v2m9","is_time":0,"name":"凡人修仙传 真人版 [2025][奇幻 古装 大陆][杨洋 金晨]","times":"2025-07-27","category":{"source_category_id":3,"name":"电视剧"}},...]';
// ...
}
</script>
每个搜索结果项的JSON结构如下:
{
"id": 51199,
"source_category_id": 3,
"title": "凡人修仙传 真人版 [2025][奇幻 古装 大陆][杨洋 金晨]",
"is_type": 4,
"code": null,
"url": "https://pan.xunlei.com/s/VOW9WQT6nyFBDjHwYjjGj13YA1?pwd=v2m9",
"is_time": 0,
"name": "凡人修仙传 真人版 [2025][奇幻 古装 大陆][杨洋 金晨]",
"times": "2025-07-27",
"category": {
"source_category_id": 3,
"name": "电视剧"
}
}
| 字段 | 类型 | 说明 | 示例 |
|---|---|---|---|
id | number | 资源唯一ID | 51199 |
title | string | 资源标题 | "凡人修仙传 真人版 [2025][奇幻 古装 大陆][杨洋 金晨]" |
is_type | number | 网盘类型标识 | 0=夸克, 1=阿里, 2=百度, 3=UC, 4=迅雷 |
code | string|null | 提取码(可能为null) | "v2m9" 或 null |
url | string | 网盘链接 | "https://pan.xunlei.com/s/..." |
times | string | 发布时间 | "2025-07-27" |
category.name | string | 资源分类 | "电视剧", "动漫", "电影"等 |
0 -> 夸克网盘 (quark)
1 -> 阿里云盘 (aliyun)
2 -> 百度网盘 (baidu)
3 -> UC网盘 (uc)
4 -> 迅雷网盘 (xunlei)
虽然数据在JS中,HTML中也有对应的展示结构:
<div class="list">
<div class="item">
<a href="javascript:;" onclick="linkBtn(this)" data-index="0" class="title">
凡人修仙传 真人版 [2025][奇幻 古装 大陆][杨洋 金晨]
</a>
<div class="type cate">分类:电视剧</div>
<div class="type time">2025-07-27</div>
<div class="type">
<span>来源:迅雷网盘</span>
</div>
<div class="btns">
<div class="btn">复制分享</div>
<a href="/d/51199.html" class="btn">查看详情</a>
<a href="javascript:;" onclick="linkBtn(this)" data-index="0" class="btn">立即访问</a>
</div>
</div>
</div>
1. 发送GET请求到搜索URL
├─ URL: https://yunsou.xyz/s/{URL编码的关键词}.html
└─ 设置完整的浏览器请求头
2. 解析HTML响应
├─ 查找包含 "var jsonData = " 的script标签
└─ 提取JSON字符串
3. 清理并解析JSON
├─ 移除控制字符和转义
├─ 解析为结构化数据
└─ 处理异常数据
4. 转换为SearchResult格式
├─ 生成UniqueID: "yunsou-{id}"
├─ 设置标题、内容、时间
├─ 根据is_type确定网盘类型
├─ 构建Link对象(包含URL和提取码)
└─ 添加分类标签
5. 关键词过滤
└─ 使用FilterResultsByKeyword过滤结果
// 提取JSON数据的正则表达式
var jsonData = '[...]';
匹配模式:
var jsonData = ' 开头提取码可能存在于两个位置:
?pwd=xxxx 格式处理逻辑:
password := ""
if code != nil && *code != "" {
password = *code
} else if strings.Contains(url, "?pwd=") {
// 从URL中提取pwd参数
password = extractPwdFromURL(url)
}
func convertNetDiskType(isType int) string {
switch isType {
case 0:
return "quark" // 夸克网盘
case 1:
return "aliyun" // 阿里云盘
case 2:
return "baidu" // 百度网盘
case 3:
return "uc" // UC网盘
case 4:
return "xunlei" // 迅雷网盘
default:
return "others"
}
}
时间格式为 "2025-07-27",需要解析为 time.Time:
// 解析时间字符串
const timeLayout = "2006-01-02"
parsedTime, err := time.Parse(timeLayout, times)
if err != nil {
parsedTime = time.Now() // 解析失败使用当前时间
}
内容字段组合多个信息:
contentParts := []string{}
if category != "" {
contentParts = append(contentParts, "【"+category+"】")
}
// 可以添加更多描述信息
content := strings.Join(contentParts, " ")
必须设置完整的浏览器请求头:
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36")
req.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8")
req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8")
req.Header.Set("Connection", "keep-alive")
req.Header.Set("Referer", "https://yunsou.xyz/")
需要处理的特殊情况:
\"\x00-\x1F, \x7F)清理代码:
// 移除控制字符
jsonStr = regexp.MustCompile(`[\x00-\x1F\x7F]`).ReplaceAllString(jsonStr, "")
// 处理转义
jsonStr = strings.ReplaceAll(jsonStr, `\"`, `"`)
jsonStr = strings.ReplaceAll(jsonStr, `\/`, `/`)
需要处理的错误情况:
在添加到结果前验证:
import (
"regexp"
"strings"
)
// 提取JSON数据
func extractJSONData(htmlContent string) (string, error) {
// 查找 var jsonData = '...'
pattern := regexp.MustCompile(`var jsonData = '(.+?)';`)
matches := pattern.FindStringSubmatch(htmlContent)
if len(matches) < 2 {
return "", fmt.Errorf("未找到JSON数据")
}
jsonStr := matches[1]
// 清理控制字符
jsonStr = regexp.MustCompile(`[\x00-\x1F\x7F]`).ReplaceAllString(jsonStr, "")
// 处理转义字符
jsonStr = strings.ReplaceAll(jsonStr, `\\/`, `/`)
jsonStr = strings.ReplaceAll(jsonStr, `\\"`, `"`)
return jsonStr, nil
}
// 构建Link对象
func buildLink(item YunsouItem) model.Link {
link := model.Link{
Type: convertNetDiskType(item.IsType),
URL: item.URL,
}
// 处理提取码
if item.Code != nil && *item.Code != "" {
link.Password = *item.Code
} else if strings.Contains(item.URL, "?pwd=") {
link.Password = extractPwdFromURL(item.URL)
}
return link
}
根据云搜影视的特点,建议设置优先级为 2:
https://yunsou.xyz/s/凡人修仙传.htmlhttps://yunsou.xyz/d/51199.html (可选,插件不需要访问)