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

📅 2026/7/1 9:00:24
告别零散截图!用Python+Selenium把整个网站一键打包成MHTML文件(附完整代码)
告别零散截图用PythonSelenium把整个网站一键打包成MHTML文件附完整代码每次遇到优秀的教程网站或文档站点你是否也遇到过这样的困扰想要离线保存却只能一张张截图或者用浏览器自带的另存为功能结果发现样式错乱、图片丢失今天我将分享一个高效解决方案——用PythonSelenium将整个网站完整打包成MHTML文件。这种方法不仅能保留原始布局、图片和样式还能实现自动化批量处理特别适合需要离线学习、内容备份或网站分析的场景。MHTMLMIME HTML是一种将网页所有资源HTML、CSS、JavaScript、图片等打包成单个文件的格式。相比传统截图或HTML保存方式它有三大优势完整性保留原始网页的所有元素和交互功能便携性单个文件易于存储和分享可读性无需联网即可完整呈现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(optionschrome_options)2. 核心代码实现与解析2.1 网站链接抓取模块首先需要获取目标网站的所有页面链接。这里我们使用递归爬取方式import requests from bs4 import BeautifulSoup from urllib.parse import urljoin def get_all_links(base_url, max_depth3): 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, timeout10) soup BeautifulSoup(response.text, html.parser) for link in soup.find_all(a, hrefTrue): 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(fError processing {current_url}: {str(e)}) return all_links2.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, encodingutf-8) as f: f.write(result[data]) return True except Exception as e: print(fFailed to save {url}: {str(e)}) return False3. 高级功能实现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, timeout10): 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(fDynamic content loading timeout: {str(e)})3.2 反爬策略应对针对有反爬机制的网站可以添加以下配置chrome_options.add_argument(user-agentMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36) chrome_options.add_argument(--disable-blink-featuresAutomationControlled)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(optionschrome_options) # 获取所有链接 print(Collecting all page links...) all_links get_all_links(base_url) print(fFound {len(all_links)} pages to save) # 保存每个页面为MHTML for link in tqdm(all_links, descSaving 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 性能优化技巧并行处理使用多线程加速页面捕获断点续传记录已处理的URL避免重复工作智能等待根据网络状况动态调整等待时间from concurrent.futures import ThreadPoolExecutor def process_page(link): # 实现单个页面的处理逻辑 pass with ThreadPoolExecutor(max_workers4) as executor: list(tqdm(executor.map(process_page, all_links), totallen(all_links)))5. 实际应用中的问题排查5.1 常见错误与解决方案错误类型可能原因解决方案页面不完整动态内容未加载增加等待时间或添加显式等待保存失败特殊字符路径对文件名进行清洗处理超时错误网络延迟调整超时设置或重试机制5.2 日志记录与调试建议添加详细的日志记录功能import logging logging.basicConfig( levellogging.INFO, format%(asctime)s - %(levelname)s - %(message)s, filenamewebsite_saver.log ) def save_as_mhtml(driver, url, output_path): try: logging.info(fProcessing {url}) # ...原有代码... except Exception as e: logging.error(fFailed to save {url}: {str(e)}) raise在实际项目中我发现最耗时的部分往往是等待动态内容加载。通过分析具体网站的加载模式可以定制更精确的等待策略。例如某些单页应用(SPA)需要等待特定DOM元素出现后才算加载完成。