从空白需求到自动化数据采集:Playwright实战全链路记录
上周收到一个需求项目名叫【无标题】正文空白、关键词空白连摘要也只留了一句“先看看能做什么”。一开始我以为是对方漏贴了内容后来发现这事在真实工作里太常发生了很多项目最早期根本没有成文的需求只有一个代号、一个念头所有细节都要靠人去推演补齐。我当时的处理方式是把这个空白需求当成一个完整的实战项目来做——一个自动化数据采集项目从需求拆解、技术选型、代码实现到调度监控把整条链路从头到尾走一遍。这篇文章就是这次过程的完整记录分享给正在面对空需求、不知道从哪里下手的读者也顺带整理一下我在自动化采集和页面自动化这条路上实际踩过的坑和验证过的做法。1. 空白需求的第一步先做需求拆解再碰代码接到【无标题】这种需求最容易犯的错误就是立刻打开编辑器开始写代码。因为你根本不知道要写什么就算硬写出来大概率也是自嗨。我的习惯是先花半小时做需求拆解把模糊的意图变成问题清单然后再决定用哪套技术。这个环节的价值在于页面自动化项目里80%的返工不是写不出来而是开始前没有把范围定清楚。1.1 先回答五个问题把空标题变成可执行的需求边界我拿到任何空白需求都会先逼自己回答下面五个问题答不出来就继续问直到能答出来为止。数据从哪里来——要访问哪些页面页面是静态 HTML 还是后端接口渲染需要哪些字段——哪怕只是标题、发布时间、作者、正文摘要这四样也要提前列出来。多久更新一次——决定了是一次性脚本还是需要长期运行的任务。结果保存在哪里——CSV、JSON、数据库还是推送到其他系统采集之后拿它做什么——做趋势分析、做展示页面、做定时监控这三个方向对数据质量的要求完全不同。这五个问题看起来简单但它们能立刻把一个“无标题”需求变成具体的边界。比如我自己这次最终确定的方向是从某个公开列表页采集公开可见的标题和价格信息每天更新一次落成 JSON 和 CSV 双份文件供后续统计使用。字段很少、频率不高、结果不需要实时——这就已经足够支撑后面的技术选型了。如果需求方给不出明确答案也不要卡在原地。我会主动提一个“最小可用版本”作为对齐基准先做最简单的公开数据采集跑通之后再讨论要不要加量、要不要做交互操作。所有复杂的自动化需求几乎都是从这个最小版本上长出来的。1.2 用一份最小数据结构草案对齐预期需求拆解之后我做的第二件事是定义数据结构。这一步经常被忽略但它直接影响后面的清洗和输出。不要等到采集完再想字段怎么存那肯定乱套。我通常会先定一个最小草案比如下面的 JSON 结构{ source: example-list-page, crawled_at: 2025-01-01T08:30:0008:00, items: [ { title: 示例标题, author: 作者A, published_at: 2025-01-01 } ] }这个草案的重点不在于格式漂不漂亮而在于提前统一几个容易乱的点字段名用英文还是中文、时间格式是标准 ISO 还是自定义字符串、字段缺失时是给 null 还是直接丢弃。这些细节越早定后面写清洗逻辑越省力。我的经验是数据结构草案顺手丢给对方看一眼哪怕对方说“都行”也比完全没对齐强。需求越空白越需要有一个具体的东西摆在那当靶子否则大家讨论的全是抽象概念。2. 选型权衡为什么最终选择无头浏览器自动化需求边界清楚了接下来才是技术选型。自动化采集这个方向方案远不止一种。很多人一上来就问“用什么库”但其实先要回答的是“我需不需要一个能执行 JavaScript 的浏览器环境”。在自动化采集项目里这个问题的答案直接决定了整套技术栈的方向。2.1 三条路线的真实差异我把常见的方案分成三类分别对应的场景完全不同。方案优点缺点适用场景纯 HTTP 请求 HTML 解析简单、快、资源占用低拿不到 JavaScript 渲染后的内容动态页面会抓空静态页面、结构简单、字段固定Scrapy 框架并发能力强、生态成熟学习曲线陡涉及动态渲染时需要额外桥接配置成本高大规模、目标站点数量多、页面结构统一无头浏览器自动化能模拟真实用户操作JS 渲染、点击翻页、表单提交都能做资源占用高、运行速度慢、依赖浏览器内核页面强依赖 JS、交互复杂、需要模拟真实访问行为至于无头浏览器本身我这次选的是开源工具 Playwright。它能把 Chromium 内核跑在后台不需要弹出可见窗口页面渲染、事件触发、元素选取都通过代码控制。简单理解就是把一个完整的浏览器塞进黑盒里运行它在后台默默加载页面、执行脚本你等它干完活再把数据取出来。相比纯 HTTP 请求这种方式慢不少但它最大的价值是能拿到“人眼真正看到的内容”而不是服务器返回的初始 HTML 壳子。2.2 为什么 Playwright 在这个项目里最顺手实际上自动化浏览器这个领域里可选的工具不止一个但我个人更偏爱 Playwright。最核心的原因是它在“等待”这件事上做得足够聪明。做页面自动化的都懂最烦的就是打开网页之后脚本不知道页面有没有加载完。传统做法是sleep(5)硬等时间短了会失败时间长了纯粹浪费。Playwright 的等待机制是“按需睁眼”元素没出现就一直等出现了立刻继续执行效率比固定延时高一截。另一个我很看重的点是浏览器上下文隔离。你可以把 context 理解成一个独立的用户会话不同 context 之间的 cookie、缓存、登录状态完全隔开。这意味着我在同一个进程里可以并行跑多个独立会话互不污染非常适合做多来源数据对比。再加上它支持同步和异步两种 API简单脚本用同步并发场景切异步过渡成本很低。当然选型不能无脑追新。如果目标页面是纯静态的字段也不复杂直接用 requests 或 httpx 就够了没必要抬出一个浏览器来杀鸡。我的建议是先判断目标页面能不能用curl拿到完整内容能就优先用轻量方案不能再考虑无头浏览器。技术选型永远是需求倒推出来的不是越先进越好。3. 项目落地页面加载、数据提取到文件输出的完整链路确定方案之后我用两个多小时把核心链路跑通了。整个流程可以拆成四步启动浏览器、打开目标列表页、等待关键元素出现、提取所需的标题和价格。听起来不难但每一步都有可以优化的细节。这一节我把完整过程贴出来代码是示意结构实际业务里的选择器需要按目标页面调整。3.1 环境准备一次安装全局可用环境准备分三步。首先是创建独立的 Python 虚拟环境避免和系统环境互相污染然后安装 Playwright 库最后下载它需要的 Chromium 内核。python -m venv venv source venv/bin/activate # Windows 下用 venv\Scripts\activate pip install playwright playwright install chromium我见过不少人卡在最后一步跑完pip install playwright就急着写代码结果程序报启动浏览器失败。这里要提个醒Playwright 和内核是分开安装的缺了playwright install chromium代码本身没问题但没有浏览器可启动。下载过程中需要一些网络资源如果下载慢可以配置使用镜像源但不建议跳过这一步。内核只要装好一次后面多个项目都能共用。3.2 抓取主流程等待-定位-提取-翻页核心采集逻辑我用一个函数包起来方便扩展。下面这段是完整的主流程from playwright.sync_api import sync_playwright def fetch_page_data(url: str, max_pages: int 3): results [] with sync_playwright() as p: browser p.chromium.launch(headlessTrue) page browser.new_page() current_url url for page_index in range(max_pages): print(f处理第 {page_index 1} 页: {current_url}) page.goto(current_url, timeout30000) page.wait_for_selector(.list-container, timeout15000) cards page.locator(.item-card).all() for card in cards: try: title card.locator(.title).inner_text(timeout5000) price card.locator(.price).inner_text(timeout5000) results.append({ title: title, price: price, page: page_index 1 }) except Exception: # 单条数据失败不影响整页采集 continue next_button page.locator(.pagination .next) if next_button.count() 0 and next_button.is_visible(): current_url next_button.get_attribute(href) else: break browser.close() return results这段代码里最值得说的是等待逻辑和翻页逻辑。等待时我用了wait_for_selector而不是sleep这是前面说过的原则可以大幅提升稳定性。翻页时通过检测“下一页”按钮是否存在且可见来决定要不要继续如果按钮不存在直接结束。max_pages参数是安全绳防止目标站点分页异常导致脚本无限循环下去。为什么每次只取inner_text而不是inner_html因为页面自动化里文本提取是高频场景HTML 源码里往往裹着一堆样式和机器注释反而增加解析成本。先拿到干净文本再在清洗环节统一处理格式这是最顺畅的方式。如果后续要获取链接再单独用get_attribute(href)提取。3.3 结果落地JSON 与 CSV 双写为后续入库留口数据抓回来之后落地格式我选了双写既存 JSON也存 CSV。JSON 保留完整嵌套结构方便程序继续处理CSV 则是给不写代码的人看的Excel 打开就能用。这个选择在空需求场景下尤其实用因为使用者很多提前给两种格式能省去后续反复转换import json import csv def save_results(results, base_name): # JSON保留结构和类型 with open(f{base_name}.json, w, encodingutf-8) as f: json.dump(results, f, ensure_asciiFalse, indent2) # CSV便于表格软件直接查看 with open(f{base_name}.csv, w, encodingutf-8-sig, newline) as f: fieldnames [title, price, page] writer csv.DictWriter(f, fieldnamesfieldnames) writer.writeheader() writer.writerows(results)这里有一个特别容易踩的坑CSV 文件如果用普通的 UTF-8 编码保存用 Excel 打开中文会乱码。所以写入 CSV 时要用utf-8-sig也就是带 BOM 的 UTF-8这是处理中文字符时最省心的编码方案。JSON 则用普通 UTF-8 即可因为多数程序都认。4. 实测暴露的问题超时、脏数据与页面结构变化跑通核心链路不代表项目结束了恰恰相反真正花时间的都在后面。我在实际运行中遇到了三个典型问题每一个都是页面自动化项目的常见病。这里把排查过程完整写出来比直接给答案更有参考价值。4.1 元素定位超时先判断是慢还是错第一次运行脚本我在wait_for_selector这行报了个 TimeoutError等待 15 秒没找到.item-card。按报错信息看有两种可能——页面加载慢超过 15 秒才出现列表或者选择器写错了元素压根不存在。我没有急着改代码而是先手动打开页面确认。确认页面里确实有卡片元素那就排除了“选择器写错”的可能。接着我把等待拆成两步先等一个外层稳定的容器.list-container再等内部的.item-card。因为列表容器通常在页面骨架加载时就出现了等它稳定之后再等列表项成功率会高很多。page.wait_for_selector(.list-container, timeout15000) page.wait_for_selector(.item-card, timeout10000)这个“先父后子”的等待策略是我后来做页面自动化项目一直沿用的惯例。它的好处是不会因为某个内部元素渲染慢就误判整个页面失败同时也能快速区分到底是页面挂了还是元素确实不存在。超时问题绝大多数是等待策略的问题而不是脚本逻辑的问题。4.2 字段脏数据空白、多余空格、特殊字符的统一清洗第二个问题是数据抓回来之后看起来乱糟糟。inner_text拿到的文本经常包含大量换行、制表符和多余空格有的字段还夹杂着特殊引号和全角字符。如果直接把原始文本写进 CSV后续统计时就会发现标题对不上、字段串行非常恼人。我的做法是在入库之前统一走一个清洗函数import re def clean_text(raw_text): if not raw_text: return # 连续空白字符含换行、制表符统一替换为单个空格 text re.sub(r\s, , raw_text) # 去掉首尾空白 return text.strip()清洗规则不要做得太激进。比如正文多段之间原本存在的换行如果将来要做语义分析就不该统一抹掉。我的经验是针对字段类型定义清洗规则。标题、作者、价格这类单行字段统一压缩空白没问题正文类字段则保留换行只去掉首尾空格。先观察数据样本再定规则比一上来就写正则要靠谱得多。4.3 长任务内存告警浏览器上下文要按批次关闭第三个问题是运行时长超过一小时之后内存占用持续上涨从初始的 200MB 一路涨到 2GB 以上。排查后发现原因很典型脚本在一个browser实例里不断打开新页面但没有及时关闭。页面对象虽然不再使用但浏览器内核依然持有资源时间一长必然爆内存。修复方式是按批次管理上下文。每批数据用完就关掉整个context相当于清空了该批次的所有页面资源with sync_playwright() as p: browser p.chromium.launch(headlessTrue) for batch in batches: context browser.new_context() page context.new_page() # ... 执行采集逻辑 ... context.close() browser.close()这看似只是加了一行context.close()但效果立竿见影。做任何长跑任务前都要先想好资源回收策略不能指望操作系统替你兜底。另外如果单个任务确实要跑很久建议定期重启浏览器进程这是最简单粗暴也最有效的兜底手段。4.4 合规边界不是所有页面都适合自动化采集这一条放在这里说是因为它不该在项目结束时才考虑。我做的所有自动化采集项目都严格限定在公开可见的信息范围内。不绕过任何访问控制不处理需要登录授权才能获取的内容不通过脚本去破解验证码也不伪造身份规避平台限制。每个目标网站的使用条款和服务协议我都会在项目开始前过一遍确认自己的采集行为在允许范围内。原因很简单自动化采集本质上是替代人工浏览但如果它变成了突破访问限制的手段性质就完全不一样了。合规的底线不应该是技术能不能做到而应该是规则允不允许。这个原则定了后面的所有技术选型才会安全。5. 从“手跑脚本”到“稳定交付”调度、监控与结果校验脚本能跑通只是一个开始。自动化的价值在于“自动”在于没人盯着它的时候它也能稳定运行并且在结果异常时能留下线索。我见过太多项目死在“脚本能跑”这一步手动执行没问题一挂到定时任务里就各种灵异事件。其实无非是没把调度、日志、校验这三件事做好。5.1 让任务按计划自动跑我用 APScheduler 做定时调度它轻量、配置简单不需要额外部署服务。下面的例子让采集任务每天 08:30 自动跑一次from apscheduler.schedulers.blocking import BlockingScheduler def main(): results fetch_page_data(https://example.com/list, max_pages3) save_results(results, report) scheduler BlockingScheduler() scheduler.add_job(main, cron, hour8, minute30, iddaily_collect) scheduler.start()有两个细节值得注意。第一运行频率不要设置得太高。页面自动化任务本身耗时长且占用资源高频调度只会放大不稳定因素。第二如果同时跑多个任务建议在调度器里给每类任务加一点随机延时避免多个任务同时启动导致瞬时负载过高。任何线上服务都要有“错峰”意识采集任务也一样。5.2 脚本不报错不代表结果正确数据校验不能省之前我吃过一个大亏脚本每天准时执行日志也干干净净直到后来统计时才发现某天的数据只有正常量的三分之一。原因是一个页面结构微调导致大量列表项没被识别出来脚本又不报错静默地把错误结果写进文件。从那以后我每次采集完都会加一层数据校验。最简单的方式是设置阈值import logging logging.basicConfig( filenamecollector.log, levellogging.INFO, format%(asctime)s %(levelname)s %(message)s ) def verify_results(results, expected_min50): total len(results) if total 0: logging.error(采集结果为空) elif total expected_min: logging.warning(结果数量偏少预期最少 %s实际 %s, expected_min, total) else: logging.info(采集完成共 %s 条, total) return total只要结果数量低于阈值就算脚本没有崩溃日志里也会留下一条醒目的 warning。对于长时间运行的采集任务空值率、重复率、总量波动是最基本的三项健康指标建议每次运行后都计算一遍并写入日志之后排查问题会方便很多。5.3 收尾给项目留一个可观察的运行状态把调度、日志、数据校验串起来整个项目才算真正能交付。我最后的习惯是给项目目录固定一个结构collector.log运行日志记录每次采集的开始、结束、异常摘要。report.json/report.csv最新一份采集结果。history/按日期归档的历史数据目录保留周期根据需求定。归档文件时我会在文件名里带日期比如report_2025-01-01.json这样后续做趋势对比时直接按文件名拉数据就行。日志则重点盯两个东西有没有 Error 级别的异常有没有 Warning 级别的数量波动。异常靠报错栈定位波动靠校验日志定位这两个信息齐全绝大多数线上问题都能在五分钟内找到方向。最后再分享两个实操习惯吧。第一个是写任何采集脚本之前先想清楚“页面结构变化了怎么办”——给选择器留出声明的集中目录而不是散落在业务代码里维护时会轻松很多。第二个是所有脚本入口必须打印输入参数和输出行数哪怕只访问一页也打一行已处理 page 1, 共 12 条。看起来多此一举但真正出问题的时候这行打印能帮你省下一个上午。自动化的项目最终的可靠性拼的不是某个环节的高超技巧而是每个环节留下足够多的可观察痕迹。

