Brozzler分布式爬虫:真实浏览器渲染解决动态页面抓取难题
做爬虫这行最怕听到的一句话是页面我打开明明有内容你怎么抓回来是空的我第一次被这种问题问住是在处理一批带前端动态渲染的落地页时。那个页面右键查看源代码能看到的只有几个script标签和一个空荡荡的div idapp可真实用户访问时里面密密麻麻是商品信息、图片地址、交互按钮。把这种页面交给传统 HTTP 爬虫拿回来的所谓网页源码几乎等于一份空壳。也正是在那段时间我翻开源社区的资料注意到了 Brozzler。Brozzler 是一个主打真实浏览器渲染的分布式网页爬虫设计目标非常明确抓取器不再只是向服务器发请求、收响应而是真正打开一个浏览器内核等页面上的脚本把 DOM 结构搭好再把渲染完成后的状态完整记录下来。它很适合做网页存档、页面快照、复杂前端站点采集这类场景也适合想认真研究分布式任务调度的爬虫工程师。下面我会把它的设计思路、部署过程和实际使用中容易踩的坑一次性讲透。1. 为什么传统爬虫总在动态站点上栽跟头1.1 静态源码与渲染后的页面差距可能是一整条瀑布流普通爬虫采集网页信息大体的流程是三步曲向目标地址发 HTTP 请求拿到 HTML 文本用解析器从文本中抽出链接和内容。这个流程对早期的门户网站、静态文档页面完全够用因为那些页面上的信息在发送请求时就已经全部包含在 HTML 源代码里了。但近几年前端工程化让页面形态发生了很大变化。常见的单页应用SPA会把业务逻辑拆散交给浏览器执行服务端只返回一个带脚本引用的空骨架。数据展示通常依靠异步请求页面先渲染出加载动画脚本随后请求各类接口拿到 JSON 后再往 DOM 里填充内容。有些页面甚至要等滚动事件触发、图表库初始化完成后关键信息才出现。这个过程的最终结果只存在于渲染结束后的浏览器内存里并不存在于任何一份静态 HTML 文件中。对传统爬虫来说这几乎等同于看到页面和抓到内容之间出现了断层。倒不是说完全抓不到很多站点会额外提供 JSON 接口逆向一下也能拿到同样的数据但接口字段不稳定、数据结构随版本变化、登录态校验复杂维护成本往往高得吓人。更麻烦的是如果你要的不是数据而是页面当时的真实观感比如存档取证、竞争页面快照、长期回溯分析那接口数据无论如何都无法代替渲染后的页面本身。1.2 Brozzler 的破局方式把浏览器内核直接放进抓取链路Brozzler 的核心思路与上面那种解析源码的路线完全不同。它使用 Chromium 内核作为真正的抓取器通过调试协议CDP与浏览器实例通信。每一个 URL 会被分配到一个浏览器标签页浏览器像普通用户一样加载页面、执行脚本、发起异步请求然后 Brozzler 等待一个相对稳妥的时机认为页面已经稳定再从 DOM 中抽取链接、保存页面内容、生成 WARC 格式的记录文件。这个过程解决了两大问题第一脚本执行、异步请求、渲染样式全都在真实的浏览器环境中完成不会出现源码里有数据但页面没显示或者页面显示了但源码拿不到的情况。第二存档的质量贴近用户真实体验。因为保存的是渲染完成后的最终状态回放时还能看到完整的排版、图片和交互痕迹。后来我把几个真实项目里的页面同时交给传统解析爬虫和 Brozzler 抓前者抓回来一屏代码、后者抓到的是能直接点击的页面快照效率高下立判。Brozzler 最早是配合网页存档场景打磨出来的这一点从它的很多设计里都能看出来WARC 存档格式、与 Web 回放工具的联动、分布式任务队列的容错都是为了长期保存并回放网页这个目标服务的。这个定位也决定了它和通用数据采集爬虫在气质上有明显差异。2. 分布式架构拆解Seed、Frontier、Worker 与状态存储2.1 核心组件如何分工看官方文档或者源码目录第一眼可能会觉得乱但 Brozzler 的角色模型其实非常清晰可以拆成三个层面。第一层是前端Frontier你可以把它理解成一个待抓取任务清单。它会维护所有已知但还没有被处理的 URL同时负责去重、优先级排序和任务分发。第二层是 Worker多个 Worker 可以跑在同一台或者多台机器上每个 Worker 从 Frontier 领取任务再驱动一个或多个 Chromium 实例完成实际抓取。第三层是状态与协调服务Brozzler 在默认配置下使用 ZooKeeper 来保存 Frontier 状态、做 Worker 注册、心跳和故障转移。我刚开始理解这套设计的时候总习惯性地把任务队列想象成一个独立服务但 Brozzler 的做法更巧妙它把队列状态直接放进 ZooKeeper 的有序节点里。Worker 空闲时取一个任务抓完后把新发现的链接写回队列。任务到底由哪个 Worker 处理不是预先分配的而是动态争抢。这种做法让整个系统非常容易横向扩展加机器只需要多启动 Worker职责自然被分散出去。2.2 ZooKeeper 在任务调度中到底做了什么如果只跑单机模式你可能会觉得 ZooKeeper 是多余的开销。但一旦 Worker 数量超过一个ZooKeeper 的价值立刻体现出来。任务去重和消费进度保存在共享状态中Worker 启动后会在 ZooKeeper 里注册临时节点进程存活期间持续发心跳万一某台 Worker 突然宕机协调服务会发现临时节点失联把该 Worker 尚未完成的任务交还队列交给其他节点继续处理。对于需要长时间运行的抓取任务这套容错机制非常关键不然一个节点挂掉就意味着整批任务要从头再来。当然这也带出一个实际代价引入 ZooKeeper 意味着运维线上多了一个有状态组件需要监控它的连接数、会话超时和磁盘使用。因此我建议先用 Docker Compose 把它和 Brozzler 一起拉起来等你在单机上完全摸熟了再考虑跨机器部署。2.3 浏览器实例的连接与生命周期Worker 驱动 Chromium 时走的通道是调试协议CDP。Worker 和 Chromium 之间的关系不是一次请求一次响应而是一个持续存在的会话。Worker 创建浏览器标签页设置用户代理等参数然后通过 CDP 监听页面加载事件、网络请求日志、DOM 变化等。抓取流程通常是这样导航到目标 URL等待页面主加载事件触发再额外等待脚本周期、网络空闲或固定延时之后执行抓取逻辑比如滚动页面、等待图片懒加载最后从上下文中提取所有可见或可访问的链接和资源地址写进 WARC 的同时把新链接回填到 Frontier。抓完一个页面后Worker 可以选择关闭标签页或直接复用浏览器实例这个复用的尺度直接影响到系统资源占用后面我会专门讲。2.4 结果如何落盘WARC 与回放工具链Brozzler 的抓取产物不是一堆临时文件而是按标准格式组织成 WARC 记录。WARCWeb ARChive可以理解为网页领域的容器封装格式把请求头、响应体、时间戳、元数据打包在一起一个站点的一次抓取可能对应多条记录。WARC 本身看起来不够友好但搭配回放工具使用时就会很自然。业内常见的做法是用专门的 WARC 回放工具把抓取产物索引并还原成网页。我也在实践中用过命令行生成 CDX 索引的方式快速核对某个 URL 是否被抓到。这里不展开具体命令但要记住的是Brozzler 不是一个单纯保存 HTML的工具它生成的结果天然适合长期存档、离线浏览和逐日增量回放。3. 本地跑通 Brozzler 的完整过程与关键配置项3.1 环境准备推荐 Docker 与源码两种路径先从最省事的环境入手。Brozzler 的依赖包括 Python 环境、Chromium 二进制和 ZooKeeper。如果直接在本机构建最需要注意的是 Chromium 版本和系统依赖图形库、字体、沙箱权限常常让人折腾到怀疑人生。所以我日常推荐优先用现成的 Docker 镜像把 Chromium 和运行库一次性装好ZooKeeper 单独用容器启动。下面是一个最小化的启动方式我用一个 docker-compose 文件组织 ZooKeeper 和 Brozzler 两个服务。具体镜像名以你实际操作时的版本为准这里我只给占位符。services: zookeeper: image: zookeeper:3.8 brozzler: image: brozzler 镜像 depends_on: - zookeeper volumes: - ./data:/data/brozzler想要更接近源码级研究的话也可以拉源码安装。源码方式的好处是可以随时看日志、改行为策略适合需要深度定制抓取逻辑的进阶场景。第一次实验我更建议直接在容器里操作踩坑成本低。3.2 配置文件的核心分组与参数作用Brozzler 用 YAML 做配置整体上可以分成 worker、chrome、crawl、behavior 四组。下面给出一个贴近我实际使用习惯的骨架配置字段含义随后逐条解释。不同版本的字段名可能略有差别请以你下载的版本自带的示例配置为准。worker: zookeeper: localhost:2181 service-registration: false max_workers: 2 chrome: executable: /usr/bin/chromium headless: true args: - --no-sandbox crawl: user_agent: Mozilla/5.0 (X11; Linux x86_64) Brozzler/1.0 robots: true enable_stealth: true proxy: behavior: wait_seconds: 5 max_seconds: 120 scroll: 0worker分组里要填写 ZooKeeper 地址。单机调试时service-registration可以关掉免得 Worker 注册不上导致任务发不出去。max_workers指在一个 Worker 进程内最多同时跑多少个浏览器实例默认值通常不大但改动前要看内存余量。chrome分组用于指定浏览器执行文件路径和启动参数。headless: true表示无头模式适合服务器环境--no-sandbox是因为很多容器的内核限制无法开启沙箱这需要你自行权衡利弊。crawl分组里robots控制是否遵守目标网站的 robots 协议enable_stealth用于降低被页面脚本识别的概率proxy则可以填一个可用的代理地址。behavior分组直接决定抓取质量wait_seconds是页面加载事件之后额外等待的时间max_seconds上限防止某些无限加载的页面把任务拖死。3.3 添加种子并启动 Worker假设你已经把配置保存为brozzler.yaml目标是采集一个种子站点https://somesite.test。先添加种子brozzler-new -c brozzler.yaml https://somesite.test然后启动 Workerbrozzler-worker -c brozzler.yamlWorker 启动后日志会不断输出当前正在处理的 URL、页面等待状态和写入结果。看到哪一行出现疑似记录生成完毕的日志就说明整条链路已经通了。这个时候不要急着加更多站点先回到 ZooKeeper 容器里检查一下队列情况并且确认 WARC 文件已经出现在输出目录再把规模扩大。3.4 输出产物怎么看抓完一批页面后Brozzler 会生成以时间戳命名的 WARC 文件。想直观确认抓到了什么可以用配套的回放工具把索引启动起来也可以直接用命令行工具生成 CDX 索引快速列出某个 URL 的所有抓取记录。我第一次跑通时盯着漫天日志和新生成的 WARC 文件夹才真正理解了前面说的网页存档和抓数据之间的区别Brozzler 的目标是把页面完整打包而不是把字段拆出来。4. 调参记录三个直接影响抓取质量的参数维度4.1 等多久才算渲染完等待策略对结果的决定性影响Brozzler 处理动态页面的关键难点不是发请求而是判断现在可以抓了。如果把等待时间设置得太短可能赶上接口还没返回截下来的页面就缺图片如果设置得过长一个页面几分钟整个队列的吞吐量直线下降抓完一个中型站点要好几天。我个人的经验是先观察目标站点的实际加载规律再结合wait_seconds与一个总超时上限来兜底。对大部分内容型页面页面主事件触发后额外等 3 到 8 秒就已经足够但如果目标站点依赖长轮询或 WebSocket 实时推送就需要适当延长并且接受单页耗时变长的代价。总超时上限最好按照正常加载时间的两倍以上去设置避免某些异常页面卡死整个 Worker。这里有个容易被忽略的细节异步加载并不是一次性的。有些页面会在用户滚动、点击、切换 Tab 时才触发新一轮请求。如果抓取目的只是存档首屏那固定等待就够了如果想要页面更深层的内容就得依赖滚动策略或者额外的交互脚本。Brozzler 默认提供的是比较偏保守存档的等待逻辑你要是追求完整交互态需要自己评估站点行为再决定要不要定制。4.2 多浏览器实例与内存之间的平衡很多人在初学阶段会犯一个错误把max_workers调得很大觉得并发越高抓得越快。但每个 Chromium 实例占用几百 MB 内存在 8 GB 内存的机器上开 10 个浏览器实例可能页面还没抓几个系统已经进入 swap 拖延状态。我曾经做过一次估算当实例数量接近物理内存的半数以上后吞吐量的增长曲线就趋于平缓甚至可能因为频繁 GC 和换页反而下降。下面是我常用的一个大致的配比参考具体还要看你抓取页面的复杂度物理内存建议浏览器实例数适合场景4 GB1-2轻量页面验证流程8 GB2-3常规站点小批量任务16 GB4-6中型站点混合内容32 GB 以上8大规模采集分布式部署实际配置时我会先让单个 Worker 保持两个实例跑半小时观察内存占用平均值再按比例扩大。记住对分布式抓取系统来说稳定比峰值速度重要得多。宁可让 Worker 数量少一点也要给 Chromium 留出足够的内存余量否则进程互相挤压最后反而拖慢整体进度。4.3 合理处理反爬识别与抓取礼仪Brozzler 作为一个真实浏览器驱动的爬虫先天上就不太容易被简单的脚本检测识别因为它确实在执行脚本、渲染元素、产生真实的网络请求。配置里的 stealth 选项和自定义 UA 可以进一步降低被识别的概率。但这里必须说清楚边界这些配置只适合抓取公开可访问的页面绝不代表可以绕过登录授权、付费墙或者其它访问控制。真正要做长期采集更应该关注的是目标网站的 robots 协议、服务条款和各地相关法律法规。轻则被拉黑 IP重则惹来不必要的麻烦完全不值得。我还见过一些同学为了追求效率把抓取间隔压到毫秒级结果站点日志里出现明显异常的流量特征最后整个 IP 段都被封掉这类教训很常见。5. 生产环境里的踩坑记录三个问题的完整排查链路5.1 ZooKeeper 连接不稳定导致任务静默中断有段时间我负责的一个抓取任务跑了十几个小时后突然不再输出新记录Worker 进程还活着日志也没有明显的报错。我当时的第一反应是去翻输出目录发现 WARC 的时间戳停在一个小时前说明问题不是从最近几分钟才开始。排查链路是这样的先检查 ZooKeeper 容器和 Worker 之间的网络在 Worker 机器上用四字命令查看连接数再看 Worker 心跳日志确认是否存在会话超时。最后定位到是 ZooKeeper 的会话超时设置过短加上 Worker 机器空闲时没有及时通信会话过期后临时节点被自动清理任务队列里的任务自然也没有人认领了。解决方案其实很简单增大会话超时时间或者定期由 Worker 主动发送心跳让 ZooKeeper 认为节点仍然健康。从那以后我形成了一条规律任何进程活着但任务没进展的故障先怀疑状态协调层不要急着盯抓取逻辑。5.2 Chromium 进程越积越多最终吃光内存另一个常见问题是内存泄漏。症状很典型抓取运行一整天后系统越来越慢进程列表一查Chromium 相关进程数量多得离谱而且还在持续增长。原因是某些标签页在抓取完或超时后没有被及时关闭调试协议连接也没有正常释放导致浏览器进程一直驻留在内存里。我的处理办法分两步。第一步做兜底限制单个 Worker 处理页面的数量达到阈值后主动重启 Worker掉不了的进程交给系统层面清理。第二步从源头排查找到哪些页面触发了标签页未关闭的分支逻辑补上资源释放的代码。长期维护一个生产级抓取集群如果只靠猜效率太低最好的方式一开始就要把页面关闭逻辑写严谨并且监控资源曲线而不是等机器卡死才去救。5.3 robots 协议判断没按预期工作大量站点拒绝访问还有一回我在配置中打开了robots: true却发现某些站点的请求被统一拒绝。粗看以为是被封了 IP但日志里的 User-Agent 显示请求头完全是我们自己的而且其他站点一切正常明显不是 IP 被封。顺着这个方向查下去发现问题的根源出在 robots 规范化上Brozzler 需要以域名或者更细粒度为单位去取 robots 规则如果域名规范化逻辑处理得不对同一站点可能被当成多个不同的站点去请求重复请求的频率超过了站点阈值然后就触发了访问限制。把域名的规整逻辑理顺、为高频站点设置合理的抓取间隔之后拒绝访问的现象就消失了。遇到这种问题我的建议是抓取请求头和 robots 文件的实际内容先人工核对再去看调度策略。很多时候目标站点反爬了只是表面现象真正的坑藏在更靠前的任务规整、代理路由这些细节里。最后再分享一点个人心得。Brozzler 的价值在于忠实还原页面这决定了它非常适合做存档、回溯、取证但它的资源消耗和运维成本也明显高于普通 HTTP 爬虫。所以接到采集需求时我建议先想清楚是要干净的数据还是要完整的页面视图。如果能通过接口拿字段就尽量别搬出浏览器级别的大炮如果确实要可回放的页面快照那 Brozzler 整套架构值得你好好研究。另外我习惯把 ZooKeeper 和 WARC 输出目录放到 SSD 上这个改动比调大多数浏览器参数更能直接降低延迟尤其是在队列规模扩大之后收益非常明显。

