1. 项目背景与核心挑战
动态网页数据抓取一直是爬虫领域的硬骨头。传统基于requests+BeautifulSoup的技术栈在面对现代前端框架(如React/Vue)构建的网站时往往束手无策。以某点评网为例,其核心数据通过AJAX动态加载,页面元素随用户交互实时变化,常规爬虫只能获取到空壳HTML。
这个项目要解决三个技术痛点:
- 动态内容渲染问题 - 需要完整执行JavaScript
- 反爬绕过机制 - 需要模拟真人操作轨迹
- 大规模采集稳定性 - 需要应对IP封锁和验证码
2. 技术选型:双引擎架构解析
2.1 Selenium方案特点
- 成熟稳定,浏览器兼容性好
- 支持真实浏览器环境调试
- 执行速度较慢(需启动完整浏览器)
- 典型配置示例:
python复制from selenium import webdriver
options = webdriver.ChromeOptions()
options.add_argument('--headless')
driver = webdriver.Chrome(options=options)
2.2 Playwright优势
- 微软开源,支持多浏览器
- 自带智能等待机制
- 执行效率比Selenium高30%
- 典型启动代码:
python复制from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_page()
2.3 混合方案设计思路
- Playwright主攻高频数据采集
- Selenium作为备用方案
- 自动切换逻辑:
python复制def get_driver(engine_type):
if engine_type == 'playwright' and playwright_available:
return PlaywrightDriver()
return SeleniumDriver()
3. 核心实现细节
3.1 页面等待策略优化
- 固定等待(不推荐):time.sleep(3)
- 条件等待(推荐):
python复制# Selenium方式
WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.CSS_SELECTOR, ".shop-list"))
)
# Playwright方式
page.wait_for_selector('.shop-list', state='attached')
3.2 反爬对抗方案
- 请求头完整模拟:
python复制headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0)',
'Accept-Language': 'zh-CN,zh;q=0.9',
'Referer': 'https://www.dianping.com/'
}
- 鼠标移动轨迹模拟:
python复制# 使用bezier曲线模拟自然移动
def move_mouse(page, selector):
element = page.query_selector(selector)
box = element.bounding_box()
page.mouse.move(
box['x'] + box['width']/2,
box['y'] + box['height']/2,
steps=random.randint(30, 50)
)
3.3 数据提取技巧
- 动态class处理方案:
python复制# 使用CSS属性选择器
page.query_selector('[class*="shopname-"]')
# XPath模糊匹配
driver.find_element(By.XPATH, '//div[contains(@class, "comment")]')
4. 分布式架构设计
4.1 任务调度系统
mermaid复制graph TD
A[主节点] -->|分发任务| B(Worker 1)
A -->|分发任务| C(Worker 2)
A -->|分发任务| D(Worker 3)
B -->|数据回传| E[MySQL]
C -->|数据回传| E
D -->|数据回传| E
4.2 IP代理池管理
- 代理质量检测算法:
python复制def check_proxy(proxy):
try:
res = requests.get('http://httpbin.org/ip',
proxies={'http': proxy},
timeout=5)
return res.status_code == 200
except:
return False
5. 数据存储方案
5.1 数据库设计
sql复制CREATE TABLE shops (
id VARCHAR(32) PRIMARY KEY,
name VARCHAR(100) NOT NULL,
rating DECIMAL(2,1),
review_count INT,
address TEXT,
phone VARCHAR(20),
updated_at TIMESTAMP
);
5.2 增量更新策略
- 基于时间戳的增量查询:
python复制SELECT MAX(updated_at) FROM shops WHERE city='上海'
6. 异常处理机制
6.1 常见异常类型
| 异常类型 | 触发场景 | 解决方案 |
|---|---|---|
| ElementNotInteractableException | 元素未加载完成 | 增加等待时间 |
| TimeoutException | 网络延迟 | 自动重试机制 |
| CaptchaException | 验证码拦截 | 触发人工处理流程 |
6.2 自动恢复实现
python复制retry_count = 0
while retry_count < 3:
try:
scrape_page(url)
break
except Exception as e:
retry_count += 1
change_proxy()
logging.warning(f"Retry {retry_count}: {str(e)}")
7. 性能优化技巧
7.1 请求合并技术
python复制# 批量获取店铺详情
def batch_scrape(shop_ids):
with ThreadPoolExecutor(max_workers=5) as executor:
futures = [executor.submit(scrape_shop, id) for id in shop_ids]
return [f.result() for f in futures]
7.2 缓存利用方案
python复制@lru_cache(maxsize=1000)
def get_shop_info(shop_id):
return db.query_shop(shop_id)
8. 法律合规要点
8.1 robots.txt检查
python复制from urllib.robotparser import RobotFileParser
rp = RobotFileParser()
rp.set_url("https://www.dianping.com/robots.txt")
rp.read()
can_fetch = rp.can_fetch("*", target_url)
8.2 采集频率控制
python复制# 随机延迟算法
delay = random.uniform(1.5, 3.0)
time.sleep(delay)
重要提示:实际开发中请严格遵守目标网站的Terms of Service,本文示例仅作技术研究用途。
9. 完整项目架构
9.1 系统模块划分
code复制project/
├── core/ # 核心爬取逻辑
├── proxy/ # 代理管理
├── storage/ # 数据存储
├── utils/ # 工具函数
└── config.py # 配置文件
9.2 关键配置示例
python复制# config.py
CONCURRENT_REQUESTS = 3
DOWNLOAD_DELAY = 2.5
RETRY_TIMES = 2
USER_AGENTS = [...]
10. 实战经验总结
-
元素定位优先顺序:
- 首选稳定的ID选择器
- 次选CSS类名选择器
- 最后考虑XPath
-
验证码处理建议:
- 商业方案:接入打码平台
- 技术方案:使用OCR识别简单验证码
- 终极方案:人工介入流程
-
性能数据对比(测试环境):
- 纯Selenium:约120页/小时
- Playwright:约180页/小时
- 混合模式:约200页/小时
在实际部署中发现,Playwright在页面加载速度上比Selenium快约40%,但某些特殊场景下Selenium的兼容性更好。建议根据目标网站特性动态调整两种方案的使用比例。