页面抓取全流程踩坑指南(从报错卡死到完整抓取视频+批量优化)

在日常爬虫开发中,我们常会遇到「页面渲染依赖JS」「浏览器驱动下载失败」「资源抓取不完整」等问题,尤其是针对富文本文档页面,抓取过程中更容易出现各种异常。本文将完整记录从初始报错到最终实现「页面完整抓取(文字+图片+视频)+ 批量优化视频播放格式」的全流程,包含所有踩坑点、解决方案和最终可直接复用的代码,适合有爬虫需求但遇到环境或渲染问题的开发者参考。

一、需求背景

核心需求:抓取文档页面(指定链接从本地文件读取),要求:

    1. 能获取 JS 渲染后的真实页面内容(目标是 id 为 pageRoot 的节点);
    1. 完整抓取页面中的图片和视频资源,确保离线可查看;
    1. HTML 文件统一放在 page_contents 目录下,资源文件归到子目录 media 中;
    1. 批量优化 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>

四、关键注意事项(避坑重点)

  1. 环境适配:Windows 系统优先使用自带 Edge 浏览器,避免 ChromeDriver 下载和配置问题,无需额外安装驱动;

  2. 渲染等待:页面依赖 JS 渲染,必须使用 WebDriverWait 等待目标节点加载,避免未渲染完成就抓取;

  3. 资源处理:图片/视频需下载到本地,并替换 HTML 中的路径为相对路径,否则离线无法查看;

  4. 网络问题:国内网络无法下载 Chromium、ChromeDriver 等资源时,优先选择系统原生工具(如 Edge),避免依赖外部下载;

  5. 批量处理:正则匹配时使用非贪婪模式(.*?),避免匹配范围过大,导致 HTML 结构错乱。

五、总结

本次页面抓取从初始的依赖报错、浏览器启动卡死,到最终实现完整抓取和格式优化,核心是「避开外部资源下载依赖」「确保页面渲染完成」「规范资源路径」。文中所有代码均经过实测,可直接复用,适用于类似的 JS 渲染页面抓取需求。

如果遇到其他爬虫相关问题(如页面反爬、资源无法提取),可根据具体报错调整代码,重点排查「渲染等待」「网络环境」「节点匹配」三个核心环节,基本能解决大部分常见问题。

相关推荐
林姜泽樾3 小时前
Python爬虫基础第一章,JSON
爬虫·python·网络爬虫
@zulnger21 小时前
自动化测试框架:Selenium剖析(1.1)
selenium·测试工具
独断万古他化1 天前
Selenium 实战 —— 抽奖系统 UI 自动化测试框架搭建
java·selenium·测试工具·ui·自动化·测试
老神在在0012 天前
【Selenium 自动化精讲】浏览器弹窗与登录界面的本质区别 & 实操指南
javascript·学习·selenium·测试工具·自动化
测试19982 天前
python+selenium 定位到元素,无法点击的解决方法
自动化测试·软件测试·python·selenium·测试工具·测试用例·压力测试
狗都不学爬虫_2 天前
JS逆向 - Akamai阿迪达斯(三次) 补环境、纯算
javascript·爬虫·python·网络爬虫·wasm
程序员杰哥2 天前
Web UI自动化测试之PO篇
自动化测试·软件测试·python·selenium·测试工具·ui·测试用例
心疼你的一切3 天前
【矛与盾的博弈:ZLibrary反爬机制实战分析与绕过技术全解析】
人工智能·爬虫·python·网络爬虫