相关新闻

Kotlin Lambda与匿名函数实战:闭包、集合操作与性能陷阱

Kotlin Lambda与匿名函数实战:闭包、集合操作与性能陷阱

我早期做Android开发的时候,最不习惯Kotlin的地方不是空安全,也不是协程,反而是Lambda表达式和匿名函数。明明在Java里要写一整套匿名内部类才做得完的事,Kotlin一行就给你整整齐齐地解决了。一开始只觉得“哇,好简洁”…

2026/10/14 5:07:01 阅读更多 →
Vite的这个问题坑了我三天,原来如此解决!

Vite的这个问题坑了我三天,原来如此解决!

上周在给一个中后台项目升级时,我遇到了一个诡异的问题:生产环境构建后,某些动态导入的组件居然消失了,而开发环境一切正常。更离谱的是,控制台没有报错,只是页面渲染时直接空白,仿佛这些组件从…

2026/10/14 5:06:01 阅读更多 →
vLLM-Omni V2工程实践:多模态推理的调度范式跃迁

vLLM-Omni V2工程实践:多模态推理的调度范式跃迁

1. 这不是一篇技术报告,而是一次面向工程落地的坦诚复盘“写在vLLM-Omni V2 tech report发布前的一些杂谈”——这个标题本身就很耐人寻味。它没说“详解”、没提“架构图”、更没用“重磅发布”这类营销腔,而是用了“杂谈”二字,还特意点明“…

