⚔️ 背景:从付费 API 到"自力更生"
在上一篇中,我们使用 SerpApi 成功验证了"通过图片搜索一致性判断图片质量"的算法。但在实际工程化落地时,我们面临了两个严峻挑战:
-
成本爆炸:电商场景下,一个 SKU 对应多张图片,每天数万次的调用量,API 费用是一笔巨款。
-
数据缺失 :Google Lens 页面中经常包含 AI 生成的详细描述(Knowledge Graph),这对于 SEO 至关重要,但标准 API 往往无法完整提取这部分动态渲染的内容。
为了降本增效,我们决定迁移到 Playwright。这是一个现代化的浏览器自动化工具,比 Selenium 更快、更稳。但面对 Google Lens 这种级别的对手,简单的脚本会被瞬间识破。
本篇将详细拆解我们在 FindQC 项目中构建的 四层反爬虫防御体系。
🛡️ 第一层防御:基础特征抹除 (Stealth Mode)
Google 检测自动化的第一步是检查浏览器环境中的 navigator.webdriver 属性。普通的 Playwright 启动后,这个属性为 true,相当于直接告诉 Google:"我是机器人"。
我们引入 playwright_stealth 库来覆盖这些显眼的特征。
code Python
downloadcontent_copy
expand_less
from playwright.sync_api import sync_playwright
from playwright_stealth import stealth
def init_browser(page):
# 应用 Stealth 模式,隐藏 navigator.webdriver 及其他自动化特征
stealth.Stealth().apply_stealth_sync(page)
# 额外移除 Chrome 自动化控制提示栏
page.evaluate("() => {Object.defineProperty(navigator, 'webdriver', {get: () => undefined})}")
🎭 第二层防御:指纹伪造与环境持久化
仅仅隐藏 webdriver 是不够的。Google 还会检查 User-Agent、Header 顺序、甚至浏览器缓存。
1. 真实 User-Agent 筛选
很多教程推荐使用 fake-useragent 库,但在 Google Lens 场景下有个大坑:它经常随机出移动端 (Mobile) 的 UA。这会导致 Google Lens 返回移动版页面,DOM 结构完全不同,甚至强制跳转 App 下载页。
我们需要严格筛选 桌面端 (Desktop) UA:
code Python
downloadcontent_copy
expand_less
def get_desktop_user_agent():
# 模拟筛选逻辑,排除 Android/iPhone 关键词
# 实际项目中维护了一个经过验证的 Chrome/Mac/Win 高频 UA 池
return "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"
def generate_headers():
return {
'Sec-CH-UA': '"Google Chrome";v="120", "Not:A-Brand";v="8"',
'Sec-CH-UA-Mobile': '?0', # 关键:明确告诉服务器我是桌面端
'Sec-CH-UA-Platform': '"macOS"',
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8'
}
2. 持久化上下文 (Persistent Context)
每次启动浏览器都创建一个全新的无痕模式(Incognito),在 Google 看来是非常可疑的行为(没有 Cookie,没有历史记录)。
我们改用 launch_persistent_context 加载真实的 Chrome 配置文件,让爬虫看起来像一个"有历史"的老用户。
code Python
downloadcontent_copy
expand_less
browser = playwright.chromium.launch_persistent_context(
user_data_dir="./chrome_user_data", # 指向本地真实的 Chrome 配置目录
channel="chrome", # 使用本机安装的 Chrome 而非 Playwright 内置的 Chromium
headless=False, # 开发阶段建议开启有头模式,便于调试
args=["--disable-blink-features=AutomationControlled"]
)
🖱️ 第三层防御:人类行为模拟 (Humanizing)
Google 会记录鼠标轨迹和点击行为。机器人的操作通常是瞬移(坐标 A 直接跳到坐标 B)且时间间隔固定。
我们实现了一个模拟器,引入了 贝塞尔曲线 鼠标移动和 随机抖动。
code Python
downloadcontent_copy
expand_less
import random
import time
import math
def simulate_human_behavior(page):
# 1. 随机延迟
time.sleep(random.uniform(1.5, 4.0))
# 2. 模拟鼠标随机移动(贝塞尔曲线逻辑略)
# 这里的关键是不要走直线,且移动过程中要有速度变化
page.mouse.move(random.randint(100, 800), random.randint(100, 600), steps=random.randint(10, 50))
# 3. 模拟"浏览"动作:上下滚动
page.mouse.wheel(0, random.randint(300, 800))
time.sleep(random.uniform(0.5, 1.5))
page.mouse.wheel(0, -random.randint(100, 300))
🚨 第四层防御:异常处理与重定向陷阱
即便做好了上述所有准备,Google 依然可能通过 IP 信誉度或其他深层特征识别出我们。最典型的表现就是被重定向到 /sorry/index 页面(验证码页面)。
我们需要构建一套熔断与重试机制:
code Python
downloadcontent_copy
expand_less
def process_image(page, image_url):
try:
page.goto("https://lens.google.com/upload", wait_until="domcontentloaded")
# 检查是否被重定向到验证页面
if "/sorry/index" in page.url:
print("⚠️ 触发 Google 验证反爬,进入冷却模式...")
time.sleep(300) # 暂停 5 分钟
return None
# 正常业务逻辑:输入图片 URL,点击搜索
# input_box = page.locator(...)
# input_box.fill(image_url)
# 提取关键数据:AI 描述 (这是 API 方案拿不到的)
ai_desc = page.locator("div.knowledge-graph-description").text_content()
return ai_desc
except Exception as e:
print(f"Playwright Error: {e}")
return None
📉 遇到的瓶颈
通过 Playwright,我们实现了零成本获取数据,并且成功提取到了 API 无法提供的 AI 智能描述,丰富了商品信息。
但是,随着采集量的增加,新的问题出现了:
-
性能瓶颈:Playwright 启动浏览器非常消耗内存和 CPU。处理 1000 张图片需要数小时,效率远低于 API。
-
CDP 检测:Google 升级了检测机制,开始针对 Chrome DevTools Protocol (CDP) 进行探测。即使使用了 Stealth 模式,Playwright 依然会在高频访问下暴露。
🔜 下篇预告
为了追求极致的过检测率(Pass Rate)和更底层的控制权,我们探索了比 Playwright 更底层的技术栈------DrissionPage ,并最终结合了 Decodo API 形成了一套混合方案。
在下一篇 《FindQC 实战 (三):基于 DrissionPage 的底层攻防与 Decodo 混合架构》 中,我们将揭示如何绕过 CDP 检测,并总结整个项目的最终架构演进。