Python爬虫——urllib_ajax的get请求爬取豆瓣电影前十页
Python爬虫——urllib_ajax的get请求爬取豆瓣电影前十页
一、背景与问题
在Web爬虫领域,AJAX请求的处理是核心难点之一。传统页面爬虫仅需解析HTML内容,而AJAX请求则涉及动态加载数据的场景。以豆瓣电影Top250为例,其分页数据是通过AJAX接口动态加载的,传统requests库无法直接获取。
这种场景下,使用urllib库进行GET请求时需要特别注意:
- 需要正确构造请求头(User-Agent等)
- 要处理分页参数的动态变化
- 需要解析返回的JSON数据
- 可能遇到反爬虫机制(如IP封禁、验证码)
本篇文章将深入探讨urllib处理AJAX GET请求的原理与实践,通过完整案例展示如何爬取豆瓣电影前十页数据。
二、基本原理
1. AJAX请求机制
AJAX(Asynchronous JavaScript and XML)是一种在后台与服务器进行数据交换的技术。对于豆瓣电影,其分页数据是通过以下URL加载的:
https://movie.douban.com/api/v2/movie/top250?start={start}&count={count}其中start参数表示起始页码(从0开始),count表示每页电影数量(默认25)。
2. urllib工作原理
urllib库通过urllib.request.Request对象构建请求,通过urllib.request.urlopen发送HTTP请求。核心流程如下:
- 构造请求头(headers)
- 创建请求对象(Request)
- 发送请求获取响应
- 解析响应内容(JSON格式)
3. 反爬虫机制
豆瓣电影接口会对请求进行以下限制:
- 需要携带User-Agent头
- 需要处理Referer头
- 需要处理Cookie(可能)
- 需要处理请求频率限制
三、环境准备
# 安装依赖(如需)
pip install lxml四、核心实现
1. 基础请求构造
import urllib.request
import json
# 构造请求头
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4443.116 Safari/537.36',
'Referer': 'https://movie.douban.com/'
}
# 构造请求对象
def create_request(url, headers):
req = urllib.request.Request(url, headers=headers)
return req
# 发送请求获取响应
def send_request(req):
with urllib.request.urlopen(req) as response:
return response.read().decode('utf-8')关键点解释:
User-Agent模拟浏览器行为Referer防止CSRF攻击urllib.request.urlopen返回的是bytes类型数据- 需要显式解码为字符串
2. 分页参数处理
def get_page_data(page):
start = page * 25
url = f'https://movie.douban.com/api/v2/movie/top250?start={start}&count=25'
return url3. 数据解析
def parse_response(html):
data = json.loads(html)
if data.get('error', None):
print(f"请求失败: {data['error']}")
return []
movies = []
for item in data['data']:
title = item.get('title', 'N/A')
rating = item.get('rating', {}).get('average', 0)
movies.append({
'title': title,
'rating': rating,
'year': item.get('year', 'N/A')
})
return movies五、完整案例
1. 爬取前十页数据
import json
import urllib.request
def main():
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4443.116 Safari/537.36',
'Referer': 'https://movie.douban.com/'
}
for page in range(10): # 爬取前10页
url = f'https://movie.douban.com/api/v2/movie/top250?start={page * 25}&count=25'
req = urllib.request.Request(url, headers=headers)
try:
with urllib.request.urlopen(req) as response:
html = response.read().decode('utf-8')
data = json.loads(html)
if data.get('error'):
print(f"请求失败: {data['error']}")
continue
movies = data['data']
print(f"\n第{page+1}页数据:")
for idx, movie in enumerate(movies):
print(f"{idx+1}. {movie['title']} {movie['rating']['average']}")
# 保存数据到文件(可选)
with open(f'douban_movies_page{page+1}.json', 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=2)
except Exception as e:
print(f"请求异常: {str(e)}")
if __name__ == '__main__':
main()关键点分析:
- 使用
try-except处理网络异常 - 每页数据保存为JSON文件
- 避免重复请求相同URL
- 控制爬取范围(10页)
六、源码解析
1. 请求构造过程
req = urllib.request.Request(url, headers=headers)Request对象包含完整请求信息headers参数用于设置请求头- 可以通过
req.get_method()获取请求方法(GET/POST)
2. 响应处理
with urllib.request.urlopen(req) as response:
html = response.read().decode('utf-8')urllib.request.urlopen返回的是HTTPResponse对象read()方法读取响应体decode('utf-8')将bytes转换为字符串
3. JSON解析
data = json.loads(html)json.loads()将字符串转换为Python字典- 需要处理可能的异常(如JSONDecodeError)
- 对返回数据进行校验(检查error字段)
七、进阶使用
1. 增加请求频率控制
import time
for page in range(10):
# ... 请求逻辑 ...
time.sleep(1) # 每次请求间隔1秒2. 处理反爬虫机制
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4443.116 Safari/537.36',
'Referer': 'https://movie.douban.com/',
'Accept-Language': 'zh-CN,zh;q=0.9',
'Accept-Encoding': 'gzip, deflate, br'
}3. 使用Cookie处理认证
import http.cookiejar
# 创建CookieJar对象
cj = http.cookiejar.CookieJar()
# 创建处理器
handler = urllib.request.HTTPCookieProcessor(cj)
# 创建 opener
opener = urllib.request.build_opener(handler)八、性能与工程实践
1. 性能优化
- 使用
concurrent.futures多线程处理 - 使用
requests库替代urllib(更简洁) - 使用缓存机制(如
httpcache库)
2. 异常处理
except urllib.error.URLError as e:
print(f"URL错误: {e.reason}")
except urllib.error.HTTPError as e:
print(f"HTTP错误: {e.code} {e.reason}")3. 安全风险
- 需要处理可能的反爬虫机制(如IP封禁)
- 避免泄露User-Agent等敏感信息
- 使用代理IP池处理封禁问题
4. 代码组织
建议采用如下目录结构:
douban_crawler/
├── main.py # 主程序
├── utils.py # 工具函数
├── config.py # 配置文件
├── data/ # 存储数据
└── logs/ # 日志文件九、常见问题与踩坑
1. 请求被拒绝(403 Forbidden)
错误示例:
urllib.request.urlopen(req) # 未设置User-Agent解决方法:
headers = {'User-Agent': 'Mozilla/5.0...'}2. JSON解析错误
错误示例:
json.loads(html) # 未处理异常解决方法:
try:
data = json.loads(html)
except json.JSONDecodeError as e:
print(f"JSON解析错误: {e}")3. 超时处理
错误示例:
urllib.request.urlopen(req) # 未设置超时解决方法:
req = urllib.request.Request(url, headers=headers, timeout=10)4. 分页参数错误
错误示例:
start = page * 25 # 未考虑起始页码解决方法:
start = (page - 1) * 25 # 调整分页逻辑十、最佳实践
1. 推荐方案
- 对于简单的AJAX GET请求,使用urllib足够
- 对于复杂的场景,使用requests库更方便
- 对于需要处理认证的场景,使用CookieJar处理Cookie
- 对于需要处理动态内容的场景,使用selenium
2. 推荐代码结构
# utils.py
import urllib.request
import json
def get_page_data(page):
start = (page - 1) * 25
url = f'https://movie.douban.com/api/v2/movie/top250?start={start}&count=25'
return url
def send_request(url, headers):
req = urllib.request.Request(url, headers=headers)
try:
with urllib.request.urlopen(req) as response:
return response.read().decode('utf-8')
except Exception as e:
print(f"请求异常: {str(e)}")
return None
def parse_response(html):
try:
data = json.loads(html)
if data.get('error'):
print(f"请求失败: {data['error']}")
return []
return data['data']
except json.JSONDecodeError as e:
print(f"JSON解析错误: {e}")
return []3. 推荐配置
# config.py
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4443.116 Safari/537.36',
'Referer': 'https://movie.douban.com/',
'Accept-Language': 'zh-CN,zh;q=0.9',
'Accept-Encoding': 'gzip, deflate, br'
}十一、总结
通过本篇文章的深入探讨,我们了解到使用urllib处理AJAX GET请求的完整流程,包括:
- 构造正确的请求头
- 处理分页参数的动态变化
- 解析返回的JSON数据
- 处理可能的异常和反爬虫机制
在实际开发中,这种方案适用于:
- 需要处理简单AJAX GET请求的场景
- 对性能要求不高的爬虫任务
- 需要精确控制请求头的场景
但需要注意:
- 不适合处理复杂的动态内容(应使用selenium)
- 不适合需要处理认证的场景(应使用CookieJar)
- 不适合需要高并发的场景(应使用多线程/异步)
对于豆瓣电影爬虫,建议结合requests库和代理IP池进行优化,同时注意遵守网站的robots.txt规则。通过合理的设计和实践,可以有效提升爬虫的稳定性和效率。
评论已关闭