Files
白夜 fb14cf7916 refactor: 将文件从子目录提升到仓库根目录
所有文件从 hello_js_reverse_skill/ 子目录移至仓库根目录,
使项目结构更清晰,便于作为 Skill 直接引用。

Made-with: Cursor
2026-03-18 22:55:27 +08:00

171 lines
5.2 KiB
JavaScript

/**
* 主脚本模板 - 浏览器自动化
*
* 适用场景:TLS 指纹检测、复杂环境依赖、window 蜜罐
* 使用 Playwright 控制真实 Chrome 浏览器执行请求
*
* TODO: 根据逆向分析结果修改配置和逻辑
*/
const { chromium } = require('playwright-core');
// ============ 配置区域 ============
const CONFIG = {
name: '示例项目 - 浏览器自动化',
description: '采集全部5页数据',
// 目标URL
pageURL: 'https://target.com/page',
// Chrome 路径(macOS 默认路径)
chromePath: '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
// Linux: '/usr/bin/google-chrome'
// Windows: 'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe'
// 是否显示浏览器
headless: false,
totalPages: 5,
delay: 2000,
// 登录 Cookie
cookies: [
// { name: 'sessionid', value: 'xxx', domain: 'target.com', path: '/' },
],
// 注入脚本(可选)
injectScript: null,
};
// ============ 主逻辑 ============
async function main() {
console.log(`[*] 项目:${CONFIG.name}`);
console.log(`[*] 目标:${CONFIG.description}`);
console.log('');
// 启动浏览器
console.log('[*] 启动浏览器...');
const browser = await chromium.launch({
executablePath: CONFIG.chromePath,
headless: CONFIG.headless,
args: [
'--disable-blink-features=AutomationControlled',
'--no-sandbox',
],
});
const context = await browser.newContext({
userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
viewport: { width: 1920, height: 1080 },
locale: 'zh-CN',
});
// 设置 Cookie
if (CONFIG.cookies.length > 0) {
await context.addCookies(CONFIG.cookies);
}
// 隐藏自动化特征
await context.addInitScript(() => {
Object.defineProperty(navigator, 'webdriver', { get: () => undefined });
window.chrome = { runtime: {} };
});
// 注入自定义脚本
if (CONFIG.injectScript) {
await context.addInitScript(CONFIG.injectScript);
}
const page = await context.newPage();
try {
// 导航到目标页面
console.log('[*] 打开目标页面...');
await page.goto(CONFIG.pageURL, { waitUntil: 'networkidle', timeout: 30000 });
console.log('[+] 页面加载完成');
// 采集数据
const allData = [];
for (let pageNum = 1; pageNum <= CONFIG.totalPages; pageNum++) {
// TODO: 根据实际页面结构修改数据提取逻辑
const pageData = await extractPageData(page, pageNum);
allData.push(...pageData);
console.log(`[+] 正在采集第 ${pageNum}/${CONFIG.totalPages} 页... ✓ 获取 ${pageData.length} 条数据`);
if (pageNum < CONFIG.totalPages) {
// 翻页
await goToNextPage(page, pageNum + 1);
await sleep(CONFIG.delay);
}
}
console.log(`\n[+] 采集完成,共 ${allData.length} 条数据`);
// 计算结果
const result = allData.reduce((sum, val) => sum + val, 0);
console.log('\n' + '='.repeat(30) + ' 计算结果 ' + '='.repeat(30));
console.log(`答案:${result}`);
console.log('='.repeat(70));
} catch (error) {
console.error('[!] 错误:', error.message);
await page.screenshot({ path: 'error_screenshot.png' });
console.log('[*] 已保存错误截图: error_screenshot.png');
} finally {
await browser.close();
}
}
/**
* 从页面提取数据
* TODO: 根据实际页面结构修改
*/
async function extractPageData(page, pageNum) {
// 方式1:从页面DOM提取
const data = await page.evaluate(() => {
const rows = document.querySelectorAll('.data-row');
return Array.from(rows).map(row => {
const value = row.querySelector('.value')?.textContent?.trim();
return parseFloat(value) || 0;
});
});
return data;
// 方式2:拦截网络响应
// const responsePromise = page.waitForResponse(resp => resp.url().includes('/api/data'));
// // 触发数据加载...
// const response = await responsePromise;
// const json = await response.json();
// return json.data;
}
/**
* 翻到下一页
* TODO: 根据实际页面结构修改翻页逻辑
*/
async function goToNextPage(page, targetPage) {
// 方式1:点击翻页按钮
await page.click(`.pagination a:has-text("${targetPage}")`);
await page.waitForLoadState('networkidle');
// 方式2:等待特定元素出现
// await page.waitForSelector('.data-loaded');
// 方式3:直接导航到带页码的URL
// await page.goto(`${CONFIG.pageURL}?page=${targetPage}`, { waitUntil: 'networkidle' });
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
main().catch(error => {
console.error('\n[!] 运行错误:', error.message);
process.exit(1);
});