window.chrome = { runtime: {}, loadTimes: function() {}, csi: function() {}, app: {} }; window.chrome 对象概述
在真实的 Chrome 浏览器中,window.chrome 是一个全局对象,包含了 Chrome 浏览器特有的 API 和功能。自动化工具(如 Playwright)启动的浏览器可能缺少这个对象,这会被反爬虫系统识别。
各属性详解
1. runtime: {}
runtime: {} 真实作用:
- 在真实 Chrome 中,
chrome.runtime提供扩展程序运行时的 API - 包含消息传递、存储管理、生命周期管理等功能
真实示例:
// 真实 Chrome 中的 runtime 对象包含: chrome.runtime = { onMessage: {...}, sendMessage: function() {...}, getManifest: function() {...}, getURL: function() {...}, id: "extension-id" } 这里为什么是空对象:
- 简单伪装,让检测代码认为存在 chrome.runtime
- 避免实现复杂的 API,因为大多数检测只是检查对象是否存在
2. loadTimes: function() {}
loadTimes: function() {} 真实作用:
-
chrome.loadTimes()是 Chrome 的性能监控 API - 返回页面加载的详细时间信息
真实返回数据:
chrome.loadTimes() // 真实返回: { requestTime: 1642680000.123, startLoadTime: 1642680000.125, commitLoadTime: 1642680000.150, finishDocumentLoadTime: 1642680000.200, finishLoadTime: 1642680000.250, firstPaintTime: 1642680000.180, firstPaintAfterLoadTime: 0, navigationType: "navigate" } 为什么是空函数:
- 防止调用时报错(如果不存在会抛出异常)
- 一些检测脚本只检查函数是否存在,不关心返回值
3. csi: function() {}
csi: function() {} 真实作用:
- CSI = Chrome Speed Index
- 提供客户端性能指标和统计信息
- 用于 Chrome 内部的性能分析
真实返回数据:
chrome.csi() // 真实返回: { pageT: 1234.56, // 页面加载时间 startE: 1642680000123, // 开始时间戳 onloadT: 1234.56, // onload 事件时间 tran: 15 // 传输次数 } 4. app: {}
app: {} 真实作用:
- 在 Chrome 应用环境中提供应用相关的 API
- 主要用于 Chrome 打包应用(Chrome Apps,现已弃用)
真实内容:
// 在 Chrome 应用中包含: chrome.app = { runtime: { onLaunched: {...}, onRestarted: {...} }, window: { create: function() {...} } } 检测对抗原理
反爬虫检测可能的代码:
// 检测是否为真实 Chrome if (typeof window.chrome === 'undefined') { console.log('可能是自动化浏览器'); } if (typeof chrome.loadTimes !== 'function') { console.log('不是真实 Chrome'); } // 更严格的检测 try { const loadTimes = chrome.loadTimes(); if (!loadTimes || typeof loadTimes.requestTime === 'undefined') { console.log('chrome.loadTimes 返回异常'); } } catch (e) { console.log('chrome.loadTimes 调用失败'); } 我们的对策:
window.chrome = { runtime: {}, // 通过存在性检测 loadTimes: function() {}, // 通过函数类型检测 csi: function() {}, // 通过函数类型检测 app: {} // 通过存在性检测 }; 更完善的实现
如果要更真实地伪装,可以这样写:
window.chrome = { runtime: { onConnect: {}, onMessage: {}, id: undefined }, loadTimes: function() { return { requestTime: Date.now() / 1000 - Math.random(), startLoadTime: Date.now() / 1000 - Math.random(), commitLoadTime: Date.now() / 1000 - Math.random(), finishDocumentLoadTime: Date.now() / 1000 - Math.random(), finishLoadTime: Date.now() / 1000, firstPaintTime: Date.now() / 1000 - Math.random(), firstPaintAfterLoadTime: 0, navigationType: "navigate" }; }, csi: function() { return { pageT: Math.random() * 1000, startE: Date.now() - Math.random() * 1000, onloadT: Math.random() * 1000, tran: Math.floor(Math.random() * 20) }; }, app: { isInstalled: false } }; 不过对于大多数反检测场景,简单的空对象和空函数就足够了。
完整使用样例
async def run_local(self, proxy=None): async with async_playwright() as p: # 更完善的启动参数 launch_data = { "headless": False, "proxy": proxy, "args": [ '--disable-blink-features=AutomationControlled', '--disable-dev-shm-usage', '--no-first-run', '--no-default-browser-check', '--disable-infobars', '--disable-extensions', '--disable-features=VizDisplayCompositor' ] } browser = await p.chromium.launch(**launch_data) # 创建上下文时添加更多参数 context = await browser.new_context( user_agent=user_agent, viewport={'width': 1920, 'height': 1080}, screen={'width': 1920, 'height': 1080}, device_scale_factor=1, is_mobile=False, has_touch=False, locale='en-US', timezone_id='America/New_York', permissions=['notifications'] ) timeout = 30 context.set_default_timeout(timeout * 1000) page = await context.new_page() await page.add_init_script(""" // 模拟真实的 chrome 对象 window.chrome = { runtime: {}, loadTimes: function() {}, csi: function() {}, app: {} }; """) # 监听请求流 page.on('response', self.on_response) url = 'https://gmgn.ai/meme/LXtw30LM?chain=sol' # 先访问主页,模拟真实用户行为 await page.goto('https://gmgn.ai/') await asyncio.sleep(2) # 再访问目标地址 await page.goto(url) await asyncio.sleep(3) # 过反爬,如果不加就是被block的状态 await page.reload() await asyncio.sleep(10) await self.detect(page) # 1小时后关闭浏览器 await page.evaluate("setTimeout(() => window.x = 5, 60 * 60 * 1000)") await page.wait_for_function("() => window.x > 0", timeout=0)
Top comments (0)