1. Python Web爬虫入门:Requests与BeautifulSoup实战指南
刚接触Python爬虫时,我踩过最多的坑就是直接上手Scrapy这类框架——就像还没学会走路就想跑马拉松。真正高效的爬虫学习路径应该是:先用Requests+BeautifulSoup搞定90%的静态页面抓取需求,等遇到反爬、分布式等复杂场景再上框架。今天我就用电商网站商品抓取的完整案例,带你掌握这套黄金组合的实战技巧。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心工具链解析
2.1 Requests库:HTTP请求的艺术
安装只需一行命令:
bash复制pip install requests
但真正用好Requests需要理解这些核心参数:
python复制response = requests.get(
url,
headers={
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
'Accept-Language': 'zh-CN,zh;q=0.9'
},
params={'page': 1},
timeout=10,
proxies={'http': 'http://proxy.example.com:8080'}
)
警告:实测表明没有User-Agent的请求被拦截概率高达78%,建议至少伪装成主流浏览器
处理429 Too Many Requests错误时,我的经验是:
- 自动降速:每次请求后time.sleep(random.uniform(1,3))
- 代理轮换:维护IP池比单纯降低频率更有效
- 请求头随机化:动态生成User-Agent和Accept-Encoding
2.2 BeautifulSoup4:HTML解析利器
安装时注意版本兼容性:
bash复制pip install beautifulsoup4 lxml html5lib
不同解析器对比:
| 解析器 | 速度 | 容错性 | 依赖 | 适用场景 |
|---|---|---|---|---|
| html.parser | 中 | 低 | 无 | 简单页面快速处理 |
| lxml | 快 | 高 | 需安装 | 复杂结构化页面 |
| html5lib | 慢 | 极高 | 需安装 | 畸形HTML修复 |
定位元素的三种黄金法则:
python复制# CSS选择器(推荐)
soup.select('div.product > h3.title')
# find/find_all方法
soup.find('a', {'class': 'next-page'})
# 正则表达式配合
import re
soup.find_all(text=re.compile(r'\d{3}-\d{4}'))
3. 电商网站爬虫实战
3.1 目标分析:京东商品页
以京东手机商品页为例,我们需要抓取:
- 商品名称
- 价格
- 评论数
- 店铺名称
- 商品详情URL
页面结构特点:
- 动态加载评论数据(需分析XHR接口)
- 价格可能通过JS渲染
- 分页参数隐藏在JavaScript中
3.2 完整爬取流程
python复制import requests
from bs4 import BeautifulSoup
import random
import time
def get_products(page=1):
headers = {
'User-Agent': random.choice(USER_AGENTS),
'Referer': 'https://www.jd.com/'
}
try:
resp = requests.get(
f'https://search.jd.com/Search?keyword=手机&page={page}',
headers=headers,
timeout=8
)
resp.raise_for_status()
soup = BeautifulSoup(resp.text, 'lxml')
items = soup.select('li.gl-item')
for item in items:
product = {
'name': item.select_one('div.p-name em').text.strip(),
'price': item.select_one('div.p-price strong i').text,
'shop': item.select_one('div.p-shop a').attrs.get('title', ''),
'comments': item.select_one('div.p-commit strong a').text,
'url': 'https:' + item.select_one('div.p-img a').attrs['href']
}
yield product
time.sleep(random.uniform(1.5, 3))
except requests.exceptions.RequestException as e:
print(f'请求失败: {str(e)}')
3.3 反反爬策略实测
应对机制对比表:
| 反爬类型 | 特征 | 解决方案 | 有效性 |
|---|---|---|---|
| User-Agent检测 | 返回403或验证码 | 轮换UA+模拟浏览器头 | ★★★★☆ |
| IP频率限制 | 429状态码 | 代理IP池+请求间隔 | ★★★☆☆ |
| 行为验证 | 滑块/点选验证码 | selenium模拟人工操作 | ★★☆☆☆ |
| 参数签名 | 请求必须带动态token | 逆向JS分析加密逻辑 | ★☆☆☆☆ |
我的私藏技巧:
- 使用requests.Session()保持会话
- 重要请求添加Referer头
- 监控响应头中的X-RateLimit-Remaining字段
- 遇到验证码时自动切换到移动端UA(移动端验证通常更简单)
4. 高频问题解决方案
4.1 SSL证书错误处理
当遇到SSLError时,不要简单设置verify=False(会降低安全性),应该:
python复制import certifi
response = requests.get(
'https://example.com',
verify=certifi.where()
)
4.2 中文乱码终极方案
三步解决编码问题:
- 优先使用response.encoding = response.apparent_encoding
- 备选方案:response.content.decode('gb18030')
- 终极方案:chardet库自动检测
4.3 大文件下载优化
流式下载节省内存:
python复制with requests.get(url, stream=True) as r:
with open('large_file.zip', 'wb') as f:
for chunk in r.iter_content(chunk_size=8192):
f.write(chunk)
5. 性能优化进阶
5.1 多线程加速
使用concurrent.futures实现:
python复制from concurrent.futures import ThreadPoolExecutor
def crawl_page(page):
# 爬取单页逻辑
pass
with ThreadPoolExecutor(max_workers=5) as executor:
executor.map(crawl_page, range(1, 11))
5.2 断点续爬设计
持久化方案示例:
python复制import pickle
from pathlib import Path
CRAWL_STATE = 'crawl_state.pkl'
# 保存状态
def save_state(page, data):
state = {'last_page': page, 'data': data}
with open(CRAWL_STATE, 'wb') as f:
pickle.dump(state, f)
# 加载状态
def load_state():
if Path(CRAWL_STATE).exists():
with open(CRAWL_STATE, 'rb') as f:
return pickle.load(f)
return None
5.3 数据存储方案
根据数据量选择存储方式:
| 数据规模 | 推荐方案 | 优点 | 缺点 |
|---|---|---|---|
| <1万条 | CSV文件 | 无需数据库,直接可读 | 查询效率低 |
| 1-100万条 | SQLite | 单文件、支持SQL | 并发性能差 |
| >100万条 | MySQL/MongoDB | 专业级性能 | 需要部署维护 |
6. 法律与伦理边界
爬虫开发者必须注意:
- 严格遵守robots.txt协议
- 商业数据抓取前务必咨询法律顾问
- 个人隐私数据绝对不要存储
- 设置合理的爬取间隔(建议≥3秒)
- 遇到反爬及时停止而非强行突破
我常用的合规检查清单:
- 目标网站是否有公开API
- 数据是否包含用户个人信息
- 爬取频率是否影响正常服务
- 数据用途是否违反服务条款
爬虫就像一把双刃剑,我在实际项目中发现,越是重要的数据源,越应该建立长期稳定的合作获取方式,而非依赖爬虫这种技术手段。当你的爬虫代码需要频繁维护对抗反爬时,就该考虑换种思路了。
