Python爬虫脚本如何抓取动态网页:从原理到实战的完整指南
目录导读
- 什么是动态网页?为什么传统爬虫抓不到?
- 动态网页抓取的三大核心技术对比
- 实战案例:使用Selenium抓取京东商品数据
- 实战案例:使用Playwright抓取微博动态内容
- 高频问题问答(Q&A)
- 常见反爬策略与应对方案
- 总结与最佳实践建议
什么是动态网页?为什么传统爬虫抓不到?
动态网页是指页面内容通过JavaScript、Ajax或WebSocket动态加载渲染,而非服务器直接返回完整的HTML,典型特征包括:

- 页面滚动后加载新内容(无限滚动)
- 点击按钮才显示隐藏数据
- 数据通过XHR接口异步获取
传统爬虫(如requests+BeautifulSoup)只能获取静态HTML源码,而动态网站初次加载时只返回一个空白壳页面,核心数据由JS脚本渲染,浏览器打开淘宝商品列表,真正的内容出现在<div id="app">中,但直接请求curl只会拿到一段空的<div>。
动态网页抓取的三大核心技术对比
| 技术方案 | 原理 | 速度 | 资源开销 | 适合场景 |
|---|---|---|---|---|
| Selenium | 模拟真实浏览器(Chrome) | 较慢(秒级) | 高 | 复杂交互(点击/滚动) |
| Playwright | 新型无头浏览器 | 较快 | 中等 | 现代Web应用(SPA) |
| Pyppeteer | Python版Puppeteer | 快 | 中等 | 需要Chrome DevTools |
| 直接API抓取 | 分析网络请求,模拟XHR | 最快 | 极低 | 有公开接口的站点(需懂抓包) |
选型建议:
- 新手/快速验证:Selenium(但注意性能)
- 生产环境:Playwright(官方已不再推荐Selenium)
- 偏数据研究:先抓包找API(如浏览器F12→Network→XHR)
实战案例:使用Selenium抓取京东商品数据
1 环境准备
pip install selenium==4.15.0 webdriver-manager
webdriver-manager自动管理ChromeDriver版本,避免手动下载。
2 完整代码示例(抓取前5页搜索“Python书籍”)
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
import time
# 1. 启动浏览器(无头模式提高速度)
options = webdriver.ChromeOptions()
options.add_argument('--headless') # 不显示界面
options.add_argument('--no-sandbox')
options.add_argument('--disable-gpu')
driver = webdriver.Chrome(options=options)
# 2. 访问京东,搜索关键词
driver.get("https://www.jd.com/")
search_box = driver.find_element(By.ID, "key")
search_box.send_keys("Python书籍")
search_box.submit() # 模拟回车
# 3. 等待商品列表加载(动态渲染需要时间)
wait = WebDriverWait(driver, 10)
wait.until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, ".gl-item")))
# 4. 循环翻页,提取数据
for page in range(1, 6):
print(f"正在抓取第{page}页...")
items = driver.find_elements(By.CSS_SELECTOR, ".gl-item")
for item in items:
title = item.find_element(By.CSS_SELECTOR, ".p-name em").text
price = item.find_element(By.CSS_SELECTOR, ".p-price i").text
# 处理可能缺失的店铺名(京东动态加载)
try:
shop = item.find_element(By.CSS_SELECTOR, ".p-shop a").text
except:
shop = "无店铺信息"
print(f"标题: {title} | 价格: {price} | 店铺: {shop}")
# 翻页:找到“下一页”按钮
try:
next_btn = driver.find_element(By.CSS_SELECTOR, ".pn-next")
driver.execute_script("arguments[0].click();", next_btn) # 用JS点击避免加载冲突
time.sleep(2) # 等待页面更新
except:
break
driver.quit()
关键点解析:
WebDriverWait解决动态元素未渲染的问题- 使用
execute_script点击按钮绕过普通点击失效问题 - 异步加载的店铺名可能丢失,需加try-except
实战案例:使用Playwright抓取微博动态内容
Playwright由微软开发,支持Chromium/Firefox/Webkit,语法更现代。
1 安装
pip install playwright playwright install chromium # 下载浏览器引擎
2 抓取微博热搜词及热度
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
# 启动浏览器(无头模式)
browser = p.chromium.launch(headless=True)
page = browser.new_page()
page.goto("https://weibo.com/")
# 等待热搜区域加载(动态渲染)
page.wait_for_selector("#pl_top_realtimehot", state="visible")
# 提取热搜列表
hot_items = page.query_selector_all("#pl_top_realtimehot .list_a .td_02")
for item in hot_items[:10]: # 取前10条
title = item.query_selector(".title").inner_text()
hot_num = item.query_selector(".star_num").inner_text() if item.query_selector(".star_num") else "热度未知"
print(f"热搜: {title} | 热度: {hot_num}")
browser.close()
优势:
- 自动等待(
wait_for_selector)内置智能重试 - 支持拦截网络请求(例如获取真实的API响应数据)
高频问题问答(Q&A)
Q1:抓动态网页时,如何处理“滑块验证码”?
A:方案分三级:
① 简单滑块:用ActionChains模拟拖动(Selenium)
② 智能滑块:接打码平台(如2captcha)
③ 破坏性方案:禁用JS让验证码失效(部分网站静态验证码可直接获取)
注意:大规模破解验证码可能触犯法律。
Q2:动态加载的内容滚动到底部才显示,如何抓取?
A:在Selenium中执行JS滚动:
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
time.sleep(2) # 等待新内容加载
Playwright简化版:page.evaluate("window.scrollTo(0, document.body.scrollHeight)")
Q3:网站有反爬,比如检测到Selenium就返回错误?(很多网站会屏蔽selenium特征)
A:使用undetected-chromedriver库替代标准WebDriver:
import undetected_chromedriver as uc driver = uc.Chrome()
或者用Playwright自带的stealth模式:
page = browser.new_page(extra_http_headers={"User-Agent": "Mozilla/5.0 ..."})
常见反爬策略与应对方案
| 反爬手段 | 检测原理 | 应对方案 |
|---|---|---|
| IP频率限制 | 同一IP请求过多 | 代理IP池 + 随机延时 |
| User-Agent检测 | 头信息异常 | 随机UA库(fake-useragent) |
| 浏览器指纹识别 | Canvas/Font/WebGL指纹 | 用playwright-stealth或内置指纹随机 |
| 动态Token验证 | 每个请求需带加密token | 先抓取首页获取token,再拼接请求 |
| 无头浏览器检测 | 检查navigator.webdriver |
修改JS变量(Playwright默认已隐藏) |
总结与最佳实践建议
- 优先抓API:打开浏览器F12→Network→XHR,找到真正的数据接口,用
requests直接调用,比模拟浏览器快10倍以上。 - 合理降噪:动态网页抓取失败的80%原因是等待时间不够,用显式等待(
WebDriverWait)而非sleep(5)。 - 尊重robots.txt:即使是技术爬虫,也建议设置
time.sleep(1)避免打乱服务器。 - 数据存储:推荐写入MongoDB或CSV,避免内存溢出。
- 法律风险:仅抓取公开数据,避免绕过登录/验证码获取付费内容,据《网络安全法》未经授权爬取个人隐私可能违法。
一句话总结:动态网页抓取的核心在于等待渲染完成+模拟用户交互,工具选型上Playwright优于Selenium,而最高效的方案永远是“找到隐藏的API接口”。