2026/10/14 5:06:01 阅读更多 →

最新新闻

云智变AI:从大纲到定稿,把论文写作变成一条可执行的“学术生产线”|云智变AI官网www.yunzhibian.cn

云智变AI:从大纲到定稿,把论文写作变成一条可执行的“学术生产线”|云智变AI官网www.yunzhibian.cn

你有没有算过,写一篇论文到底要切换多少个工具? 大纲用思维导图软件,文献用PDF阅读器加笔记工具,数据分析用SPSS或R,图表用Excel或Origin,正文用Word,查重降重用这个网站,AIGC检测用…

2026/10/14 6:23:26 阅读更多 →
大模型驱动的装修AI助手:知识库搭建与对话引擎实践

大模型驱动的装修AI助手:知识库搭建与对话引擎实践

装修这件事,最磨人的往往不是搬砖,而是问问题。我去年给房子做翻新,第一反应是上网搜“瓷砖通铺要不要做对缝”,结果答案分成两派,一派坚持要对缝才好看,另一派说这是智商税,两边分析得头头是道…

2026/10/14 6:23:26 阅读更多 →
从会思考到能干活:AI Agent工具调用与任务规划实战

从会思考到能干活:AI Agent工具调用与任务规划实战

1. 从“会聊天”到“能干活”:AI 能力跃迁的底层逻辑过去两年,大家跟 AI 打交道的方式基本停留在“你问我答”这个层面。不管是写文案、改代码还是做翻译,本质上都是模型在“动嘴”——它给你一段文字,你自己拿去用。但最近一段时…

