在日常爬虫开发中,我们常会遇到「页面渲染依赖JS」「浏览器驱动下载失败」「资源抓取不完整」等问题,尤其是针对富文本文档页面,抓取过程中更容易出现各种异常。本文将完整记录从初始报错到最终实现「页面完整抓取(文字+图片+视频)+ 批量优化视频播放格式」的全流程,包含所有踩坑点、解决方案和最终可直接复用的代码,适合有爬虫需求但遇到环境或渲染问题的开发者参考。
一、需求背景
核心需求:抓取文档页面(指定链接从本地文件读取),要求:
-
- 能获取 JS 渲染后的真实页面内容(目标是 id 为 pageRoot 的节点);
-
- 完整抓取页面中的图片和视频资源,确保离线可查看;
-
- HTML 文件统一放在 page_contents 目录下,资源文件归到子目录 media 中;
-
- 批量优化 HTML 中的视频播放格式,将复杂视频节点替换为简洁播放器。
初始环境:Windows 系统、Python 3.13,无额外配置浏览器驱动,网络环境无法正常下载外部驱动资源。
二、全流程踩坑与解决方案(按报错顺序)
坑点1:依赖缺失报错(lxml.html.clean 模块找不到)
报错信息
plain
ImportError: lxml.html.clean module is now a separate project lxml_html_clean.
Install lxml[html_clean] or lxml_html_clean directly.
原因分析
新版 lxml 已将 HTML 清理功能拆分到独立包,原代码中使用的 requests-html 依赖该模块,导致导入失败。
解决方案
执行以下命令安装缺失依赖,二选一即可(推荐第二种,更稳定):
bash
pip install lxml_html_clean
# 或
pip install "lxml[html_clean]"
坑点2:Chromium 下载失败(requests-html 启动卡死)
报错信息
plain
[INFO] Starting Chromium download.
❌ 失败:Chromium downloadable not found at https://storage.googleapis.com/chromium-browser-snapshots/Win_x64/1181205/chrome-win.zip: Received <?xml version='1.0' encoding='UTF-8'?><Error><Code>NoSuchKey</Code>...
原因分析
requests-html 启动时会自动下载 Chromium 浏览器内核,但国内网络无法访问谷歌存储地址,导致下载失败、程序卡死。
解决方案
放弃 requests-html,尝试其他轻量 JS 渲染工具,先后测试 dryscrape、pyppeteer,均因「需要下载浏览器内核」「编译依赖缺失」(如 dryscrape 依赖 webkit_server,需 qmake 编译环境)再次报错,最终转向更稳定的 Selenium + 本地浏览器方案。
坑点3:Selenium 启动浏览器卡死(无 ChromeDriver)
报错现象
执行 Selenium 代码时,卡在「启动浏览器」步骤,无任何报错输出,排查后发现是缺少 ChromeDriver,且网络无法自动下载驱动。
解决方案
放弃 Chrome 浏览器,改用 Windows 系统自带的 Edge 浏览器(无需手动安装驱动,系统默认集成),优化代码强制使用本地 Edge,避免驱动下载步骤。
坑点4:Edge 启动失败(驱动位置异常)
报错信息
plain
[错误] Edge 启动失败:Message: Unable to obtain driver for MicrosoftEdge; For documentation on this error, please visit: https://www.selenium.dev/documentation/webdriver/troubleshooting/errors/driver_location
原因分析
新版 webdriver-manager 已删除 EdgeDriverManager 类,原代码中使用该类导致导入失败,且 Edge 驱动未正确关联。
解决方案
删除 webdriver-manager 相关依赖,直接使用 Edge 原生启动方式,无需额外驱动下载,代码中添加 Edge 启动参数,避免日志冗余和启动异常。
坑点5:pageRoot 节点未找到(页面未加载完成)
报错现象
浏览器启动成功,但抓取时提示「未找到 pageRoot」,实际页面确有该节点,排查后发现是页面 JS 未渲染完成,程序就已开始抓取。
解决方案
使用 Selenium 的 WebDriverWait 等待机制,设置最长 30 秒等待时间,确保 pageRoot 节点加载完成后再进行抓取,同时添加页面滚动操作,触发懒加载资源(图片、视频)。
坑点6:图片/视频未抓取(资源路径未替换)
问题现象
成功抓取 HTML 内容,但打开后图片、视频无法显示,原因是抓取的是在线资源路径,未下载到本地,且路径未替换为本地相对路径。
解决方案
添加资源下载函数,遍历页面中的 img 和 video 节点,提取真实资源地址,下载到统一的 media 子目录,同时将 HTML 中的在线路径替换为本地相对路径,确保离线可查看。
坑点7:视频播放格式复杂(需批量优化)
问题现象
抓取的 HTML 中,视频节点包含多余属性和子节点(如 、),播放体验不佳,需要批量替换为简洁的视频播放器格式。
解决方案
编写正则匹配逻辑,遍历所有 HTML 文件,找到包含视频节点的 block-root div,提取真实视频地址(剔除 URL 多余参数),替换为指定格式的简洁视频播放器。
三、最终可复用代码(按功能分类)
以下代码均经过实测,可直接复制使用,按需求选择对应脚本,放在对应目录运行即可。
1. 页面完整抓取脚本(含图片+视频+路径规范)
功能:读取本地链接文件,抓取页面,保存 HTML 到 page_contents 目录,图片/视频下载到 media 子目录,确保离线可查看。
python
import os
import time
import requests
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
# ===================== 配置 =====================
MISSING_LINKS_FILE = r'C:\Users\Administrator\Desktop\ceshi\wuk\missing_links.txt'
OUTPUT_DIR = r'C:\Users\Administrator\Desktop\ceshi\wuk\page_contents'
MEDIA_DIR = os.path.join(OUTPUT_DIR, "media") # 所有资源统一放这里
os.makedirs(OUTPUT_DIR, exist_ok=True)
os.makedirs(MEDIA_DIR, exist_ok=True)
HEADERS = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
}
def read_links():
print("[日志] 读取链接文件...")
links = []
with open(MISSING_LINKS_FILE, 'r', encoding='utf-8') as f:
for line in f:
line = line.strip()
if not line:
continue
parts = line.split('\t')
if len(parts) >= 2:
lid, url = parts[0], parts[1]
links.append((lid, url))
print(f"[日志] 读取完成,共 {len(links)} 个链接")
return links
def get_edge():
print("\n[日志] 启动 Edge 浏览器...")
edge_options = webdriver.EdgeOptions()
edge_options.add_argument("--headless=new")
edge_options.add_argument("--disable-gpu")
edge_options.add_argument("--no-sandbox")
edge_options.add_experimental_option('excludeSwitches', ['enable-logging'])
driver = webdriver.Edge(options=edge_options)
driver.implicitly_wait(10)
print("[日志] Edge 启动成功 ✅")
return driver
# 下载图片/视频到统一的 media 文件夹
def download_media(url):
try:
if not url or url.startswith("data:"):
return None
# 提取文件名
name = os.path.basename(url.split("?")[0].split("#")[0])
local_path = os.path.join(MEDIA_DIR, name)
if not os.path.exists(local_path):
resp = requests.get(url, headers=HEADERS, timeout=20)
with open(local_path, "wb") as f:
f.write(resp.content)
# 返回相对路径,HTML 能找到图片
return f"media/{name}"
except:
return None
def main():
print("="*60)
print(" 完整抓取(HTML统一存放 + 资源归整)")
print("="*60)
links = read_links()
driver = get_edge()
for idx, (lid, url) in enumerate(links, 1):
html_file = os.path.join(OUTPUT_DIR, f"{lid}.html")
print(f"\n===== [{idx}/{len(links)}] 抓取中 =====")
print(f"链接:{url}")
print(f"保存HTML:{html_file}")
try:
driver.get(url)
# 等待 pageRoot 加载
print("[日志] 等待 pageRoot 加载...")
wait = WebDriverWait(driver, 30)
page_root = wait.until(
EC.presence_of_element_located((By.ID, "pageRoot"))
)
# 滚动加载所有图片视频
print("[日志] 加载所有图片、视频...")
driver.execute_script("window.scrollTo(0, document.body.scrollHeight)")
time.sleep(3)
# 获取页面HTML
html = page_root.get_attribute("outerHTML")
# 替换所有图片
imgs = driver.find_elements(By.CSS_SELECTOR, "#pageRoot img")
for img in imgs:
src = img.get_attribute("src")
new_path = download_media(src)
if new_path:
html = html.replace(src, new_path)
# 替换所有视频
videos = driver.find_elements(By.CSS_SELECTOR, "#pageRoot video")
for v in videos:
src = v.get_attribute("src")
new_path = download_media(src)
if new_path:
html = html.replace(src, new_path)
# 生成可离线打开的页面
final_html = f'''
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<title>{lid}</title>
<style>
body {{ padding: 30px; background: #fff; }}
</style>
</head>
<body>{html}</body>
</html>
'''
with open(html_file, 'w', encoding='utf-8') as f:
f.write(final_html)
print("[结果] ✅ 抓取成功:文字+图片+视频")
except Exception as e:
print(f"[错误] 抓取失败:{str(e)[:60]}")
time.sleep(2)
driver.quit()
print("\n🎉 所有任务完成!")
if __name__ == "__main__":
main()
2. 批量优化 HTML 视频播放格式脚本
功能:遍历当前目录下所有 HTML 文件,将包含视频的 block-root div 替换为简洁播放器,自动提取真实视频地址并剔除多余参数。
python
import os
import re
# 遍历当前目录下所有 .html 文件
for filename in os.listdir("."):
if filename.endswith(".html"):
print(f"正在处理:{filename}")
with open(filename, "r", encoding="utf-8") as f:
content = f.read()
# 1. 匹配 block-root 整块 div(非贪婪匹配)
pattern = re.compile(
r'<div data-area="block-root" class="node-container[^>]*>.*?'
r'<video playsinline[^>]*>.*?<source src="([^"]+)"[^>]*>.*?</video>.*?'
r'</div>',
re.DOTALL
)
# 2. 替换成简洁视频播放器
def replace_block(match):
video_url = match.group(1)
# 只保留真实 mp4 地址,去掉后面参数
mp4_url = video_url.split("?")[0].split("#")[0]
return f'<video src="{mp4_url}" style="width:90%;" controls muted loop></video>'
new_content = pattern.sub(replace_block, content)
# 保存
with open(filename, "w", encoding="utf-8") as f:
f.write(new_content)
print("✅ 所有 HTML 处理完成!视频已全部替换为简洁播放器")
3. 简易视频播放 HTML 示例(备用)
功能:单独播放指定视频地址,可直接保存为 HTML 文件打开使用。
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>视频播放</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { padding: 20px; background: #f5f5f5; }
.video-box {
max-width: 1000px;
margin: 0 auto;
}
video {
width: 100%;
height: auto;
outline: none;
}
</style>
</head>
<body>
<div class="video-box">
<!-- 👇 把这里的地址换成你的视频链接(支持 mp4 最稳) -->
<video src="https://你的视频地址.mp4" controls autoplay muted loop></video>
</div>
</body>
</html>
四、关键注意事项(避坑重点)
-
环境适配:Windows 系统优先使用自带 Edge 浏览器,避免 ChromeDriver 下载和配置问题,无需额外安装驱动;
-
渲染等待:页面依赖 JS 渲染,必须使用 WebDriverWait 等待目标节点加载,避免未渲染完成就抓取;
-
资源处理:图片/视频需下载到本地,并替换 HTML 中的路径为相对路径,否则离线无法查看;
-
网络问题:国内网络无法下载 Chromium、ChromeDriver 等资源时,优先选择系统原生工具(如 Edge),避免依赖外部下载;
-
批量处理:正则匹配时使用非贪婪模式(.*?),避免匹配范围过大,导致 HTML 结构错乱。
五、总结
本次页面抓取从初始的依赖报错、浏览器启动卡死,到最终实现完整抓取和格式优化,核心是「避开外部资源下载依赖」「确保页面渲染完成」「规范资源路径」。文中所有代码均经过实测,可直接复用,适用于类似的 JS 渲染页面抓取需求。
如果遇到其他爬虫相关问题(如页面反爬、资源无法提取),可根据具体报错调整代码,重点排查「渲染等待」「网络环境」「节点匹配」三个核心环节,基本能解决大部分常见问题。