Python实现网页自动化归档与长截图工具开发
1. 项目背景与核心价值最近在整理技术文档时发现一个痛点很多优质的技术文档站点会突然关闭或改版导致之前收藏的链接失效。更麻烦的是有些文档内容需要以完整长图形式保存便于分享或打印。市面上的网页保存工具要么功能单一要么操作复杂于是决定自己用Python开发一个轻量级解决方案。这个工具的核心功能很简单将指定文档站点生成完整快照包括HTML、CSS、JS等资源同时自动生成整个页面的无缝长截图支持定时自动归档和版本对比相比传统截图工具这个方案有三大优势完整保留原始样式和交互元素如可折叠目录长图自动拼接无需手动滚动截图支持增量更新和差异对比2. 技术方案选型2.1 核心组件对比经过技术调研最终确定以下技术栈组合功能需求可选方案最终选择选择理由网页渲染Selenium/PlaywrightPlaywright更快的渲染速度原生支持无头浏览器和PDF/截图生成长图拼接Puppeteer/PillowPlaywrightPillowPlaywright负责分块截图Pillow处理图像合并兼容性更好资源下载requests/scrapyrequestsparsel轻量级组合parsel支持XPath和CSS选择器定时任务APScheduler/crontabAPScheduler纯Python方案跨平台兼容差异对比difflib/jsondiffdhashImageChops图像哈希对比像素级差异分析更适合视觉化内容2.2 关键技术实现路径整个处理流程分为四个阶段初始化阶段使用Playwright启动Chromium浏览器实例设置1280px的固定视窗宽度保证排版一致性注入自定义CSS强制显示所有折叠内容解决动态加载问题资源抓取阶段主HTML下载使用requestsretry机制应对网络波动静态资源采用异步下载器aiohttp实现URL规范化处理解决相对路径问题长图生成阶段通过page.evaluate()获取页面实际高度按2000px高度分块截图避免内存溢出用Pillow的Image.paste()进行垂直拼接添加页眉页脚元信息URL时间戳版本管理阶段使用SQLite存储抓取元数据文件存储采用{domain}/{date}/的目录结构差异对比采用感知哈希dhash算法3. 详细实现步骤3.1 环境准备推荐使用Python 3.8环境依赖安装pip install playwright pillow requests parsel apscheduler numpy playwright install # 安装浏览器驱动3.2 核心代码实现网页快照模块async def save_snapshot(url, output_dir): async with async_playwright() as p: browser await p.chromium.launch() context await browser.new_context(viewport{width:1280,height:800}) page await context.new_page() # 拦截静态资源请求 async def handle_route(route): await route.continue_() resource await route.request.response() if resource: save_resource(await resource.body(), route.request.url) await page.route(**/*, handle_route) await page.goto(url, wait_untilnetworkidle) await page.evaluate(() { // 强制展开所有折叠内容 document.querySelectorAll([aria-expandedfalse]).forEach(el el.click()); }) # 保存主HTML html await page.content() with open(f{output_dir}/index.html, w) as f: f.write(html) await browser.close()长图生成模块def capture_fullpage(url, output_path): with sync_playwright() as p: browser p.chromium.launch() page browser.new_page(viewport{width:1280, height:800}) page.goto(url, wait_untilnetworkidle) # 获取页面实际高度 total_height page.evaluate(() document.body.scrollHeight) viewport_height page.viewport_size[height] images [] for y in range(0, total_height, viewport_height): # 分块截图 image_path f/tmp/part_{y}.png page.evaluate(fwindow.scrollTo(0, {y})) page.screenshot(pathimage_path, clip{ x:0, y:0, width:1280, height:min(viewport_height, total_height-y) }) images.append(Image.open(image_path)) # 垂直拼接 full_image Image.new(RGB, (1280, total_height)) y_offset 0 for img in images: full_image.paste(img, (0, y_offset)) y_offset img.size[1] img.close() full_image.save(output_path) browser.close()3.3 定时任务集成from apscheduler.schedulers.blocking import BlockingScheduler def job(url, output_base): date_str datetime.now().strftime(%Y%m%d) output_dir f{output_base}/{urlparse(url).netloc}/{date_str} os.makedirs(output_dir, exist_okTrue) asyncio.run(save_snapshot(url, output_dir)) capture_fullpage(url, f{output_dir}/fullpage.png) scheduler BlockingScheduler() scheduler.add_job(job, cron, args[target_url, output_path], day_of_week0-6, hour3) # 每天凌晨3点执行 scheduler.start()4. 实战优化技巧4.1 性能调优方案并发控制限制同时打开的浏览器实例数建议≤3静态资源下载使用Semaphore控制并发量sem asyncio.Semaphore(5) async with sem: await download_resource(url)缓存利用对静态资源URL计算MD5作为文件名实现304 Not Modified检测if os.path.exists(cache_path): with open(cache_path, rb) as f: etag hashlib.md5(f.read()).hexdigest() headers {If-None-Match: etag}智能等待策略# 混合等待条件 await page.wait_for_selector(article, stateattached) await page.wait_for_function( () document.readyState complete window.jQuery ! undefined jQuery.active 0 )4.2 常见问题解决方案问题1动态内容加载不全解决方案注入强制渲染脚本// 滚动触发懒加载 window.scrollBy(0, 100); setTimeout(() { window.scrollBy(0, -100); }, 500);问题2截图出现空白间隙解决方案调整滚动步长与截图高度比例scroll_step viewport_height - 50 # 保留50px重叠区域 for y in range(0, total_height, scroll_step): ...问题3反爬虫机制拦截解决方案伪装常规浏览器特征context await browser.new_context( user_agentMozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36..., localezh-CN, timezone_idAsia/Shanghai )5. 扩展应用场景5.1 企业级增强方案对于团队协作场景可以扩展以下功能API服务化from fastapi import FastAPI app FastAPI() app.post(/archive) async def create_archive(url: str): task_id str(uuid.uuid4()) asyncio.create_task(background_archive(url, task_id)) return {task_id: task_id}可视化对比def generate_diff(old_img, new_img): diff ImageChops.difference(old_img, new_img) diff diff.convert(L).point(lambda x: 255 if x 30 else 0) return diff自动生成报告def generate_report(url, changes): pdf FPDF() pdf.add_page() pdf.set_font(Arial, size12) pdf.cell(200, 10, txtfArchiving Report for {url}, ln1) for change in changes: pdf.cell(200, 10, txtchange, ln1) pdf.output(report.pdf)5.2 个人知识管理集成Obsidian插件方案module.exports async function(url) { const {execSync} require(child_process) const output execSync(python archiver.py ${url}) this.app.vault.create(Archives/${Date.now()}.md, output) }Notion自动化集成from notion_client import Client notion Client(authos.environ[NOTION_TOKEN]) def upload_to_notion(url, img_path): with open(img_path, rb) as f: file notion.upload_file(f) notion.pages.create( parent{database_id: DB_ID}, properties{Title: {title: [{text: {content: url}}]}}, children[{type: image, image: {file: {url: file.url}}}] )6. 维护与迭代建议监控指标设计成功率监控记录每次抓取的HTTP状态码质量检测通过OCR识别截图中的404等错误文本性能统计记录各阶段耗时网络请求、渲染、截图等异常处理机制async def safe_capture(url): try: return await capture_page(url) except PlaywrightTimeoutError: await page.reload() return await capture_page(url) except Exception as e: send_alert(fCapture failed: {str(e)}) raise自动化测试方案pytest.mark.asyncio async def test_snapshot(): test_url https://example.com await save_snapshot(test_url, /tmp/test) assert os.path.exists(/tmp/test/index.html) assert os.path.getsize(/tmp/test/index.html) 1024这个项目在实际使用中给我最大的启示是自动化归档不仅要考虑技术实现更需要设计合理的内容组织结构。我现在采用域名/年/月-日的目录结构配合SQLite记录元数据半年下来已经建立了可快速检索的万级文档库。最近新增的视觉差异对比功能帮助我发现了多个技术文档的隐蔽更新点这些都是在原始需求之外获得的意外价值。

