
Python 3.12 requests 实现网页单文件保存3种方案对比与自动化脚本当我们需要将网页内容完整保存下来时浏览器插件虽然方便但在自动化场景中往往力不从心。作为开发者我们更希望用代码实现这一功能将其集成到自动化流程中。本文将介绍三种基于Python的方案从简单到复杂满足不同场景下的需求。1. 基础方案requests BeautifulSoup对于静态网页最简单的方案是使用requests获取HTML内容再用BeautifulSoup处理资源链接。这个方案轻量快速适合大多数内容型网站。首先安装必要的库pip install requests beautifulsoup4核心代码如下import os import requests from bs4 import BeautifulSoup from urllib.parse import urljoin, urlparse def save_webpage(url, output_diroutput): # 创建输出目录 os.makedirs(output_dir, exist_okTrue) # 获取网页内容 headers {User-Agent: Mozilla/5.0} response requests.get(url, headersheaders) response.raise_for_status() # 解析HTML soup BeautifulSoup(response.text, html.parser) # 处理资源链接 for tag in soup.find_all([img, link, script]): if tag.name img and tag.get(src): tag[src] download_resource(urljoin(url, tag[src]), output_dir) elif tag.name link and tag.get(href) and stylesheet in tag.get(rel, []): tag[href] download_resource(urljoin(url, tag[href]), output_dir) elif tag.name script and tag.get(src): tag[src] download_resource(urljoin(url, tag[src]), output_dir) # 保存HTML文件 output_path os.path.join(output_dir, index.html) with open(output_path, w, encodingutf-8) as f: f.write(str(soup)) return output_path def download_resource(resource_url, output_dir): try: response requests.get(resource_url) if response.status_code 200: # 从URL提取文件名 parsed urlparse(resource_url) filename os.path.basename(parsed.path) or resource.bin filepath os.path.join(output_dir, filename) # 保存资源文件 with open(filepath, wb) as f: f.write(response.content) return filename except Exception as e: print(fFailed to download {resource_url}: {e}) return resource_url # 失败时返回原始URL优点实现简单依赖少对静态网页支持良好资源文件与HTML分离便于管理缺点无法处理JavaScript渲染的内容对动态加载的资源支持有限需要手动处理各种资源类型提示此方案适合保存新闻、文档等静态内容对于现代SPA应用效果不佳。2. 进阶方案Selenium自动化浏览器当网页内容由JavaScript动态生成时我们需要一个真正的浏览器环境来渲染页面。Selenium可以自动化浏览器操作获取渲染后的完整HTML。安装依赖pip install selenium还需要下载对应浏览器的WebDriver这里以Chrome为例from selenium import webdriver from selenium.webdriver.chrome.service import Service from selenium.webdriver.chrome.options import Options import base64 def save_webpage_selenium(url, output_filepage.html): chrome_options Options() chrome_options.add_argument(--headless) # 无头模式 chrome_options.add_argument(--disable-gpu) # 初始化浏览器 driver webdriver.Chrome(serviceService(chromedriver), optionschrome_options) driver.get(url) # 等待页面加载完成 driver.implicitly_wait(10) # 最多等待10秒 # 获取页面源码 html driver.page_source # 处理内联资源 html inline_resources(driver, html) # 保存文件 with open(output_file, w, encodingutf-8) as f: f.write(html) driver.quit() return output_file def inline_resources(driver, html): # 将CSS和图片转为内联 soup BeautifulSoup(html, html.parser) # 内联CSS for link in soup.find_all(link, relstylesheet): try: css_url link[href] if not css_url.startswith((http, //)): css_url urljoin(driver.current_url, css_url) css_content requests.get(css_url).text style_tag soup.new_tag(style) style_tag.string css_content link.replace_with(style_tag) except Exception as e: print(fFailed to inline CSS: {e}) # 内联图片 for img in soup.find_all(img): try: img_url img[src] if not img_url.startswith((http, //)): img_url urljoin(driver.current_url, img_url) img_data requests.get(img_url).content img_base64 base64.b64encode(img_data).decode(utf-8) img[src] fdata:image/png;base64,{img_base64} except Exception as e: print(fFailed to inline image: {e}) return str(soup)优点能处理JavaScript渲染的内容模拟真实浏览器环境可以执行交互操作后再保存缺点需要安装浏览器和驱动性能开销大资源处理复杂注意Selenium方案适合需要交互或动态内容的场景但维护成本较高。3. 专业方案Playwright无头浏览器Playwright是微软推出的新一代浏览器自动化工具比Selenium更强大、更稳定。它支持多种浏览器并提供丰富的API来处理网页内容。安装Playwrightpip install playwright playwright install # 安装浏览器二进制文件实现代码from playwright.sync_api import sync_playwright import os def save_webpage_playwright(url, output_filepage.html): with sync_playwright() as p: # 启动浏览器 browser p.chromium.launch(headlessTrue) page browser.new_page() # 导航到页面 page.goto(url, wait_untilnetworkidle) # 等待网络空闲 # 获取页面HTML html page.content() # 保存为单个HTML文件 html make_single_file(page, html) # 写入文件 with open(output_file, w, encodingutf-8) as f: f.write(html) browser.close() return output_file def make_single_file(page, html): # 使用Playwright的evaluate方法在页面上下文中执行JavaScript # 将所有资源内联到HTML中 html page.evaluate(async (html) { const doc new DOMParser().parseFromString(html, text/html); // 内联CSS for (const link of doc.querySelectorAll(link[relstylesheet])) { try { const response await fetch(link.href); const css await response.text(); const style document.createElement(style); style.textContent css; link.replaceWith(style); } catch (e) { console.warn(Failed to inline CSS:, e); } } // 内联图片 for (const img of doc.querySelectorAll(img)) { try { const response await fetch(img.src); const blob await response.blob(); const reader new FileReader(); const dataUrl await new Promise(resolve { reader.onload () resolve(reader.result); reader.readAsDataURL(blob); }); img.src dataUrl; } catch (e) { console.warn(Failed to inline image:, e); } } // 返回处理后的HTML return new XMLSerializer().serializeToString(doc); }, html) return html优点支持所有现代浏览器API设计更合理执行更稳定内置等待机制减少竞态条件可以处理最复杂的SPA应用缺点需要下载浏览器二进制文件学习曲线略陡峭4. 三种方案对比与选型指南为了帮助开发者选择合适的方案我们整理了一个对比表格特性requestsBeautifulSoupSeleniumPlaywright静态网页支持★★★★★★★★★★★★★★★动态内容支持★☆☆☆☆★★★★☆★★★★★执行速度快慢中等资源消耗低高中等安装复杂度低中等中等维护成本低高中等适合场景内容归档测试/爬虫生产环境选型建议如果目标网页是纯静态内容如文档、新闻选择requestsBeautifulSoup方案如果需要处理简单JavaScript交互选择Selenium方案如果是复杂SPA应用或生产环境选择Playwright方案5. 自动化脚本实现结合上述方案我们可以创建一个可配置的自动化脚本根据需求选择不同的保存方式import argparse from pathlib import Path def main(): parser argparse.ArgumentParser(description网页保存工具) parser.add_argument(url, help要保存的网页URL) parser.add_argument(-o, --output, defaultoutput.html, help输出文件路径) parser.add_argument(-m, --mode, choices[basic, selenium, playwright], defaultbasic, help保存模式) args parser.parse_args() print(f正在保存 {args.url}...) if args.mode basic: output_dir Path(args.output).parent save_webpage(args.url, output_dir) elif args.mode selenium: save_webpage_selenium(args.url, args.output) elif args.mode playwright: save_webpage_playwright(args.url, args.output) print(f网页已保存到 {args.output}) if __name__ __main__: main()使用示例# 保存静态网页 python webpage_saver.py https://example.com -o example.html -m basic # 保存动态网页 python webpage_saver.py https://example.com/spa -o spa.html -m playwright这个脚本可以轻松集成到CI/CD流程或定时任务中实现网页内容的自动归档。我在实际项目中使用Playwright方案每天自动归档数百个网页稳定性非常好即使面对最复杂的React/Vue应用也能可靠工作。