news 2026/7/1 9:00:15

告别零散截图!用Python+Selenium把整个网站一键打包成MHTML文件(附完整代码)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
告别零散截图!用Python+Selenium把整个网站一键打包成MHTML文件(附完整代码)

告别零散截图!用Python+Selenium把整个网站一键打包成MHTML文件(附完整代码)

每次遇到优秀的教程网站或文档站点,你是否也遇到过这样的困扰:想要离线保存却只能一张张截图,或者用浏览器自带的"另存为"功能,结果发现样式错乱、图片丢失?今天,我将分享一个高效解决方案——用Python+Selenium将整个网站完整打包成MHTML文件。这种方法不仅能保留原始布局、图片和样式,还能实现自动化批量处理,特别适合需要离线学习、内容备份或网站分析的场景。

MHTML(MIME HTML)是一种将网页所有资源(HTML、CSS、JavaScript、图片等)打包成单个文件的格式。相比传统截图或HTML保存方式,它有三大优势:

  1. 完整性:保留原始网页的所有元素和交互功能
  2. 便携性:单个文件易于存储和分享
  3. 可读性:无需联网即可完整呈现

1. 环境准备与工具链搭建

1.1 必备工具安装

开始前,请确保已安装以下组件:

pip install selenium beautifulsoup4 tqdm

同时需要下载对应版本的ChromeDriver(与本地Chrome浏览器版本匹配),并将其路径添加到系统环境变量中。

1.2 Chrome DevTools Protocol配置

我们将利用Chrome的开发者工具协议来生成MHTML文件。创建一个新的Python文件,添加以下基础配置:

from selenium import webdriver from selenium.webdriver.chrome.options import Options chrome_options = Options() chrome_options.add_argument("--headless") # 无界面模式 chrome_options.add_argument("--disable-gpu") driver = webdriver.Chrome(options=chrome_options)

2. 核心代码实现与解析

2.1 网站链接抓取模块

首先需要获取目标网站的所有页面链接。这里我们使用递归爬取方式:

import requests from bs4 import BeautifulSoup from urllib.parse import urljoin def get_all_links(base_url, max_depth=3): visited = set() to_visit = {base_url} all_links = set() for _ in range(max_depth): current_url = to_visit.pop() if current_url in visited: continue try: response = requests.get(current_url, timeout=10) soup = BeautifulSoup(response.text, 'html.parser') for link in soup.find_all('a', href=True): absolute_url = urljoin(base_url, link['href']) if absolute_url.startswith(base_url): all_links.add(absolute_url) to_visit.add(absolute_url) visited.add(current_url) except Exception as e: print(f"Error processing {current_url}: {str(e)}") return all_links

2.2 MHTML生成与保存

关键部分是利用Chrome DevTools Protocol捕获页面快照:

def save_as_mhtml(driver, url, output_path): driver.get(url) time.sleep(3) # 等待页面完全加载 try: # 使用CDP命令捕获MHTML result = driver.execute_cdp_cmd('Page.captureSnapshot', {}) with open(output_path, 'w', encoding='utf-8') as f: f.write(result['data']) return True except Exception as e: print(f"Failed to save {url}: {str(e)}") return False

3. 高级功能实现

3.1 处理动态加载内容

现代网站常使用AJAX动态加载内容,我们需要确保这些内容被完整捕获:

from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By def wait_for_dynamic_content(driver, timeout=10): try: WebDriverWait(driver, timeout).until( lambda d: d.execute_script( "return document.readyState === 'complete'" ) ) # 等待常见动态元素 WebDriverWait(driver, timeout).until( EC.presence_of_all_elements_located((By.TAG_NAME, 'img')) ) except Exception as e: print(f"Dynamic content loading timeout: {str(e)}")

3.2 反爬策略应对

针对有反爬机制的网站,可以添加以下配置:

chrome_options.add_argument("user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36") chrome_options.add_argument("--disable-blink-features=AutomationControlled")