相关新闻

图像处理文献综述文档使用指南:快速定位研究方向与构建综述框架

图像处理文献综述文档使用指南:快速定位研究方向与构建综述框架

简介:这份文献综述文档面向图像处理方向的本科生与研究生,尤其适合正在撰写毕业设计或课程论文、需要系统梳理图像滤波知识脉络的读者。内容围绕图像滤波这一核心环节展开,涵盖其发展历程、去噪与细节保留的平衡问题,以及中值滤波…

2026/10/18 14:20:27 阅读更多 →
大猿人V6.0充值平台部署全攻略:环境配置、数据库导入与避坑指南

大猿人V6.0充值平台部署全攻略:环境配置、数据库导入与避坑指南

简介:这套部署包是大猿人V6.0旗舰版充值平台的完整可运行版本,面向数字内容服务、虚拟商品交易与会员体系管理场景,基于PHPMySQL标准技术栈开发,兼容PHP 7.2至8.1与LAMP/WAMP环境,以高度集成化和即装即用为设计核心&am…

2026/10/18 14:20:27 阅读更多 →
UEditor粘贴Word样式错乱治理:从根因到三层防线方案

UEditor粘贴Word样式错乱治理:从根因到三层防线方案

上个月,我们维护的一所学校的教育信息化平台连续收到了好几条工单,反馈的内容惊人地一致:老师从Word教案里复制图文内容,粘贴进公告编辑器,保存之后再打开,页面变得乱七八糟——表格散架、字体忽大忽小、段…

