Fix: Bypassing Cloudflare's TLS fingerprint detection for Node.js using curl.
This commit is contained in:
1 parent
df68291483
commit
51c9ccceef
2 files changed
+23
-62
No files matched your search
+22
-61
@@ -1,61 +1,44 @@
|
||||
import axios from 'axios';
|
||||
import { execSync } from 'child_process';
|
||||
import * as cheerio from 'cheerio';
|
||||
import { getCache, setCache } from './cache.js';
|
||||
|
||||
const BASE_URL = 'https://javdb.com';
|
||||
|
||||
// 把 _jdb_session 的值解码
|
||||
const SESSION = decodeURIComponent('wJkH2678EN3cZzzL2Pqbyr158quff0CaGzuh5hRxUXXADcKOQm1zKdOnlwow3wDfL5AX2NeKne52BgUZT6JpBGp5prKgUmKyBReopEABv30rItmWnxowjJ04Mki%2BO0jQ3OO%2F4F2BYE7TTZ8GlgpA3kuesTAsX8bAcL0HqWF4LDRdMeo9JYqzDn%2FoPAUFxnmwXBieXtMXqCP8JnudI2vQ44jtIhFRvSrzf832gRMi7STwMG7K8O9%2BH3AoJfMKbuBomnLMFuBNBbPbB3SShbi3SBja8bX8nudBILUX0ZiJtD%2FEOl%2BN3r6dVPw5--do%2Bi7mvLi5xyZ0HZ--gZT%2Fl7%2BX9Vr3GjRNK7FXOw%3D%3D');
|
||||
|
||||
const HEADERS = {
|
||||
'User-Agent':
|
||||
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) ' +
|
||||
'AppleWebKit/537.36 (KHTML, like Gecko) ' +
|
||||
'Chrome/123.0.0.0 Safari/537.36',
|
||||
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',
|
||||
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
|
||||
'Accept-Encoding': 'gzip, deflate, br',
|
||||
'Connection': 'keep-alive',
|
||||
'Upgrade-Insecure-Requests': '1',
|
||||
'Sec-Fetch-Dest': 'document',
|
||||
'Sec-Fetch-Mode': 'navigate',
|
||||
'Sec-Fetch-Site': 'none',
|
||||
'Sec-Fetch-User': '?1',
|
||||
'Cache-Control': 'max-age=0',
|
||||
Cookie: `list_mode=h; theme=auto; locale=zh; over18=1; _jdb_session=${SESSION}`, // over18=1 跳过成人内容确认页
|
||||
};
|
||||
const COOKIE = `list_mode=h; theme=auto; locale=zh; over18=1; _jdb_session=${SESSION}`;
|
||||
const BASE_URL = 'https://javdb.com';
|
||||
|
||||
async function fetchHtml(url) {
|
||||
const res = await axios.get(url, {
|
||||
headers: HEADERS,
|
||||
timeout: 15000,
|
||||
maxRedirects: 5,
|
||||
decompress: true,
|
||||
});
|
||||
return res.data;
|
||||
function fetchHtml(url) {
|
||||
const result = execSync(
|
||||
`curl -sL "${url}" \
|
||||
-H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36" \
|
||||
-H "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8" \
|
||||
-H "Accept-Language: zh-CN,zh;q=0.9,en;q=0.8" \
|
||||
-H "Cookie: ${COOKIE}"`,
|
||||
{ timeout: 15000, maxBuffer: 1024 * 1024 * 10 }
|
||||
);
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
export async function search(id) {
|
||||
// 第一步:先查缓存
|
||||
const cached = getCache(id);
|
||||
if (cached) return cached;
|
||||
|
||||
// 缓存没有,走网络请求,搜索番号,拿到详情页链接
|
||||
const searchUrl = `${BASE_URL}/search?q=${encodeURIComponent(id)}&f=all`;
|
||||
const searchHtml = await fetchHtml(searchUrl);
|
||||
const searchHtml = fetchHtml(searchUrl);
|
||||
const $ = cheerio.load(searchHtml);
|
||||
|
||||
// 找第一个匹配的结果卡片
|
||||
const firstResult = $('.movie-list .item a').first();
|
||||
if (!firstResult.length) return null;
|
||||
|
||||
const detailPath = firstResult.attr('href');
|
||||
if (!detailPath) return null;
|
||||
|
||||
// 第二步:抓取详情页
|
||||
const detailUrl = `${BASE_URL}${detailPath}`;
|
||||
const detailHtml = await fetchHtml(detailUrl);
|
||||
return parseDetail(detailHtml, id);
|
||||
const detailHtml = fetchHtml(detailUrl);
|
||||
const result = parseDetail(detailHtml, id);
|
||||
|
||||
setCache(id, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
function parseDetail(html, queryId) {
|
||||
@@ -75,20 +58,13 @@ function parseDetail(html, queryId) {
|
||||
tags: [],
|
||||
coverUrl: '',
|
||||
score: '',
|
||||
detailUrl: '',
|
||||
};
|
||||
|
||||
// 标题
|
||||
result.title = $('h2.title strong.current-title').text().trim() ||
|
||||
$('h2.title').text().trim();
|
||||
|
||||
// 封面图
|
||||
result.coverUrl = $('.video-cover img').attr('src') || '';
|
||||
|
||||
// 评分
|
||||
result.score = $('.score .value').first().text().trim();
|
||||
|
||||
// 遍历 panel info 的每一行
|
||||
$('.movie-panel-info .panel-block').each((_, el) => {
|
||||
const label = $(el).find('strong').text().trim().replace(':', '');
|
||||
const valueEl = $(el).find('.value');
|
||||
@@ -97,53 +73,38 @@ function parseDetail(html, queryId) {
|
||||
case /日期|發行|发行/.test(label):
|
||||
result.releaseDate = valueEl.text().trim();
|
||||
break;
|
||||
|
||||
case /時長|时长|分鐘|分钟/.test(label):
|
||||
result.duration = valueEl.text().trim();
|
||||
break;
|
||||
|
||||
case /導演|导演/.test(label):
|
||||
result.director = valueEl.text().trim();
|
||||
break;
|
||||
|
||||
case /片商|制作|製作/.test(label):
|
||||
result.studio = valueEl.text().trim();
|
||||
break;
|
||||
|
||||
case /發行商|发行商/.test(label):
|
||||
result.label = valueEl.text().trim();
|
||||
break;
|
||||
|
||||
case /系列/.test(label):
|
||||
result.series = valueEl.text().trim();
|
||||
break;
|
||||
|
||||
case /類別|类别|genre/i.test(label):
|
||||
valueEl.find('a').each((_, a) => {
|
||||
result.tags.push($(a).text().trim());
|
||||
});
|
||||
valueEl.find('a').each((_, a) => result.tags.push($(a).text().trim()));
|
||||
break;
|
||||
|
||||
case /演員|演员|女優|女优/.test(label): {
|
||||
case /演員|演员|女優|女优/.test(label):
|
||||
valueEl.find('a').each((_, a) => {
|
||||
const name = $(a).text().trim();
|
||||
if (name) result.actresses.push(name);
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
case /男優|男优/.test(label): {
|
||||
case /男優|男优/.test(label):
|
||||
valueEl.find('a').each((_, a) => {
|
||||
const name = $(a).text().trim();
|
||||
if (name) result.actors.push(name);
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 写入缓存
|
||||
setCache(id, result);
|
||||
|
||||
return result;
|
||||
}
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "javinfo",
|
||||
"version": "1.0.3",
|
||||
"version": "1.0.4",
|
||||
"description": "AV番号命令行查询工具",
|
||||
"main": "./index.js",
|
||||
"type": "module",
|
||||
|
||||
Reference in new issue
Block a user