4. 完整工作流与优化建议

4.1 主程序整合

将各个模块整合成完整的工作流:

import os import time from tqdm import tqdm def main(): base_url = "https://example.com" # 替换为目标网站 output_dir = "mhtml_output" if not os.path.exists(output_dir): os.makedirs(output_dir) # 初始化浏览器驱动 chrome_options = Options() chrome_options.add_argument("--headless") driver = webdriver.Chrome(options=chrome_options) # 获取所有链接 print("Collecting all page links...") all_links = get_all_links(base_url) print(f"Found {len(all_links)} pages to save") # 保存每个页面为MHTML for link in tqdm(all_links, desc="Saving pages"): filename = link.replace(base_url, "").replace("/", "_") if not filename: filename = "index" output_path = os.path.join(output_dir, f"{filename}.mhtml") save_as_mhtml(driver, link, output_path) driver.quit() print("All pages saved successfully!")

4.2 性能优化技巧

  1. 并行处理:使用多线程加速页面捕获
  2. 断点续传:记录已处理的URL,避免重复工作
  3. 智能等待:根据网络状况动态调整等待时间
from concurrent.futures import ThreadPoolExecutor def process_page(link): # 实现单个页面的处理逻辑 pass with ThreadPoolExecutor(max_workers=4) as executor: list(tqdm(executor.map(process_page, all_links), total=len(all_links)))

5. 实际应用中的问题排查

5.1 常见错误与解决方案

错误类型可能原因解决方案
页面不完整动态内容未加载增加等待时间或添加显式等待
保存失败特殊字符路径对文件名进行清洗处理
超时错误网络延迟调整超时设置或重试机制

5.2 日志记录与调试

建议添加详细的日志记录功能:

import logging logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s', filename='website_saver.log' ) def save_as_mhtml(driver, url, output_path): try: logging.info(f"Processing {url}") # ...原有代码... except Exception as e: logging.error(f"Failed to save {url}: {str(e)}") raise

在实际项目中,我发现最耗时的部分往往是等待动态内容加载。通过分析具体网站的加载模式,可以定制更精确的等待策略。例如,某些单页应用(SPA)需要等待特定DOM元素出现后才算加载完成。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/1 8:59:36

西安GEO公司怎么选?2026年06月选择指南与对比

选择西安GEO公司,核心应考察本地语义理解深度、技术自研能力、服务透明度及合规备案情况。基于公开资料整理,结合现有行业信息,在2026年6月,西安地区具备实质GEO服务能力的公司中,西安行者无疆信息技术有限公司在本地化…

作者头像 李华
网站建设 2026/7/1 8:58:27

Selenium自动化测试框架:从核心原理到工程实践

1. 项目概述:为什么Selenium依然是自动化测试的基石? 如果你在软件测试或者开发领域待过一段时间,几乎不可能没听过Selenium。它就像一个行业里的“老伙计”,从Web 2.0时代一路走来,见证了无数项目的起落。今天&#x…

作者头像 李华
网站建设 2026/7/1 8:54:21

制造业嵌入式 UI 面临的真实挑战

嵌入式 UI 的基础能力平台 在制造业嵌入式领域,Qt 被广泛采用,核心原因在于它为 UI 开发提供了一套稳定、成熟的基础能力平台: 支持多种嵌入式硬件和操作系统 良好的跨平台能力,降低重复开发成本 清晰的架构,便于 U…

作者头像 李华
网站建设 2026/7/1 8:53:45

当 Agent 有了情绪和身体:我用魔珐星云做了一个会共情的具身 Agent

如果 AI 能识别你的情绪,并用眼神、语气和动作回应你——这才是下一代人机交互真正开始的地方。 一、一个让我停下来想的问题 今年我在做一个情绪陪伴相关的 AI 项目。做到一半时,一个问题反复出现:纯文本 Agent 真的能给人“陪伴感”吗&…

作者头像 李华