1. 项目背景与工具选型
爬取豆瓣电影Top250榜单是许多Python初学者接触网络爬虫的第一个实战项目。这个榜单包含了华语影史上最受观众喜爱的250部电影,数据规整且无需登录即可访问,非常适合作为爬虫练习的靶场。不过随着豆瓣反爬机制的升级,传统的requests+BeautifulSoup方案已经很难稳定运行。本文将分享一套结合安全测试工具的高效解决方案。
为什么选择Kali+Burp Suite这套组合?Kali Linux内置了大量网络安全工具,其代理配置和流量分析能力可以帮我们快速定位反爬机制。Burp Suite作为专业的Web安全测试平台,能直观展示所有HTTP请求和响应细节,这对分析动态加载内容和反爬策略至关重要。XPath则是处理HTML文档的利器,相比正则表达式更易维护。
注意:本文所有技术仅用于学习交流,请控制请求频率,建议间隔3-5秒,避免对目标服务器造成压力。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境准备与工具配置
2.1 Kali Linux基础环境
建议使用Kali 2023.3以上版本,已预装Python3.11。如果使用其他Linux发行版,需要额外安装以下依赖:
bash复制sudo apt install python3-pip chromium-driver
关键工具链配置:
- 配置系统代理为127.0.0.1:8080(Burp默认监听端口)
- 安装Python依赖库:
bash复制pip install requests_html lxml pandas fake-useragent
2.2 Burp Suite拦截配置
Community版即可满足需求,重点配置两项:
- Proxy -> Options里确保"Intercept Client Requests"已启用
- 在"Proxy Listeners"添加0.0.0.0:8080的绑定
测试配置是否生效:
python复制import requests
proxies = {'http': 'http://127.0.0.1:8080', 'https': 'http://127.0.0.1:8080'}
requests.get("http://movie.douban.com/top250", proxies=proxies)
此时在Burp的Proxy标签页应能看到拦截的请求。
3. 反爬机制分析与绕过方案
3.1 请求头校验
豆瓣会检查以下关键头部:
- User-Agent:必须使用常见浏览器标识
- Referer:需要模拟从豆瓣站内跳转
- Cookie:首次访问会设置验证cookie
解决方案:
python复制from fake_useragent import UserAgent
headers = {
'User-Agent': UserAgent().chrome,
'Referer': 'https://www.douban.com/',
'Accept-Language': 'zh-CN,zh;q=0.9'
}
3.2 IP频率限制
实测发现单个IP连续请求超过10次会触发临时封禁。建议:
- 使用time.sleep随机延时(3-8秒)
- 配合代理IP池(本文不展开)
3.3 动态内容加载
通过Burp拦截发现,部分电影详情是通过AJAX动态加载的。解决方案:
python复制from requests_html import HTMLSession
session = HTMLSession()
r = session.get(url)
r.html.render(sleep=2) # 等待JavaScript执行
4. XPath定位技巧详解
4.1 基础定位方法
豆瓣Top250页面的电影条目都包含在class为"item"的div中:
python复制movies = r.html.xpath('//div[@class="item"]')
关键字段提取示例:
python复制for movie in movies:
title = movie.xpath('.//span[@class="title"]/text()')[0] # 中文名
rating = movie.xpath('.//span[@class="rating_num"]/text()')[0]
link = movie.xpath('.//div[@class="hd"]/a/@href')[0]
4.2 处理多语言标题
部分电影有中英文两个标题:
python复制titles = movie.xpath('.//span[@class="title"]/text()')
chinese_title = titles[0]
english_title = titles[1] if len(titles)>1 else None
4.3 提取导演和主演信息
这些信息位于class为"bd"的div中:
python复制info = movie.xpath('.//div[@class="bd"]/p[1]/text()')[0].strip()
director = info.split('\n')[0].replace('导演:', '').strip()
actors = info.split('\n')[1].replace('主演:', '').strip()
5. 完整爬虫实现与数据存储
5.1 分页处理逻辑
豆瓣Top250采用经典的分页模式,每页25条:
python复制base_url = "https://movie.douban.com/top250?start={}"
for page in range(0, 250, 25):
url = base_url.format(page)
# 发送请求并处理响应...
5.2 异常处理机制
必须包含以下异常处理:
python复制try:
r = session.get(url, headers=headers, proxies=proxies, timeout=10)
r.raise_for_status()
except requests.exceptions.RequestException as e:
print(f"请求失败: {e}")
continue
5.3 数据存储方案
推荐使用pandas保存为CSV:
python复制import pandas as pd
df = pd.DataFrame({
'排名': range(1, 251),
'标题': titles,
'评分': ratings,
# 其他字段...
})
df.to_csv('douban_top250.csv', index=False, encoding='utf-8-sig')
6. 常见问题排查指南
6.1 请求返回403错误
- 检查User-Agent是否有效
- 验证Cookie是否过期(通过浏览器手动访问获取新Cookie)
- 确认IP未被封禁
6.2 XPath匹配不到数据
- 使用Burp确认实际返回的HTML结构
- 检查是否遗漏了动态加载内容(需要render())
- 尝试更宽松的XPath表达式,如"//*[contains(@class,'item')]"
6.3 数据错位问题
- 确保每个字段的索引一致
- 添加空值处理逻辑:
python复制rating = movie.xpath('.//span[@class="rating_num"]/text()')
rating = rating[0] if rating else "无评分"
7. 高级技巧与优化建议
7.1 使用Session保持状态
python复制session = HTMLSession()
session.headers.update(headers)
session.proxies = proxies
7.2 随机延时策略
python复制from random import uniform
time.sleep(uniform(2.5, 5.0))
7.3 断点续爬实现
python复制import os
if os.path.exists('progress.txt'):
with open('progress.txt') as f:
start_page = int(f.read())
else:
start_page = 0
这套方案经过笔者多次实战测试,在2023年10月仍可稳定运行。关键在于通过Burp Suite实时分析请求特征,配合合理的请求间隔。如果后续豆瓣更新反爬策略,可以用同样的方法分析新机制并调整代码。
