Sync all projects
This commit is contained in:
@@ -0,0 +1,221 @@
|
||||
/**
|
||||
* SupJav 爬虫
|
||||
* 作者:deepseek
|
||||
* 版本:1.0
|
||||
* 最后更新:2025-12-17
|
||||
* 发布页 https://supjav.com/zh
|
||||
*/
|
||||
|
||||
const baseUrl = 'https://supjav.com/zh';
|
||||
|
||||
/**
|
||||
* 初始化配置
|
||||
*/
|
||||
async function init(cfg) {
|
||||
return {
|
||||
webview: {
|
||||
debug: true, // 是否开启调试模式
|
||||
showWebView: false, // 默认不显示
|
||||
widthPercent: 80, // 窗口宽度百分比
|
||||
heightPercent: 40, // 窗口高度百分比
|
||||
keyword: '', // 页面不存在该关键字时显示webview
|
||||
returnType: 'dom', // 返回DOM对象
|
||||
timeout: 30, // 超时时间(秒)
|
||||
blockImages: false, // 是否禁止加载图片
|
||||
enableJavaScript: true, // 是否启用JS
|
||||
header: {
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36',
|
||||
'Referer': baseUrl + '/',
|
||||
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8'
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 首页分类
|
||||
*/
|
||||
async function homeContent(filter) {
|
||||
return {
|
||||
class: [
|
||||
{ type_id: "popular", type_name: "热门" },
|
||||
{ type_id: "category/censored-jav", type_name: "有码" },
|
||||
{ type_id: "category/uncensored-jav", type_name: "无码" },
|
||||
{ type_id: "category/amateur", type_name: "素人" },
|
||||
{ type_id: "category/chinese-subtitles", type_name: "中文字幕" },
|
||||
{ type_id: "category/english-subtitles", type_name: "英文字幕" },
|
||||
{ type_id: "category/reducing-mosaic", type_name: "无码破解" }
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 首页推荐视频
|
||||
*/
|
||||
async function homeVideoContent() {
|
||||
const document = await Java.wvOpen(baseUrl + '/');
|
||||
const videos = parseVideoList(document);
|
||||
return { list: videos };
|
||||
}
|
||||
|
||||
/**
|
||||
* 分类内容
|
||||
*/
|
||||
async function categoryContent(tid, pg, filter, extend) {
|
||||
const pgSuffix = (pg === 1 ? '' : `/page/${pg}`);
|
||||
const document = await Java.wvOpen(`${baseUrl}/${tid}${pgSuffix}`);
|
||||
const videos = parseVideoList(document);
|
||||
return { code: 1, msg: "数据列表", list: videos, page: pg, pagecount: 10000, limit: 24, total: 240000 };
|
||||
}
|
||||
|
||||
/**
|
||||
* 详情页
|
||||
*/
|
||||
async function detailContent(ids) {
|
||||
const document = await Java.wvOpen(ids[0]);
|
||||
const list = parseDetailPage(document, ids[0]);
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 搜索
|
||||
*/
|
||||
async function searchContent(key, quick, pg) {
|
||||
// 暂未实现搜索逻辑
|
||||
return { list: [] };
|
||||
}
|
||||
|
||||
/**
|
||||
* 播放器
|
||||
*/
|
||||
async function playerContent(flag, id, vipFlags) {
|
||||
const ids = id.split('---');
|
||||
Java.showWebView();
|
||||
|
||||
return {
|
||||
type: 'sniff', // 必填,标识嗅探模式
|
||||
url: ids[1], // 必填,要加载的播放页面 URL
|
||||
keyword: '.m3u8|.mp4', // 可选,嗅探关键字,多个用 | 分隔
|
||||
script: `
|
||||
(function(){
|
||||
setTimeout(() => {
|
||||
document.querySelectorAll('.btn-server').forEach(btn => {
|
||||
if(btn.textContent.trim() === '${ids[0]}') {
|
||||
btn.click();
|
||||
console.log('已点击服务器: ${ids[0]}');
|
||||
}
|
||||
});
|
||||
setTimeout(() => {
|
||||
document.querySelector("#a > div.spin").click();
|
||||
console.log('已点击播放按钮');
|
||||
}, 3000);
|
||||
}, 500);
|
||||
})();
|
||||
`,
|
||||
timeout: 15 // 可选,嗅探超时时间(秒),默认 15
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* action
|
||||
*/
|
||||
async function action(actionStr) {
|
||||
try {
|
||||
const params = JSON.parse(actionStr);
|
||||
console.log("action params:", params);
|
||||
} catch (e) {
|
||||
console.log("action is not JSON, treat as string");
|
||||
}
|
||||
return { list: [] };
|
||||
}
|
||||
|
||||
|
||||
/* ---------------- 工具函数 ---------------- */
|
||||
|
||||
/**
|
||||
* 提取视频列表
|
||||
*/
|
||||
function parseVideoList(document) {
|
||||
const posts = document.querySelectorAll('.post');
|
||||
return Array.from(posts).map(post => {
|
||||
const titleLink = post.querySelector('h3 a');
|
||||
const vod_name = titleLink?.getAttribute('title') || titleLink?.textContent || '';
|
||||
const vod_id = titleLink?.getAttribute('href') || '';
|
||||
const img = post.querySelector('img');
|
||||
const vod_pic = img?.getAttribute('data-original') || img?.getAttribute('src') || '';
|
||||
const meta = post.querySelector('.meta');
|
||||
let vod_remarks = '';
|
||||
if (meta) {
|
||||
const metaText = meta.textContent || '';
|
||||
const viewsMatch = metaText.match(/(\d+)\s*Views/);
|
||||
if (viewsMatch) {
|
||||
vod_remarks = `${viewsMatch[1]}次浏览`;
|
||||
} else {
|
||||
const chineseMatch = metaText.match(/(\d+)\s*次浏览/);
|
||||
vod_remarks = chineseMatch ? `${chineseMatch[1]}次浏览` : '';
|
||||
}
|
||||
}
|
||||
return { vod_id, vod_name, vod_pic, vod_remarks };
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析详情页
|
||||
*/
|
||||
function parseDetailPage(doc, id) {
|
||||
const title = doc.querySelector('.archive-title h1')?.textContent?.trim() || '';
|
||||
const vod_pic = doc.querySelector('.post-meta .img')?.src || '';
|
||||
const viewsText = doc.querySelector('.dz_view .views')?.textContent || '';
|
||||
const vod_remarks = viewsText.replace(/[^0-9]/g, '') || '0';
|
||||
const tagElements = doc.querySelectorAll('.tags a');
|
||||
const vod_actor = Array.from(tagElements).map(tag => tag.textContent.trim()).join(',');
|
||||
let vod_director = '';
|
||||
const catElements = doc.querySelectorAll('.cats p, .cats span, .cats a');
|
||||
for (let el of catElements) {
|
||||
if (el.textContent.includes('Maker')) {
|
||||
if (el.nextElementSibling?.tagName === 'A') {
|
||||
vod_director = el.nextElementSibling.textContent.trim();
|
||||
break;
|
||||
}
|
||||
const linkInParent = el.querySelector('a');
|
||||
if (linkInParent) {
|
||||
vod_director = linkInParent.textContent.trim();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
const vod_content = doc.querySelector('.post-content')?.textContent?.trim() || '';
|
||||
const serverButtons = doc.querySelectorAll('.btnst .btn-server');
|
||||
const playItems = Array.from(serverButtons).map(btn => {
|
||||
const serverName = btn.textContent.trim();
|
||||
const dataLink = btn.getAttribute('data-link');
|
||||
return serverName && dataLink ? `${serverName}$${serverName}---${id}` : '';
|
||||
}).filter(Boolean);
|
||||
const vod_play_url = playItems.join('#') || '';
|
||||
const vod = {
|
||||
code: 1,
|
||||
msg: "数据列表",
|
||||
page: 1,
|
||||
pagecount: 1,
|
||||
limit: 1,
|
||||
total: 1,
|
||||
list: [{
|
||||
vod_id: id || 'unknown_id',
|
||||
vod_name: title,
|
||||
vod_pic: vod_pic,
|
||||
vod_remarks: vod_remarks,
|
||||
vod_director: vod_director,
|
||||
vod_actor: vod_actor,
|
||||
vod_content: vod_content,
|
||||
vod_play_from: 'SERVER',
|
||||
vod_play_url: vod_play_url
|
||||
}]
|
||||
};
|
||||
// console.log(vod);
|
||||
return vod;
|
||||
}
|
||||
|
||||
|
||||
/* ---------------- 导出对象 ---------------- */
|
||||
const spider = { init, homeContent, homeVideoContent, categoryContent, detailContent, searchContent, playerContent, action };
|
||||
spider;
|
||||
Reference in New Issue
Block a user