Python爬虫——urllib_ajax的get请求爬取豆瓣电影前十页

Python爬虫——urllib_ajax的get请求爬取豆瓣电影前十页

一、背景与问题

在Web爬虫领域,AJAX请求的处理是核心难点之一。传统页面爬虫仅需解析HTML内容,而AJAX请求则涉及动态加载数据的场景。以豆瓣电影Top250为例,其分页数据是通过AJAX接口动态加载的,传统requests库无法直接获取。

这种场景下,使用urllib库进行GET请求时需要特别注意:

  1. 需要正确构造请求头(User-Agent等)
  2. 要处理分页参数的动态变化
  3. 需要解析返回的JSON数据
  4. 可能遇到反爬虫机制(如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请求。核心流程如下:

  1. 构造请求头(headers)
  2. 创建请求对象(Request)
  3. 发送请求获取响应
  4. 解析响应内容(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 url

3. 数据解析

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请求的完整流程,包括:

  1. 构造正确的请求头
  2. 处理分页参数的动态变化
  3. 解析返回的JSON数据
  4. 处理可能的异常和反爬虫机制

在实际开发中,这种方案适用于:

  • 需要处理简单AJAX GET请求的场景
  • 对性能要求不高的爬虫任务
  • 需要精确控制请求头的场景

但需要注意:

  • 不适合处理复杂的动态内容(应使用selenium)
  • 不适合需要处理认证的场景(应使用CookieJar)
  • 不适合需要高并发的场景(应使用多线程/异步)

对于豆瓣电影爬虫,建议结合requests库和代理IP池进行优化,同时注意遵守网站的robots.txt规则。通过合理的设计和实践,可以有效提升爬虫的稳定性和效率。

最后修改于:2026年09月19日 16:10

评论已关闭

推荐阅读

AIGC实战——Transformer模型
2024年12月01日
Socket TCP 和 UDP 编程基础(Python)
2024年11月30日
python , tcp , udp
如何使用 ChatGPT 进行学术润色?你需要这些指令
2024年12月01日
AI
最新 Python 调用 OpenAi 详细教程实现问答、图像合成、图像理解、语音合成、语音识别(详细教程)
2024年11月24日
ChatGPT 和 DALL·E 2 配合生成故事绘本
2024年12月01日
omegaconf,一个超强的 Python 库!
2024年11月24日
【视觉AIGC识别】误差特征、人脸伪造检测、其他类型假图检测
2024年12月01日
[超级详细]如何在深度学习训练模型过程中使用 GPU 加速
2024年11月29日
Python 物理引擎pymunk最完整教程
2024年11月27日
MediaPipe 人体姿态与手指关键点检测教程
2024年11月27日
深入了解 Taipy:Python 打造 Web 应用的全面教程
2024年11月26日
基于Transformer的时间序列预测模型
2024年11月25日
Python在金融大数据分析中的AI应用(股价分析、量化交易)实战
2024年11月25日
AIGC Gradio系列学习教程之Components
2024年12月01日
Python3 `asyncio` — 异步 I/O,事件循环和并发工具
2024年11月30日
llama-factory SFT系列教程:大模型在自定义数据集 LoRA 训练与部署
2024年12月01日
Python 多线程和多进程用法
2024年11月24日
Python socket详解,全网最全教程
2024年11月27日
python之plot()和subplot()画图
2024年11月26日
理解 DALL·E 2、Stable Diffusion 和 Midjourney 工作原理
2024年12月01日