2026/10/14 6:23:26 阅读更多 →
CSDN博客-3-FDE求职与薪资-年包百万的岗位为什么搜不到

CSDN博客-3-FDE求职与薪资-年包百万的岗位为什么搜不到

年薪 120-150 万的 FDE,为什么你在招聘网站上搜不到?搜岗关键词 薪资全解搜"FDE"只出来三个岗位——不是没有,是你搜的关键词不对。与此同时,字节、蚂蚁、智谱、阿里云的 FDE 岗位年包已经开到 70 万-105 万。 这是 FD…

2026/10/14 6:23:26 阅读更多 →
中兴微工具v1.5.zip拆包指南:半小时判断工具包是否值得投入

中兴微工具v1.5.zip拆包指南:半小时判断工具包是否值得投入

简介:中兴微工具v1.5是一款面向开发人员与系统维护人员的微系统管理工具包,主要用于系统诊断、性能监控、软件升级及数据备份恢复等场景,适合具备一定技术基础、需要对微系统进行深入管理与优化的用户使用。压缩包共收录357个文件&#xff0c…

2026/10/14 6:23:26 阅读更多 →
自动化测试与持续集成中的Git实战:分支策略、提交规范与Tag管理

自动化测试与持续集成中的Git实战:分支策略、提交规范与Tag管理

