python爬虫从0到1 -ajax的get请求进阶

'# python爬虫从0到1 -ajax的get请求进阶

一、背景与问题

在现代Web开发中,AJAX技术已经成为前端与后端交互的标配。通过AJAX,网页可以在不刷新的情况下与服务器交换数据,实现动态内容更新。这种技术给爬虫带来了新的挑战:传统爬虫通过解析静态HTML页面获取数据,而AJAX请求的动态内容往往需要模拟前端的交互行为才能获取。

典型的场景包括:

  • 网站通过AJAX分页加载数据(如商品列表、评论区)
  • 动态生成的表格数据(如股票行情、实时数据)
  • 基于用户输入的过滤条件动态加载内容
  • 通过JavaScript生成的虚拟DOM数据

这类数据通常不通过传统的<form>提交,而是通过fetch()$.ajax()等JavaScript方法发起GET/POST请求。爬虫需要模拟这些请求,获取服务器返回的原始数据。

二、基本原理

AJAX GET请求的核心原理是:

  1. 前端通过JavaScript向服务器发送HTTP GET请求
  2. 服务器返回JSON/XML等格式的数据
  3. 前端通过JavaScript更新DOM内容

爬虫实现的关键点:

  • 构造与前端完全一致的请求参数(包括查询参数、Headers、Cookie等)
  • 模拟浏览器环境(如User-Agent、Referer)
  • 处理动态生成的请求参数(如时间戳、随机token)
  • 应对服务器端的反爬虫机制(如IP封禁、验证码)

三、环境准备

pip install requests beautifulsoup4 lxml

需要准备的开发环境:

  • Python 3.8+
  • requests库用于发送HTTP请求
  • BeautifulSoup/Lxml用于解析HTML
  • 可选:Selenium模拟浏览器行为(应对复杂的JavaScript渲染)

四、核心实现

1. 基础AJAX GET请求模拟

import requests

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
    'Referer': 'https://example.com'
}

params = {
    'page': '1',
    'pageSize': '10'
}

response = requests.get(
    'https://example.com/api/data',
    params=params,
    headers=headers
)

print(response.json())

关键点解释:

  • params参数用于构造URL查询字符串
  • headers需要包含完整的请求头信息
  • 实际开发中需要通过浏览器开发者工具(F12)抓包分析请求头和参数

2. 处理动态生成的参数

import requests
import time
import random

def get_dynamic_token():
    # 模拟服务器生成的token,实际开发中需分析生成逻辑
    return f"token_{int(time.time())}_{random.randint(1000,9999)}"

headers = {
    'User-Agent': 'Mozilla/5.0',
    'X-Requested-With': 'XMLHttpRequest'
}

params = {
    'page': '1',
    'token': get_dynamic_token()
}

response = requests.get(
    'https://example.com/api/dynamic',
    params=params,
    headers=headers
)

print(response.json())

关键点解释:

  • 动态参数通常包含时间戳、随机数或业务相关字段
  • 需要分析服务器端生成逻辑(如查看网页源码或抓包)
  • 有些参数需要在浏览器上下文中生成(如Cookie中的session标识)

3. 处理分页请求

import requests

def fetch_page(page_num):
    headers = {
        'User-Agent': 'Mozilla/5.0',
        'Referer': 'https://example.com'
    }
    
    params = {
        'page': str(page_num),
        'size': '20'
    }
    
    response = requests.get(
        'https://example.com/api/pagination',
        params=params,
        headers=headers
    )
    
    return response.json()

# 获取前10页数据
for page in range(1, 11):
    data = fetch_page(page)
    print(f"Page {page} data: {len(data)} items")

