共计 2513 个字符,预计需要花费 7 分钟才能阅读完成。
背景痛点:传统爬虫为什么不够用了
日常开发中,我们经常遇到需要从网页抓取数据的场景。但传统的爬虫技术(比如简单的 requests+BeautifulSoup 组合)在现代网页面前越来越力不从心。主要有三大痛点:

- 动态内容加载:现在 90% 以上的网站都采用前端框架(React/Vue 等)动态渲染内容,直接 GET 请求拿到的 HTML 里经常找不到我们需要的数据
- 反爬机制升级:从简单的 UserAgent 检测到行为指纹识别,网站防护手段越来越智能,普通爬虫很容易被封
- 内容解析困难:即便拿到 HTML,面对复杂的 DOM 结构和频繁改版的网页,写死的 XPath/CSS 选择器维护成本极高
最近接手的一个电商价格监控项目就踩了这些坑——刚开始用 Requests 每小时能抓几百页,运行三天后成功率直接跌到 10% 以下。
技术选型:Headless 浏览器哪家强
解决动态渲染问题,目前主流方案是采用 Headless 浏览器。我们对比了三款热门工具:
- Puppeteer:Chrome 团队出品,生态完善但仅限 JavaScript
- Playwright:微软开源,支持多语言(Python/Java 等)和多浏览器(Chromium/WebKit/Firefox)
- Scrapy+ 中间件:老牌框架扩展性强,但动态渲染需要组合 Splash 等组件
最终选择 Playwright 的原因很实在:
- Python 原生支持,不需要额外维护 Node 环境
- 自动等待机制比 Puppeteer 更智能
- 自带设备模拟功能(比如模拟手机 UA 和触摸事件)
- 文档里有大量中文示例(对团队新手友好)
核心实现:从入门到防封号
动态内容加载实战
先看最基础的动态加载示例(安装:pip install playwright && playwright install):
from playwright.sync_api import sync_playwright
def scrape_dynamic_page(url):
with sync_playwright() as p:
# 建议使用 Chromium,Firefox 对某些 CSS 支持更好
browser = p.chromium.launch(headless=True) # 生产环境记得开无头模式
page = browser.new_page()
# 关键配置:模拟真实用户访问
page.set_extra_http_headers({'Accept-Language': 'zh-CN,zh;q=0.9'})
# 智能等待:直到网络空闲或指定元素出现
page.goto(url, wait_until='networkidle')
page.wait_for_selector('.product-list') # 重要数据容器
# 获取渲染后的完整 HTML
html = page.content()
browser.close()
return html
反爬虫生存指南
网站常见的反爬手段和应对策略:
-
UserAgent 检测:每次随机切换 UA
from fake_useragent import UserAgent ua = UserAgent() page.set_user_agent(ua.chrome) -
IP 频率限制:建议使用付费代理服务(注意:免费代理 99% 不可用)
browser = p.chromium.launch(proxy={'server': 'http://your-proxy:port'} ) -
行为指纹:模拟人类操作模式
# 随机滚动页面 page.evaluate('window.scrollBy(0, document.body.scrollHeight * Math.random())') # 模拟鼠标移动(Playwright 内置 API)page.mouse.move(100, 100)
结构化数据提取
推荐使用相对 XPath 而非绝对路径:
# 获取所有商品卡片
products = page.query_selector_all('//div[contains(@class,"product-item")]')
for item in products:
print({'title': item.query_selector('.//h3').inner_text(),
'price': item.query_selector('xpath=./div[2]/span').inner_text()})
更复杂的场景可以用 Playwright 的 evaluate() 直接跑 JavaScript:
# 获取 Vue 组件内的数据
vue_data = page.evaluate('''() => {return window.__NUXT__.state.data}''')
生产环境生存手册
性能优化三原则
- 并发控制 :单个 IP 请求间隔建议 2 - 5 秒,可以用
asyncio.Semaphore限制 - 缓存复用:对静态资源实现本地缓存(Playwright 支持 storage_state)
- 失败重试:对 503/429 状态码实现指数退避重试
法律红线不能碰
- 严格遵守
robots.txt(Playwright 自动处理) - 商业数据抓取前务必咨询法务
- 设置合理的爬取间隔(参考:
time.sleep(random.uniform(1,3)))
开发者避坑清单
- Cookie 未清理:记得用
browser_context.close(),否则下次访问会带旧会话 - 内存泄漏:长期运行脚本要定期重启浏览器实例
- 元素定位失败 :优先用
data-testid这类稳定属性 - 验证码触发:遇到验证码立即降频,考虑接入打码平台
- SSL 证书错误:开发环境可以加
ignore_https_errors=True,生产环境必须处理
思考题
- 如何设计分布式爬虫的 URL 调度系统?
- 当遇到 Cloudflare 五秒盾时有哪些绕过方案?
- 对于需要登录的网站,如何安全地存储和管理会话?
写在最后
实际项目中,我们通过这套方案将电商数据抓取成功率从 17% 提升到 92%。关键经验是:不要试图对抗反爬系统,而要让自己看起来像普通用户。建议先用小流量测试网站容忍度,逐步调整到稳定状态。
下一步计划尝试结合 OCR 识别验证码,以及用强化学习优化爬取路径。如果你有相关经验,欢迎在评论区交流。
正文完
发表至: 未分类
近一天内