2026/10/18 14:20:27 阅读更多 →

最新新闻

Reflector 7.4.1.179 绿色注册版部署指南:插件集成与避坑实践

Reflector 7.4.1.179 绿色注册版部署指南:插件集成与避坑实践

简介:这是一份面向.NET开发者的反编译工具整合包,主角是经典的.NET Reflector 7.4.1.179绿色注册版,并真正集成了FileDisassembler与FileGenerator两款广受好评的插件,解决原版只能逐个查看方法、无法批量导出源码的痛点。包内共2…

2026/10/18 14:58:53 阅读更多 →
Vue权限控制实战:路由、菜单与按钮级权限完整链路

Vue权限控制实战:路由、菜单与按钮级权限完整链路

简介:这份资源面向正在开发后台管理系统的Vue前端开发者,聚焦权限控制这一核心场景,帮助解决不同角色用户只能访问被授权功能的问题。内容围绕两种主流限制方式展开:一是路由不可见,借助Vue Router的meta字段存储权限列…

2026/10/18 14:58:53 阅读更多 →
建筑施工安全技术资料如何变成项目台账?链路拆解与归档实操

建筑施工安全技术资料如何变成项目台账?链路拆解与归档实操

简介:建筑施工安全技术资料是现场安全管理的底账,而非应付检查的废纸。其核心原理是把方案、交底、检查、验收、整改五个环节串成管理链路,再按塔吊、基坑、临电等对象建立检索维度,形成“链路对象”的矩阵台账。通过统一编号、逐…