关键点解释:

  • 分页参数通常包含pagesize字段
  • 需要处理服务器返回的分页信息(如总页数、当前页码)
  • 注意请求的URL可能包含路径分页参数(如/api/data?page=1

五、完整案例

案例:爬取商品评论数据

目标:爬取某电商网站的商品评论,使用AJAX分页获取数据

1. 抓包分析

通过浏览器开发者工具分析请求:

  • 请求URL: https://example.com/api/comments
  • 请求参数: page=1, pageSize=10
  • 请求头包含: User-Agent, Referer, X-Requested-With
  • 响应数据格式: JSON数组

2. 爬虫实现

import requests
import json

class CommentScraper:
    def __init__(self, product_id):
        self.product_id = product_id
        self.headers = {
            'User-Agent': 'Mozilla/5.0',
            'Referer': 'https://example.com',
            'X-Requested-With': 'XMLHttpRequest'
        }
    
    def get_comments(self, page=1):
        params = {
            'productId': self.product_id,
            'page': page,
            'pageSize': 10
        }
        
        response = requests.get(
            'https://example.com/api/comments',
            params=params,
            headers=self.headers
        )
        
        return response.json()
    
    def parse_comments(self, data):
        return [item['content'] for item in data]

# 使用示例
scraper = CommentScraper(product_id='12345')
comments = scraper.get_comments(page=1)
print(f"Found {len(comments)} comments:")
for comment in comments:
    print(f"- {comment}")

关键点解释:

  • 封装成类便于管理
  • 分页参数包含产品ID和分页参数
  • 响应数据需要解析成具体字段
  • 实际开发中需要处理API的分页机制(如总页数、当前页码)

六、源码解析

get_comments方法为例:

def get_comments(self, page=1):
    params = {
        'productId': self.product_id,
        'page': page,
        'pageSize': 10
    }
    
    response = requests.get(
        'https://example.com/api/comments',
        params=params,
        headers=self.headers
    )
    
    return response.json()

源码分析:

  1. 构造查询参数:包含产品ID、分页参数
  2. 发送GET请求:使用requests库
  3. 处理响应:返回JSON格式数据
  4. 未处理异常:实际开发中需要添加异常处理逻辑

七、进阶使用

1. 处理反爬虫机制

import requests
import time
import random

def get_request_with_retry(url, headers, params, max_retries=3):
    for i in range(max_retries):
        try:
            response = requests.get(
                url,
                params=params,
                headers=headers,
                timeout=10
            )
            response.raise_for_status()
            return response.json()
        except requests.exceptions.RequestException as e:
            print(f"Attempt {i+1} failed: {e}")
            time.sleep(2 ** i)  # 指数退避
    return None

进阶点:

  • 添加重试机制应对网络波动
  • 处理HTTP错误码(如429、503)
  • 控制请求频率(避免被封IP)

2. 使用Session保持会话

import requests

session = requests.Session()
session.headers.update({
    'User-Agent': 'Mozilla/5.0',
    'Referer': 'https://example.com'
})

response = session.get('https://example.com/api/data')

进阶点:

  • 保持Cookie会话
  • 处理需要身份验证的接口
  • 提高请求效率(减少重复设置headers)

3. 使用Selenium模拟浏览器

from selenium import webdriver
from selenium.webdriver.common.by import By

driver = webdriver.Chrome()
driver.get('https://example.com')

# 等待元素加载
driver.implicitly_wait(10)

# 获取动态生成的数据
data = driver.find_element(By.ID, 'data-container').text
print(data)

driver.quit()

适用场景:

  • 需要处理复杂JavaScript渲染
  • 涉及动态加载的页面
  • 需要模拟用户交互行为(如点击、输入)

八、性能与工程实践

1. 性能优化方法

优化策略说明
使用连接池requests.Session() 自动维护连接池
并发处理使用concurrent.futuresasyncio
缓存机制使用redis缓存高频请求结果
压缩传输使用gzip压缩响应数据
并行请求使用ThreadPoolExecutor批量处理

2. 异常处理

try:
    response = requests.get(url, headers=headers, timeout=5)
    response.raise_for_status()
except requests.exceptions.RequestException as e:
    print(f"请求异常: {e}")
    # 记录日志、重试、通知运维等

3. 安全风险

风险类型解决方案
IP封禁使用代理IP池
验证码使用第三方验证码识别服务
数据篡改验证响应签名(如HMAC)
响应伪装验证Content-Type和X-Content-Type-Options头

九、常见问题与踩坑

1. 常见错误

错误类型原因解决方案
403 Forbidden请求头不完整补全Referer、User-Agent
429 Too Many Requests请求频率过高控制请求间隔,使用代理
500 Internal Server Error服务器错误记录日志,重试机制
400 Bad Request参数缺失补全查询参数
401 Unauthorized需要认证添加Authorization头

2. 常见陷阱

  • 忽略Cookie:部分接口需要携带Cookie
  • 忽略时间戳参数:动态参数可能导致请求失效
  • 忽略Referer:部分接口需要指定来源
  • 忽略请求体:GET请求不需要Body,但部分接口可能需要
  • 忽略Content-Type:需要指定application/json

3. 踩坑案例

# 错误示例:忽略Cookie
response = requests.get('https://example.com/api/data', params=params)

# 正确做法:携带Cookie
cookies = {
    'session_id': '123456',
    'token': 'abcdef'
}
response = requests.get('https://example.com/api/data', params=params, cookies=cookies)

十、最佳实践

1. 通用实践

  • 抓包分析:使用Chrome开发者工具分析请求
  • 参数构造:严格按照接口文档构造参数
  • 异常处理:添加全面的异常捕获机制
  • 日志记录:记录请求详情和响应内容
  • 速率控制:设置合理的请求间隔(如1秒)

2. 项目组织建议

comment_scraper/
│
├── config.py          # 配置文件
├── utils.py           # 工具函数(如代理池、日志)
├── scraper.py         # 爬虫核心逻辑
├── parser.py          # 数据解析
├── requests.py        # 请求处理
└── requirements.txt   # 依赖管理

3. 推荐库选择

场景推荐库说明
简单请求requests简单易用
复杂交互Selenium模拟浏览器行为
高性能asyncio + aiohttp异步处理
代理管理requests-session维护会话
日志记录logging标准日志库

十一、总结

AJAX GET请求的爬虫技术是现代Web爬虫的重要组成部分。通过模拟前端请求,我们可以获取动态生成的数据。本文深入解析了AJAX请求的原理,提供了多个代码示例,涵盖了从基础请求到复杂场景的实现方法。

在实际开发中,需要根据具体情况选择合适的实现方式:

  • 简单接口使用requests
  • 复杂交互使用Selenium
  • 高性能场景使用异步库
  • 安全场景添加反爬虫机制

需要注意避免常见错误,如忽略请求头、动态参数缺失等。通过合理的设计和实践,可以有效应对各种反爬虫策略,提高爬虫的稳定性和效率。

在工程实践中,建议采用模块化设计、添加完善的异常处理、使用日志系统,并定期维护代理池和IP库。对于大规模数据采集,可以结合分布式爬虫框架(如Scrapy-Redis)进行扩展。

最后修改于:2026年09月14日 18:13

评论已关闭

推荐阅读

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日