相关新闻

npx陌生命令排查指南:从impeccable误报看CLI可信性诊断

npx陌生命令排查指南:从impeccable误报看CLI可信性诊断

1. 项目概述:一个被误读的“完美”工具名,以及它背后真实的CLI生态位最近在多个技术社区和前端开发者群聊里,“impeccable”这个词频繁跳出——不是作为形容词用在代码评审里夸人“写得无可挑剔”,而是作为一个具体可执行的命令出…

2026/10/15 9:48:44 阅读更多 →
hyperframes:高帧率视频处理的帧组架构与工程实践

hyperframes:高帧率视频处理的帧组架构与工程实践

1. 为什么我会盯上 hyperframes 这个方向hyperframes 这个词,我第一次看到是在一个客户的招标参数里,他们要做高速机械臂的视觉引导,要求抓拍速度到120fps,而且不能丢帧。我当时第一反应是:直接堆硬件不就完事了&#…

2026/10/15 9:48:44 阅读更多 →
2026东莞离婚纠纷维权优选:广东卡夫律所本土裁判优势深度解析

2026东莞离婚纠纷维权优选:广东卡夫律所本土裁判优势深度解析

2026东莞离婚纠纷维权优选:广东卡夫律所本土裁判优势深度解析在婚姻家事纠纷处理中,不同于普通民商事案件的刚性法条适用,离婚诉讼更看重本地法院裁判尺度、家事审判惯例、法官自由裁量标准。2026年东莞家事司法审判日趋精细化,抚…

