🔥本期内容已收录至专栏《Python爬虫实战》,持续完善知识体系与项目实战,建议先订阅收藏,后续查阅更方便~持续更新中!!

全文目录:
-
- [🌟 开篇语](#🌟 开篇语)
-
- [📚 上期回顾](#📚 上期回顾)
- [🎯 本篇目标](#🎯 本篇目标)
- [💡 为什么优先找 API?](#💡 为什么优先找 API?)
-
- [对比:Playwright vs Requests](#对比:Playwright vs Requests)
- [🔍 实战:用 Network 面板找接口](#🔍 实战:用 Network 面板找接口)
-
- [步骤 1:打开开发者工具](#步骤 1:打开开发者工具)
- [步骤 2:筛选 XHR/Fetch 请求](#步骤 2:筛选 XHR/Fetch 请求)
- [步骤 3:识别数据接口](#步骤 3:识别数据接口)
- [步骤 4:复制接口 URL 参数)或 Form Data(POST 参数)](#步骤 4:复制接口 URL 参数)或 Form Data(POST 参数))
- [🛠️ 实战:用 Requests 重写采集逻辑](#🛠️ 实战:用 Requests 重写采集逻辑)
- [⚠️ 新手常见坑](#⚠️ 新手常见坑)
-
- [坑 1:缺少关键 Headers](#坑 1:缺少关键 Headers)
- [坑 2:参数加密或签名](#坑 2:参数加密或签名)
- [坑 3:接口返回数据不完整](#坑 3:接口返回数据不完整)
- [🚀 进阶技巧](#🚀 进阶技巧)
-
- [技巧 1:用 Playwright 自动找接口](#技巧 1:用 Playwright 自动找接口)
- [技巧 2:字段映射(接口字段 vs 页面展示)](#技巧 2:字段映射(接口字段 vs 页面展示))
- [技巧 3:批量请求优化](#技巧 3:批量请求优化)
- [📊 完整案例:从 Playwright 到 Requests](#📊 完整案例:从 Playwright 到 Requests)
-
- [第一步:用 Playwright 找接口](#第一步:用 Playwright 找接口)
- [第二步:用 Requests 重写](#第二步:用 Requests 重写)
- [📝 小结](#📝 小结)
- [🎯 下一章预告](#🎯 下一章预告)
- [🌟 文末](#🌟 文末)
-
- [📌 专栏持续更新中|建议收藏 + 订阅](#📌 专栏持续更新中|建议收藏 + 订阅)
- [✅ 互动征集](#✅ 互动征集)
🌟 开篇语
哈喽,各位小伙伴们你们好呀~我是【喵手】。
运营社区: C站 / 掘金 / 腾讯云 / 阿里云 / 华为云 / 51CTO
欢迎大家常来逛逛,一起学习,一起进步~🌟
我长期专注 Python 爬虫工程化实战 ,主理专栏 👉 《Python爬虫实战》:从采集策略 到反爬对抗 ,从数据清洗 到分布式调度 ,持续输出可复用的方法论与可落地案例。内容主打一个"能跑、能用、能扩展 ",让数据价值真正做到------抓得到、洗得净、用得上。
📌 专栏食用指南(建议收藏)
- ✅ 入门基础:环境搭建 / 请求与解析 / 数据落库
- ✅ 进阶提升:登录鉴权 / 动态渲染 / 反爬对抗
- ✅ 工程实战:异步并发 / 分布式调度 / 监控与容错
- ✅ 项目落地:数据治理 / 可视化分析 / 场景化应用
📣 专栏推广时间 :如果你想系统学爬虫,而不是碎片化东拼西凑,欢迎订阅/关注专栏《Python爬虫实战》
订阅后更新会优先推送,按目录学习更高效~
📚 上期回顾
上一篇《Python爬虫零基础入门【第七章:动态页面入门(Playwright)·第2节】动态列表:滚动加载/点击翻页(通用套路)!》,我们搞定了动态列表采集,学会了用 Playwright 处理滚动加载和点击翻页。现在你已经能应对各种复杂的交互式页面了------滚动、点击、等待,样样精通。
但你有没有想过:Playwright 这么重,真的有必要吗?
启动浏览器要 2-3 秒,加载页面要等网络空闲,内存占用动辄几百 MB。而实际上,很多动态网站的数据都是通过 Ajax 接口 返回的 JSON------如果能直接找到这个接口,用 requests 抓取不是更快更稳?
今天,我们就来学习降维打击的终极技巧!
🎯 本篇目标
看完这篇,你能做到:
- 理解前后端分离架构(数据从哪来)
- 用浏览器 Network 面板找到数据接口(核心技能)
- 分析接口参数(分页、筛选、排序)
- 用 requests 替换 Playwright(速度提升 10 倍)
验收标准:找到一个动态网站的数据接口,用 requests 采集 200 条数据。
💡 为什么优先找 API?
对比:Playwright vs Requests
| 维度 | Playwright | Requests + API |
|---|---|---|
| 启动速度 | 2-3 秒 | 毫秒级 |
| 内存占用 | 200-500 MB | 5-10 MB |
| 稳定性 | 受页面变化影响大 | 接口相对稳定 |
| 数据干净度 | 需要解析 HTML | 直接拿到 60 秒 |
json
**API 方案:**
找到接口 → 循环请求 10 次(每页 20 条) → 解析 JSON
耗时:约 5 秒
效率提升 **12 倍**!
🔍 实战:用 Network 面板找接口
步骤 1:打开开发者工具
以 Chrome 为例:
- 打开目标网站(如某电商商品列表)
- 按
F12或右键 → 检查 - 切换到 Network(网络) 标签
- 勾选 Preserve log(保留日志)
- 刷新页面
F5
步骤 2:筛选 XHR/Fetch 请求
Network 面板会显示所有请求,我们只关心数据请求:
- 点击 XHR 或 Fetch 筛选器(只显示 Ajax 请求)
- 观察请求列表,找名字像
步骤 3:识别数据接口
点击某个请求,查看 Preview 或 Response 标签:
这是数据接口的特征:
json
{
"code": 0,
"data": {
"items": [
{
"id": "123456",
"title": "商品A",
"price": 99.00
},
{
"id": "123457",
"title": "商品B",
"price": 199.00
}
],
"total": 200
}
}
这不是数据接口(静态资源):
json
https://cdn.example.com/app.js
https://img.example.com/logo.png
步骤 4:复制接口 URL 参数)或 Form Data(POST 参数)
示例:
json
Request URL: https://api.example.com/products/search
Method: GET
Query String Parameters:
page: 1
pageSize: 20
keyword: 手机
sort: price_asc
🛠️ 实战:用 Requests 重写采集逻辑
第一步:验证接口可用性
用 Postman 或 Python 测试:
python
import requests
url = 'https://api.example.com/products/search'
params = {
'page': 1,
'pageSize': 20,
'keyword': '手机'
}
resp = requests.get(url, params=params, timeout=10)
print(resp.status_code)
print(resp.json())
如果返回 200 且有数据,说明接口可用!✅
第二步:分析分页逻辑
常见分页参数:
模式 1:页码 + 每页数量
python
params = {
'page': 1, # 页码(从 1 或 0 开始)
'pageSize': 20 # 每页数量
}
模式 2:偏移量 + 限制数量
python
params = {
'offset': 0, # 偏移量(page-1 * limit)
'limit': 20 # 每次取多少条
}
模式 3:游标分页
python
params = {
'cursor': 'abc123', # 上一页的最后一条 ID
'count': 20
}
第三步:循环采集所有页
python
class APISpider:
"""基于 API 的爬虫(比 Playwright 快 10 倍)"""
def __init__(self, base_url):
self.base_url = base_url
self.session = requests.Session()
# 设置通用 headers(模拟浏览器)
self.session.headers.update({
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
'Accept': 'application/json',
'Referer': 'https://example.com'
})
def fetch_page(self, page, page_size=20):
"""
获取单页数据
Args:
page: 页码
page_size: 每页数量
Returns:
dict: {'items': [...], 'has_more': True/False}
"""
params = {
'page': page,
'pageSize': page_size,
'keyword': '手机' # 根据实际需求调整
}
try:
resp = self.session.get(
self.base_url,
params=params,
timeout=10
)
resp.raise_for_status()
data = resp.json()
# 根据实际接口结构提取数据
items = data.get('data', {}).get('items', [])
total = data.get('data', {}).get('total', 0)
# 判断是否还有下一页
has_more = (page * page_size) < total
return {
'items': items,
'has_more': has_more
}
except Exception as e:
print(f"❌ 请求失败:{e}")
return {'items': [], 'has_more': False}
def crawl_all(self, max_pages=10):
"""采集所有页"""
all_items = []
page = 1
while page <= max_pages:
print(f"\n📄 正在采集第 {page} 页...")
result = self.fetch_page(page)
items = result['items']
if not items:
print("🛑 没有更多数据")
break
all_items.extend(items)
print(f" 本页获得 {len(items)} 条数据(累计 {len(all_items)} 条)")
if not result['has_more']:
print("🛑 已到最后一页")
break
page += 1
time.sleep(1) # 礼貌延迟
print(f"\n✅ 采集完成!共获得 {len(all_items)} 条数据")
return all_items
# 使用示例
if __name__ == '__main__':
spider = APISpider('https://api.example.com/products/search')
items = spider.crawl_all(max_pages=10)
# 保存结果
import json
with open('api_items.json', 'w', encoding='utf-8') as f:
json.dump(items, f, ensure_ascii=False, indent=2)
⚠️ 新手常见坑
坑 1:缺少关键 Headers
现象:用浏览器能请求成功,代码却返回 403 或空数据。
原因:缺少必要的请求头(如 Referer、Token)。
解决:
python
# 在 Network 面板复制所有 Request Headers
headers = {
'User-Agent': '...',
'Referer': 'https://example.com/products',
'X-Requested-With': 'XMLHttpRequest', # 表明是 Ajax 请求
'Authorization': 'Bearer xxx' # 如果需要登录
}
resp = requests.get(url, headers=headers)
坑 2:参数加密或签名
现象:接口需要 sign 参数,不知道怎么生成。
示例:
json
https://api.example.com/search?keyword=手机&sign=a3f8c9d2e1b4...
解决方案:
方案 A(推荐):在 Network 面板找到 JS 文件,搜索 sign
javascript
// 找到生成逻辑,用 Python 重写
function generateSign(params) {
return md5(params.keyword + params.page + 'secret_key');
}
方案 B:用 Playwright 拦截请求,获取完整 URL
python
def handle_route(route):
print(f"📡 拦截到请求:{route.request.url}")
route.continue_()
page.route('**/api/**', handle_route)
page.goto('https://example.com')
方案 C:实在不行,回到 Playwright
python
# 但至少知道数据在哪个接口了,可以针对性等待
坑 3:接口返回数据不完整
现象:网页显示 20 条,接口只返回 10 条。
原因:可能有多个接口(如基础信息 + 详情)。
解决:
python
# 先请求列表接口拿到 ID
list_items = fetch_list()
# 再批量请求详情接口
for item in list_items:
detail = fetch_detail(item['id'])
item.update(detail)
🚀 进阶技巧
技巧 1:用 Playwright 自动找接口
不想手动看 Network?让代码帮你:
python
from playwright.sync_api import sync_playwright
def find_api_requests(url):
"""自动抓取页面的所有 API 请求"""
api_requests = []
def handle_response(response):
# 只关注 JSON 响应
if 'application/json' in response.headers.get('content-type', ''):
api_requests.append({
'url': response.url,
'method': response.request.method,
'status': response.status
})
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_page()
# 监听所有响应
page.on('response', handle_response)
# 打开页面(触发接口请求)
page.goto(url, wait_until='networkidle')
browser.close()
return api_requests
# 使用
apis = find_api_requests('https://example.com/products')
for api in apis:
print(f"🔗 {api['method']} {api['url']}")
技巧 2:字段映射(接口字段 vs 页面展示)
接口返回的字段名可能和页面不一样:
python
def normalize_item(raw_item):
"""统一字段名"""
return {
'title': raw_item.get('productName') or raw_item.get('title'),
'price': raw_item.get('salePrice') or raw_item.get('price'),
'image': raw_item.get('mainImage') or raw_item.get('picUrl'),
'url': f"https://example.com/item/{raw_item['productId']}"
}
技巧 3:批量请求优化
python
import concurrent.futures
def fetch_details_batch(ids, max_workers=5):
"""批量获取详情(并发)"""
with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor:
futures = [executor.submit(fetch_detail, id) for id in ids]
results = [f.result() for f in concurrent.futures.as_completed(futures)]
return results
📊 完整案例:从 Playwright 到 Requests
第一步:用 Playwright 找接口
python
# step1_find_api.py
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch(headless=False)
page = browser.new_page()
# 监听网络请求
def log_request(response):
if '/api/' in response.url and response.status == 200:
print(f"✅ 发现接口:{response.url}")
page.on('response', log_request)
page.goto('https://example.com/products')
input("👀 观察完毕后按回车...")
browser.close()
第二步:用 Requests 重写
python
# step2_use_requests.py
import requests
def crawl_with_api():
items = []
for page in range(1, 11):
url = 'https://api.example.com/products/search'
params = {'page': page, 'pageSize': 20}
resp = requests.get(url, params=params, timeout=10)
data = resp.json()
items.extend(data['data']['items'])
print(f"第 {page} 页:{len(items)} 条")
if not data['data']['hasMore']:
break
return items
items = crawl_with_api()
print(f"✅ 共采集 {len(items)} 条数据")
📝 小结
今天我们学会了降维打击的终极技巧:
- 用 Network 面板找数据接口(核心技能)
- 分析接口参数(分页、筛选、排序)
- 用 Requests 替换 Playwright(速度快 10 倍)
- 处理加密签名(JS 逆向或拦截)
记住核心原则:能用接口就不用浏览器,能用 Requests 就不用 Playwright。先找接口,实在找不到再上自动化浏览器。
🎯 下一章预告
恭喜你完成第 7 章!现在你已经掌握了动态页面采集的核心技能------从 Playwright 基础到接口逆向,从滚动翻页到 API 降维打击。
下一章《第 8 章:项目实战与上线》,我们将进入实战环节------用前面学到的所有技术,搞定两个完整的真实项目:RSS 聚合器和信息聚合站。不仅要能跑,还要能上线、能定时运行、能监控告警!🚀
验收作业:找一个动态网站的数据接口,用 Requests 采集 200 条数据。把接口 URL 和代码发我看看!加油!
🌟 文末
好啦~以上就是本期 《Python爬虫实战》的全部内容啦!如果你在实践过程中遇到任何疑问,欢迎在评论区留言交流,我看到都会尽量回复~咱们下期见!
小伙伴们在批阅的过程中,如果觉得文章不错,欢迎点赞、收藏、关注哦~
三连就是对我写作道路上最好的鼓励与支持! ❤️🔥
📌 专栏持续更新中|建议收藏 + 订阅
专栏 👉 《Python爬虫实战》,我会按照"入门 → 进阶 → 工程化 → 项目落地"的路线持续更新,争取让每一篇都做到:
✅ 讲得清楚(原理)|✅ 跑得起来(代码)|✅ 用得上(场景)|✅ 扛得住(工程化)
📣 想系统提升的小伙伴:强烈建议先订阅专栏,再按目录顺序学习,效率会高很多~

✅ 互动征集
想让我把【某站点/某反爬/某验证码/某分布式方案】写成专栏实战?
评论区留言告诉我你的需求,我会优先安排更新 ✅
⭐️ 若喜欢我,就请关注我叭~(更新不迷路)
⭐️ 若对你有用,就请点赞支持一下叭~(给我一点点动力)
⭐️ 若有疑问,就请评论留言告诉我叭~(我会补坑 & 更新迭代)
免责声明:本文仅用于学习与技术研究,请在合法合规、遵守站点规则与 Robots 协议的前提下使用相关技术。严禁将技术用于任何非法用途或侵害他人权益的行为。