先说一个很常见的现象:很多团队的自动化测试跑不起来,或者跑起来天天报错,根子不在测试代码,而在 Git 版本控制配合上。版本一乱、分支一多、提交一乱,持续集成就成了摆设。这也就是为什么我想把“自动化测试”和“持续…

2026/10/14 6:22:26 阅读更多 →

日新闻

AnyPS5通用适配层设计:兼容性与性能的工程取舍

AnyPS5通用适配层设计:兼容性与性能的工程取舍

1. 从"AnyPS5"这个名字说起:它到底想解决什么问题第一次看到"AnyPS5"这个标题,我脑子里冒出来的第一个念头是:这大概率是一个围绕"跨平台运行"或者"通用适配"做文章的项目。名字里的"Any"…

2026/10/14 0:00:41 阅读更多 →
Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

1. 项目概述:Flutter跨平台二手交易应用开发作为一名长期从事移动应用开发的工程师,我最近完成了一个基于Flutter框架的二手物品交易平台项目。这个项目最吸引我的地方在于它完美结合了Flutter的跨平台优势与HarmonyOS的生态特性,实现了"…

2026/10/14 0:00:41 阅读更多 →
DFS算法解决飞机降落调度问题实战

DFS算法解决飞机降落调度问题实战

1. 项目背景与核心思路飞机降落问题是一个经典的调度优化场景,也是算法竞赛和面试中的高频题目。这个题目要求我们合理安排多架飞机的降落顺序和时间,确保所有飞机都能安全着陆而不发生冲突。在实际航空管制中,这类问题直接关系到飞行安全和机…

2026/10/14 0:00:41 阅读更多 →

周新闻

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

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

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

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

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

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

2026/10/13 16:22:04 阅读更多 →
影刀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/13 22:01:27 阅读更多 →
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/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练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/12 18:11:17 阅读更多 →