2026/10/18 14:58:53 阅读更多 →
YOLOv8骨干替换EfficientNetV2:均质架构提升小目标检测与推理性能

YOLOv8骨干替换EfficientNetV2:均质架构提升小目标检测与推理性能

1. 改造动机与方案选型1.1 YOLOv8原有骨干的瓶颈在哪里动手换主干之前,我先把YOLOv8原生CSPDarknet53的短板列了一遍。YOLOv8默认的backbone在COCO这类通用检测任务上确实够用,但一旦碰到分辨率高、小目标密集或纹理细节要求高的场景,它的问题…

2026/10/18 14:58:53 阅读更多 →
STM32F407 DCMI图像采集丢帧错位的硬件时序真相

STM32F407 DCMI图像采集丢帧错位的硬件时序真相

简介:本资源是一份基于STM32F407微控制器的高速并行12位ADC与DCMI数字摄像头接口协同开发实践方案,面向嵌入式初学者及图像采集方向进阶开发者,解决模拟信号高速采样与图像数据流同步传输的核心工程问题,适用于工业检测、智能视觉…

2026/10/18 14:58:53 阅读更多 →
《华为团队工作法》华为人才管理和薪酬激励:构建四位一体点燃员工热情的激励体系

《华为团队工作法》华为人才管理和薪酬激励:构建四位一体点燃员工热情的激励体系

本 115 页 PPT 适配企业人才管理、薪酬激励、干部管理类咨询方案与 HR 培训课件编制。基于华为人才管理体系核心实践,系统拆解人才选配、评估、干部任用、人才成长、文化锻造、薪酬激励、全面激励、健康成长八大模块。涵盖 STAR 行为面试、人才搭配四宫格、绩效能力…

2026/10/18 14:57:52 阅读更多 →

日新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

月新闻

我发现了一个新思路:用 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/18 0:55:02 阅读更多 →
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/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练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/18 12:16:16 阅读更多 →