人人都会AI编程

29.3 数据爬虫:多页采集、数据持久化、反爬应对

更新时间:2026-07-12

爬虫是 Python 最接地气、也最容易出活的应用方向之一。在实际业务里,一个完整的爬虫系统通常要解决三个核心问题:怎么翻页把数据拿全拿到之后怎么存怎么不被网站轻易封掉。这一节就围绕这三个点给出真实可用的方案。


多页采集

很少有网站把所有数据堆在一页里,所以翻页是爬虫的第一道坎。常见的翻页模式有三种:

1. URL 规律翻页
很多列表页的 URL 中带有 page=1page=2 这样的参数。最简单的办法就是循环拼 URL:

import requests
from bs4 import BeautifulSoup

for page in range(1, 11):          # 爬前10页
    url = f'https://example.com/news?page={page}'
    resp = requests.get(url, headers=headers)
    soup = BeautifulSoup(resp.text, 'html.parser')
    items = soup.select('.news-item')
    for item in items:
        # 提取数据...

这种方式简洁高效,前提是页面参数规整。

2. 从页面提取“下一页”链接
当 URL 规律不明显,或者网站用了 POST 形式翻页时,可以每次解析当前页面,找出“下一页”的链接:

next_url = 'https://example.com/news'
while next_url:
    resp = requests.get(next_url, headers=headers)
    soup = BeautifulSoup(resp.text, 'html.parser')
    # ... 提取当前页数据 ...
    next_tag = soup.select_one('a.next')
    next_url = next_tag['href'] if next_tag else None

优点是适应性强,缺点是每次多一次请求解析。实际应用中,结合请求间隔控制(见反爬部分)就能兼顾效率。

3. 详情页递归采集
很多时候列表页只有标题和摘要,真正需要的数据在详情页。这时需要先爬列表页拿到详情页 URL,再逐个访问:

detail_urls = []
# 第一步:收集所有详情页链接(可结合翻页)
for page in range(1, 5):
    url = f'https://example.com/list?page={page}'
    resp = requests.get(url, headers=headers)
    soup = BeautifulSoup(resp.text, 'html.parser')
    for link in soup.select('a.detail-link'):
        detail_urls.append(link['href'])

# 第二步:逐个爬取详情页
for detail_url in detail_urls:
    resp = requests.get(detail_url, headers=headers)
    soup = BeautifulSoup(resp.text, 'html.parser')
    # ... 提取完整内容 ...

如果你对效率有要求,可以考虑用 concurrent.futures 线程池或 asyncio + aiohttp 并发请求,但要注意控制并发数,避免被封。


数据持久化

数据拿到后,得有地方存,否则就是一次性有效。根据数据量和后续用途,选一种方案:

1. 写 CSV / Excel
适合几千到几十万行级别的结构化数据,直接用 pandas 最省事:

import pandas as pd

records = []  # 每条数据是一个字典
# 在循环中 records.append({'title': title, 'date': date, 'content': content})

df = pd.DataFrame(records)
df.to_csv('news.csv', index=False, encoding='utf-8-sig')
df.to_excel('news.xlsx', index=False)

如果不用 pandas,也可以用标准库 csv 模块,成本更低。

2. 写 JSON / JSON Lines
适合嵌套结构、或下一步直接喂给 API 或数据库:

import json

with open('data.json', 'w', encoding='utf-8') as f:
    json.dump(records, f, ensure_ascii=False, indent=2)

# 或者每行一条 JSON(方便逐行处理和追加)
with open('data.jsonl', 'a', encoding='utf-8') as f:
    for record in records:
        f.write(json.dumps(record, ensure_ascii=False) + '\n')

3. 存入数据库
如果数据量很大(百万级+),或者需要频繁查询、去重,就得用数据库。本地调试推荐 SQLite,上线可以切到 PostgreSQL/MySQL。

import sqlite3

conn = sqlite3.connect('data.db')
conn.execute('''CREATE TABLE IF NOT EXISTS news
                (id INTEGER PRIMARY KEY, title TEXT, date TEXT, content TEXT)''')
for record in records:
    conn.execute('INSERT INTO news (title, date, content) VALUES (?, ?, ?)',
                 (record['title'], record['date'], record['content']))
conn.commit()
conn.close()

更好的方式是配合 ORM(如 SQLAlchemy),方便后期维护和更换数据库。

4. 爬虫框架内置的导出
如果你用 Scrapy 框架,它内置了 Feed exports,可以一行配置就将数据导出为 JSON、CSV、XML 等,甚至直接入库(配合 Scrapy Item Pipeline),省心很多。


反爬应对

“爬”和“反爬”是猫鼠游戏,不存在一劳永逸的方案,核心是模拟正常人行为、降低访问频率、保留退路

1. 请求头伪装
最基本的操作:不露馅自己是爬虫。至少设置 User-Agent,最好再补上 Referer 等:

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

可以用 fake_useragent 库随机切换 UA。

2. 延时与随机化
连续高频访问是触发封禁的首要原因。最简单的办法是每次请求前后 time.sleep(random.uniform(1, 3))。如果量太大,可以用多线程但务必控制速度,或者将请求分散到更长的时间窗口(比如定时任务每小时爬一次)。

3. IP 代理
单一 IP 访问过多会被加入黑名单。免费代理可用但不稳定;生产环境一般购买付费代理池 API,每请求一次换一个 IP。基础用法:

proxies = {'http': 'http://127.0.0.1:8080', 'https': 'http://127.0.0.1:8080'}
resp = requests.get(url, headers=headers, proxies=proxies)

4. Cookie 与 Session 管理
有些网站需要登录或保持会话。使用 requests.Session() 可以自动处理 cookie:

session = requests.Session()
session.get(login_url, ...)   # 登录
session.get(data_url, ...)    # 后续自动携带 cookie

5. 验证码处理
图形验证码是最常见的反爬手段。简单的数字字母验证码可以用 OCR 库(如 pytesseract)识别,准确率有限;更靠谱的方式是接入第三方打码平台(如超级鹰、2captcha)。滑动验证码(如极验)的前端破解门槛较高,多数场景会考虑通过浏览器自动化工具(Selenium 或 Playwright)模拟真人滑动,或者准备好人工干预的通道。

6. 浏览器自动化降维打击
对于 JS 动态渲染、复杂反爬逻辑的页面,直接上 PlaywrightSelenium 驱动真实浏览器,网页就像在普通用户眼前一样渲染。代价是性能消耗大,但能绕过大部分反爬。配合无头模式(headless=True)和防检测手段(比如 stealth.min.js),效果很好。

7. 心态与法律底线

  • 爬虫是概率对抗,永远不要追求100%成功率,只要能拿到足够分析的数据即可。
  • 严格遵守 robots.txt,不要对服务器造成压力,不要抓取敏感数据和个人隐私。
  • 遇到封 IP 不要慌张,休眠几小时再试,或者寻找替代数据源(比如官方 API、开源数据集)。

以上三个环节——多页采集、持久化、反爬应对——基本覆盖了一个实用爬虫 90% 的工作。剩下的 10% 是业务逻辑、清洗和容错,这些可以根据具体需求灵活发挥。