「AI Agent 全栈开发 50 讲」——从本地模型部署到多智能体系统,一年省 87 万 第 14 课 | 进阶爬虫:API 分析 + Selenium 动态页面
第 14 课 | 进阶爬虫:API 分析 + Selenium 动态页面
第 13 课的 requests 爬虫只能处理静态 HTML。真实世界更复杂:有些网站数据来自 API 接口,有些页面由 JavaScript 动态渲染。这节课,我们攻克这两种场景。
一、业务价值:为什么需要进阶爬虫
1.1 第 13 课的局限性
第 13 课的爬虫很好,但遇到了两个现实问题:
| 场景 | 第 13 课方案 | 问题 |
|---|---|---|
| 虎嗅网新闻列表 | requests + BeautifulSoup | HTML 里只有骨架,数据是 JS 异步加载的 |
| 澎湃新闻滚动加载 | requests + BeautifulSoup | 只能拿到首屏,滚动加载的内容拿不到 |
| 36氪 API 数据 | requests + BeautifulSoup | 明明有 JSON 接口,解析 HTML 费力不讨好 |
进阶爬虫要解决的核心问题:拿到第 13 课拿不到的数据。
1.2 两种进阶方案
二、方案 A:API 接口分析(以虎嗅为例)
2.1 核心思路
很多现代网站采用前后端分离架构:前端只是壳,数据通过 API 接口以 JSON 格式返回。与其解析复杂的 HTML,不如直接请求 API——数据更干净、更高效。
2.2 如何找到 API 接口
打开 Chrome 开发者工具(F12),切换到 Network(网络) 面板,刷新页面:
关键步骤:
- 打开 F12 → Network 面板
- 点击 XHR 或 Fetch 过滤器(只看数据请求)
- 刷新页面,观察请求列表
- 找到返回 JSON 数据的请求(Preview 面板可预览)
- 右键 → Copy → Copy as cURL,分析请求参数
2.3 实战:分析新闻列表 API
以常见的新闻列表 API 为例,典型请求格式:
GET /api/v1/article/list?page=1&page_size=20&category=tech
Headers:
User-Agent: Mozilla/5.0...
Referer: https://www.example.com/
X-Requested-With: XMLHttpRequest
API 分析要点:
| 要素 | 说明 | 如何获取 |
|---|---|---|
| URL 路径 | /api/v1/article/list | Network 面板中查看 |
| 请求方法 | GET / POST | Network 面板中查看 |
| 查询参数 | page, page_size, category | 改变页码/分类,观察参数变化 |
| 请求头 | User-Agent, Referer, Token | 有些 API 需要特殊 Header |
| 分页方式 | 页码 or 游标(cursor) | 翻页时观察 URL 参数变化 |
2.4 代码实现
import requests
def fetch_articles_api(page=1, page_size=20):
"""通过 API 接口获取新闻列表"""
url = "https://api.example.com/v1/article/list"
params = {
"page": page,
"page_size": page_size,
"category": "tech",
}
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
"Referer": "https://www.example.com/",
"X-Requested-With": "XMLHttpRequest",
}
response = requests.get(url, params=params, headers=headers)
data = response.json() # 直接拿到 JSON,无需 BeautifulSoup
articles = []
for item in data.get("data", {}).get("items", []):
articles.append({
"title": item.get("title"),
"summary": item.get("summary"),
"url": item.get("url"),
"pub_time": item.get("publish_time"),
"author": item.get("author", {}).get("name"),
})
return articles
API 方式的优势:
| 对比维度 | HTML 解析 | API 接口 |
|---|---|---|
| 数据格式 | 混乱的 HTML | 干净的 JSON |
| 代码量 | 大量 CSS 选择器 | 几行字典取值 |
| 稳定性 | 网站改版就失效 | API 相对稳定 |
| 数据量 | 只返回显示的 | 可控制分页参数 |
| 网络开销 | 需下载完整 HTML | 只传输数据 |
三、方案 B:Selenium 处理动态页面
3.1 什么时候需要 Selenium
有些页面无法用 API 方式获取,必须用 Selenium:
- 滚动加载:滚动到底部才加载更多内容(如澎湃新闻)
- 点击加载:点击"加载更多"按钮才出现新内容
- 登录后可见:需要登录才能查看的内容
- 复杂交互:需要填写表单、点击按钮等操作
3.2 Selenium 工作原理
Selenium 启动一个真实的 Chrome 浏览器,执行 JavaScript 渲染页面,然后把渲染后的 HTML 返回给 Python。因为执行了 JS,所以滚动加载、动态内容都会被渲染出来。
3.3 安装配置
# 安装 Selenium
uv pip install selenium
# 安装 ChromeDriver(Selenium 4.6+ 自动管理,无需手动下载)
# 如果自动下载失败,手动安装:
# 1. 查看 Chrome 版本:chrome://version
# 2. 下载对应版本:https://chromedriver.chromium.org/
Selenium 4.6+ 的重大改进:内置了 ChromeDriver 自动管理(Selenium Manager),不需要手动下载和配置 PATH。
3.4 核心:等待策略
这是 Selenium 最关键的技巧。页面加载需要时间,如果不等待,拿到的就是空白或半成品页面。
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
driver = webdriver.Chrome()
# ❌ 错误做法:固定 sleep,浪费时间且不可靠
import time; time.sleep(3)
# ✅ 正确做法:显式等待,条件满足立即继续
wait = WebDriverWait(driver, 10) # 最多等 10 秒
element = wait.until(
EC.presence_of_element_located((By.CSS_SELECTOR, ".news-list"))
)
三种等待策略:
| 策略 | 用法 | 场景 |
|---|---|---|
presence_of_element_located | 等待元素出现在 DOM 中 | 列表容器加载完成 |
visibility_of_element_located | 等待元素可见 | 弹窗、模态框 |
element_to_be_clickable | 等待元素可点击 | 按钮、链接 |
3.5 滚动加载实战
def scroll_to_load_all(driver, max_scrolls=10):
"""滚动页面加载全部内容"""
last_height = driver.execute_script("return document.body.scrollHeight")
scroll_count = 0
while scroll_count < max_scrolls:
# 滚动到底部
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
time.sleep(2) # 等待新内容加载
# 检查是否还有新内容
new_height = driver.execute_script("return document.body.scrollHeight")
if new_height == last_height:
break # 高度没变,说明到底了
last_height = new_height
scroll_count += 1
print(f" 滚动 {scroll_count}/{max_scrolls}...")
3.6 完整 Selenium 爬虫示例
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time
# Chrome 无头模式(后台运行,不弹出窗口)
options = Options()
options.add_argument("--headless=new") # 无头模式
options.add_argument("--no-sandbox")
options.add_argument("--disable-gpu")
options.add_argument("--window-size=1920,1080")
options.add_argument("user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64)")
driver = webdriver.Chrome(options=options)
driver.get("https://www.thepaper.cn/")
# 等待新闻列表加载
wait = WebDriverWait(driver, 10)
wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, ".news-list")))
# 滚动加载更多
scroll_to_load_all(driver, max_scrolls=5)
# 提取新闻
news_items = driver.find_elements(By.CSS_SELECTOR, ".news-item")
for item in news_items:
title = item.find_element(By.CSS_SELECTOR, "h2").text
print(f" {title}")
driver.quit()
四、API vs Selenium:如何选择
选择优先级:API 接口 > requests + BeautifulSoup > Selenium
- API 最优:数据干净、速度快、省资源
- requests 次之:轻量、不需要浏览器
- Selenium 最后:重量级、需要浏览器环境,但能处理最复杂的场景
五、实战代码
本课配套代码包含两个实战脚本:
5.1 API 爬虫:huxiu_api.py
cd code/lesson-14-advanced-crawler
uv run huxiu_api.py
通过 API 接口获取新闻列表,存为 JSON 文件。演示了:
- 如何构造 API 请求参数
- 如何处理分页
- 如何解析 JSON 响应
- 数据保存到 SQLite
5.2 Selenium 爬虫:pengpai_selenium.py
cd code/lesson-14-advanced-crawler
uv run pengpai_selenium.py
用 Selenium 爬取动态加载页面,演示了:
- Chrome 无头模式配置
- 显式等待策略
- 滚动加载全部内容
- 提取后存入 SQLite
六、常见问题
6.1 ChromeDriver 版本不匹配
selenium.common.exceptions.SessionNotCreatedException:
This version of ChromeDriver only supports Chrome version XXX
解决:Selenium 4.6+ 会自动下载匹配的 ChromeDriver。如果失败,手动从 ChromeDriver 官网 下载对应版本。
6.2 Selenium 被检测为机器人
一些网站会检测 Selenium 的特征(如 navigator.webdriver 属性)。对抗方法:
options.add_argument("--disable-blink-features=AutomationControlled")
options.add_experimental_option("excludeSwitches", ["enable-automation"])
6.3 API 返回 401/403
说明需要认证。检查:
- 是否需要登录 token(在 Network 面板找 Authorization header)
- 是否需要 Referer 头
- 是否需要 Cookie(从浏览器复制)
七、总结
这节课我们掌握了两种进阶爬虫核心技术:
| 技术 | 适用场景 | 核心技巧 |
|---|---|---|
| API 分析 | 前后端分离网站 | Chrome DevTools → Network → XHR → 复制请求 |
| Selenium | JS 动态渲染页面 | 显式等待 + 滚动加载 + 无头模式 |
加上第 13 课的 requests + BeautifulSoup,你现在拥有了完整的爬虫工具箱——能应对 90% 的数据采集需求。
下一课,我们将解决另一个关键问题:数据清洗与结构化——把爬下来的"脏数据"变成 Agent 能用的高质量知识。
本课代码:code/lesson-14-advanced-crawler/
更多推荐
所有评论(0)