2026/10/15 9:47:44 阅读更多 →

最新新闻

学Simulink——储能变流器(PCS)中 PWM 整流器的恒流充放电(CC Charge / CC Discharge)仿真

学Simulink——储能变流器(PCS)中 PWM 整流器的恒流充放电(CC Charge / CC Discharge)仿真

目录 手把手教你学Simulink——储能变流器(PCS)中 PWM 整流器的恒流充放电(CC Charge / CC Discharge)仿真 一、为什么储能 PCS 要做 恒流(CC)充放电双向 PWM 整流器 二、PCS 双向控制与 CC 模式原理** 2.1 功率平衡估算(用于 idref​折算) 2.2 模式定义 三、关键…

2026/10/15 10:38:32 阅读更多 →
TaoToken 视角下的示波器使用:measure/acquire/storage/cursor 四步实测

TaoToken 视角下的示波器使用:measure/acquire/storage/cursor 四步实测

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 10:38:32 阅读更多 →
学Simulink——三相 PWM 整流器在船舶岸电系统(Shore-to-Ship Power, Cold Ironing)中的并网控制仿真

学Simulink——三相 PWM 整流器在船舶岸电系统(Shore-to-Ship Power, Cold Ironing)中的并网控制仿真

目录 手把手教你学Simulink——三相 PWM 整流器在船舶岸电系统(Shore-to-Ship Power, Cold Ironing)中的并网控制仿真 一、为什么船舶岸电系统要用 三相 PWM 整流器/并网变流器 二、岸电系统典型参数(教学模型)** 三、Simulink 建模(手把手)** 3.1 Step 1️⃣ —— 港…

2026/10/15 10:38:32 阅读更多 →
PP-HumanSeg Lite + NCNN C++ 部署实战:精准版本对齐与边缘落地

PP-HumanSeg Lite + NCNN C++ 部署实战:精准版本对齐与边缘落地

简介:本资源是一套面向嵌入式与移动端开发者的轻量级人像分割部署方案,聚焦PP-HumanSeg Lite模型在NCNN框架下的C端高效落地,适用于视频会议背景虚化、AR换装、实时抠图等低延迟场景,适合具备C基础和一定CV部署经验的中高级开发者…

2026/10/15 10:38:32 阅读更多 →
OpenGL正背面剔除与深度测试:原理、配置与穿模问题排查

OpenGL正背面剔除与深度测试:原理、配置与穿模问题排查

1. 从一个“穿模”现象说起:为什么需要正背面剔除与深度测试但凡做过3D渲染的人,几乎都遇到过这样的场景:一个封闭的立方体或者角色模型,旋转到某个角度后,本该被挡住的背面却透了出来,或者两个物体交叠的地…

2026/10/15 10:38:32 阅读更多 →
企业WordPress定制开发:核心价值与选型指南

企业WordPress定制开发:核心价值与选型指南

1. 为什么企业需要专业的WordPress定制开发服务 在数字化浪潮席卷各行各业的当下,企业官网已从简单的"电子名片"升级为集品牌展示、客户服务和业务转化于一体的核心平台。WordPress作为全球占比43%的内容管理系统,凭借其开源特性、丰富的插件生…

2026/10/15 10:37:31 阅读更多 →

日新闻

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

1. 为什么选择容器化方式部署 LoRa 网络服务LoRa 物联网项目落地时,网络服务器是整个链路的核心枢纽。它负责接收网关上报的数据包、完成去重与解密、再把有效载荷分发给上层应用。早期大家习惯把网络服务器直接装在物理机上,依赖一堆系统库和特定版本的…

2026/10/15 0:00:46 阅读更多 →
共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

1. 共享推理服务里,扩缩容到底难在哪做过大模型推理服务部署的人,大概都经历过这样的场景:一个团队共用一套推理集群,A 业务跑的是 7B 的小模型,B 业务跑的是 72B 的大模型,C 业务白天流量高、晚上几乎归零…

2026/10/15 0:00:46 阅读更多 →
Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

1. 引子:一次内核恐慌引发的追查先从一个真实场景说起。某次我给一台老旧的嵌入式设备折腾系统裁减,为了把启动时间压进两秒以内,我手贱地把一串自认为“没用”的 systemd 服务给 disable 了,其中就包括systemd-remount-fs.servic…

2026/10/15 0:00:46 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/14 16:30:29 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 0:14:36 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 9:49:14 阅读更多 →