fuzz字典选型与工具链实战:从路径发现到清洗去噪

简介:在Web安全测试与渗透测试中,路径发现是资产梳理与攻击面摸排的关键环节。目录扫描依赖高质量的fuzz字典,但字典的价值并不在于词条数量,而在于分层结构与场景匹配。本文从路径发现的基础概念出发,讲解如何按目标类型(静态站、API服务、后台管理)选用合适的字典,详细介绍ffuf与dirsearch的参数配置、结果判读方法,并针对高频问题给出避坑建议。同时,通过脚本对字典进行去噪、瘦身与交叉验证,帮助安全从业者提升路径扫描的准确率与效率,建立可持续维护的字典知识库。

1. fuzz字典不是堆词量:先想清楚“全”是给谁用的

拿到一份号称“史上最齐全”的web fuzz字典,第一反应往往是直接扔进dirsearch跑一遍。实际跑完会发现:扫出来的东西很多,真正能用上的很少——不是字典不行,而是没搞清楚这份字典的边界。fuzz字典解决的是“路径发现”问题,它的价值不在词条总数,而在覆盖结构和场景匹配度。静态站、API服务、后台管理、云存储桶,这四类目标需要的字典完全不是一回事。这篇笔记就把这套字典的选型逻辑、接入工具链的参数配置、以及我踩过的几个典型坑讲清楚,适合正在做授权测试或路径梳理的从业者参考。

2. 字典背后有逻辑:按目标类型做分层选型,比盲目跑完更值

2.1 为什么默认字典总是“看起来全、扫不深”

很多下载下来的字典体积不小,但词条构成很混乱:常见路径、备份文件、参数名、Tomcat管理路径、云厂商存储桶前缀混在一起,一把梭跑下来噪点极高。这套fuzz字典的合理之处在于,它按用途做了目录分层,而不是单一一个大文件。我一般会把字典分成四层来看:

  • 路径层:/admin、/api、/v1、/.git、/backup 这类目录发现用
  • 文件名层:index.php.bak、config.php.swp、web.config、.env 这类敏感文件发现用
  • 参数层:id、page、file、redirect、url 这类参数名爆破用
  • 扩展名层:.php、.jsp、.asp、.json、.xml 这类配合路径做组合探测

判断一套字典健不健康,先看它是否做了这种分层。如果只有一个几千行的txt从头扫到尾,大概率会淹没在404响应里。工具层面的常见做法是分层扫描:先用路径层做粗筛,再用文件名层针对敏感区域做细扫,这样命中率比一把梭高很多。

2.2 按目标类型选字典:静态站、API服务、后台管理

选字典不能只看目标是不是一个“网站”,要看它的技术形态。纯静态站用带大量动态路径后缀的字典就是浪费时间;API服务需要的不是路径,而是资源名和版本号。

  • 静态站 / 文档站:优先用文件名层字典,重点找 .bak、.old、~ 结尾的编辑器残留文件。这类站点目录结构简单,但历史遗留文件往往藏在线文档路径里。
  • API 服务:重点关注 /api/v1/users、/api/swagger-ui.html、/actuator、/graphql 这类路径。动词型路径(/getUserInfo)在这个场景下的意义不大,真正有用的是资源型路径加 HTTP 方法组合。
  • 后台管理类:/admin、/manage、/system、/console、/debug 这类路径要单独跑,并且配合低频率、高延迟的参数设置,避免直接把登录接口打崩。
  • 云存储场景:/bucket-name、.s3.amazonaws.com 前缀、OSS 域名探测这类词,普通目录字典里覆盖不到,需要单独追加。

所以拿到这套字典后的第一件事,不是直接跑,而是先看清楚它的目录结构,把场景对应的字典挑出来。命令层面可以用 find 快速浏览:

find /path/to/fuzz-dict -maxdepth 2 -type f -name "*.txt" | sort

这段命令把字典目录下两层内的所有 .txt 文件列出来并排序,用来确认字典文件的分层是否符合预期。常见的做法是:路径类字典文件命名通常包含 path、dir、directory 关键字,文件类包含 file、backup、sensitive,参数类包含 param、query。如果排序后发现这些文件确实分开了,这套字典的底子是好的;如果全挤在一个文件里,说明需要自己做一次拆分。

2.3 字典里藏着“环境标记”:怎么识别一套字典的健康度

字典文件本身也能透露出很多信息。值得看的三个维度:换行符、词条长短分布、是否带注释。

Linux 下用 file 命令能快速判断编码,CRLF 换行的字典在一些严格解析参数的工具里会有坑,比如 Wfuzz 对结尾的 \r 处理就经常出问题。这时候要先转成 LF:

sed -i 's/\r$//' /path/to/dict/*.txt

词条长短分布决定了扫描效率:全是十几个字符的长路径会让扫描队列拉长,全是短路径又容易产生大量无效请求。我一般会看一下最长和最短路径:

awk '{ print length, $0 }' /path/to/dict/sensitive-files.txt | sort -n | tail -20

这条命令按词条长度排序,打印最长的20条。如果出现类似 .git/config 这种本身就是完整路径的词条,说明这份字典混合了路径和文件命名,需要拆开。带注释的字典要重点看:注释往往标明这份字典适用的中间件版本或场景,比如某些词条只对旧版中间件有效,在新版本上就是纯噪声。

3. 把字典接入工具链:ffuf 与 dirsearch 的参数配法和结果判读

3.1 把字典喂给 ffuf:基础命令与过滤器的意义

ffuf 是目前路径发现场景里用得比较顺手的工具,它的核心优势是支持多字典组合和多条件过滤。先看最基础的目录扫描命令:

ffuf -u http://target.com/FUZZ -w /path/to/fuzz-dict/path-layer.txt \ -mc 200,301,302,403,500 \ -fc 404 -fs 12345 -t 50 -rate 100

-u 指定目标URL,FUZZ是占位符,字典里的每个词条都会替换到这个位置;-w 指定字典文件;-mc 是匹配的响应码白名单,200和301最常用,403也要留,因为有时候路径存在但被权限拦截;-fc 404 直接过滤掉404响应;-fs 过滤掉特定响应大小,这个参数很关键,很多站点对不存在的路径统一返回一个固定大小的404页面,过滤掉它能少看一大堆垃圾结果。线程和速率要看目标承受能力,我一般先用 -rate 100 做试探,稳定后再慢慢往上加。

跑完之后拿到的是命中路径列表。这时候要做的不是看200的路径,而是先看301和403——301跳转说明路径存在但可能指向另一个域名或带后缀的路径,需要跟进;403在不少场景下比200更有价值,因为它往往表示路径存在但禁止访问。ffuf 支持递归扫描,常见做法是加 -recursion 参数,遇到目录类型命中后自动往下一层跑。但递归深度要控制,建议 -recursion-depth 2,太深会把请求量放大好几倍,得不偿失。

3.2 dirsearch 做快速分层:配置项怎么调

dirsearch 是另一套顺手的工具,和 ffuf 的思路不太一样,它是目录扫描专用,内置了很多默认字典和扩展名逻辑。我一般会用它对目标做第一轮快速梳理,再用 ffuf 做精细验证。dirsearch 的关键参数如下:

dirsearch -u http://target.com -e php,jsp,json -x 404,403 \ -t 30 --random-agent --exclude-status=500,502

-e 指定要追加的扩展名列表,跑一遍相当于把同一条路径用不同扩展名各探测一次;-x 排除不想看的响应码;--random-agent 随机化 User-Agent,避免字典刚跑几十条就被日志特征拦掉;--exclude-status 把服务端错误排除,500、502这类响应在路径扫描里没有太多参考价值,可能是程序异常,不一定是路径存在。

dirsearch 跑完会输出一个报告文件,里面按响应码归档了所有命中项。我一般只看 200、301 和 403 三个分类。403 的路径需要人工确认:如果字典里跑出来一个 /admin 返回 403,而目标站点本身用的是另一个管理路径,那这个结果的价值有限;如果目标站根本没有 /admin,那这个 403 很有可能是服务端对不存在路径做了统一拦截,属于干扰项。

3.3 结果判读:响应码相同不代表路径真实存在

这是最容易翻车的一环。很多站点的 404 和真实路径的 200 页面大小完全一样,或者所有不存在的路径都返回 200 再在页面里写“未找到”。这时候只看响应码完全不够,得结合响应体和响应时间。

curl -s -o /dev/null -w "code: %{http_code}, size: %{size_download}, time: %{time_total}\n" \ http://target.com/nonexistent-path-12345

先手动探测一个大概率不存在的随机路径,记录下它的响应码、页面大小和响应时间,作为基线。再去和字典命中的路径比对:如果命中路径的 size 和基线完全一致,哪怕响应码是 200 也要标记为疑似误报。响应时间也是一个辅助指标:存在路径通常会在服务端做逻辑处理,响应时间会略长;不存在路径往往是快速返回统一错误页。把这些数据记下来,后面第 5 章讲去噪脚本时会用上。

4. fuzz 字典实战避坑:四个高发翻车现场与排查记录

4.1 现象:字典一跑就被封 IP,日志里全是超时

原因:字典里混合了太多高权重路径词条,加上线程开得大,目标服务端在短时间内收到了超量的请求,触发了频率限制。这类问题在带了 login、api 等接口词汇的字典里尤其明显。

解决:压缩线程数,同时引入随机延迟。ffuf 里的做法是加 -p 0.1-0.3 让每个请求之间随机停顿 100 到 300 毫秒。更体面的做法是先做一次小样本探测,用 30 个词条跑一遍,观察响应时间的变化斜率。如果延迟持续爬升,说明服务端已经在限流边缘了,这时候要降速率而不是换字典。我一般把 -rate 控制在 50 到 80 之间,除非目标是纯静态站。

4.2 现象:结果里全是 200,但每个页面内容都相同

原因:目标用了前端渲染框架,服务端对所有未匹配路由统一返回同一个 index.html 页面,响应码 200。这类站点用路径字典去扫,命中率几乎为零,因为路由表在客户端 JS 里。

解决:切换思路,不再用字典扫描路径,改成先抓取页面的 JS 文件列表,再提取 JS 里定义的路由字符串。常见做法是用子域名枚举加上 JS 内容分析,而不是继续堆字典词条。字典在这种场景下的价值只有配合真实路径前缀才成立,比如已知有个 /app 路由,再往下面叠加字典词条做二级路径爆破。

4.3 现象:接口路径扫出来了,但参数爆破结果全是空

原因:字典里的参数层词条来自通用场景,比如 id、page、name,这些在 REST 风格接口里并不适用。REST 接口的参数通常是路径参数,嵌套在 URL 路径段里,而不是 query 字符串。比如 /api/v1/user/123,你的字典是 /api/v1/user?id= 的格式,完全对不上。

解决:针对接口场景先抓包看真实请求格式,再决定要不要跑参数爆破。常见做法是先用路径字典扫出 /api/v1/user 这个资源点,再手测几组参数组合,确认参数传输方式是 query 还是 path,然后再写自己的参数词条文件。通用参数字典在这种场景只是辅助,真正有价值的是从历史请求里提取真实参数名。

4.4 现象:字典文件在 Windows 下生成的,跑起来报错或内容错乱

原因:换行符问题。Windows 下的 CRLF 换行在部分工具里会导致词条末尾带 \r,扫描结果里会出现带隐藏字符的路径,请求发出去后服务端返回 302 或 400,但又查不出原因。

解决:用第 2.3 节里的 sed 命令做一次全局替换,把 CRLF 转成 LF。转完之后再用 head -n 5 抽查几行,确认词条格式干净。这类问题很隐蔽,表现出来就是“随机有几个路径明明存在却扫不到”,很多时候不是字典词条不够,而是格式污染导致请求路径不合法。

5. 提升命中率的字典工程:去噪、瘦身与覆盖验证

5.1 用脚本去掉高概率 404 噪声词条

字典用久了会发现,有些词条在几乎任何站点上都不存在,比如 /path_that_never_exists、/test_xyz 这类占位词条。它们存在的意义是早期的格式调试,在正式扫描里就是纯噪声。可以用脚本和响应大小做一次清洗。思路是先采集基线响应大小,再用脚本过滤掉那些只产生基线大小的词条。脚本如下:

import requests import sys target = sys.argv[1] dict_file = sys.argv[2] baseline_size = int(sys.argv[3]) output_file = sys.argv[4] with open(dict_file, "r", errors="ignore") as f: words = [line.strip() for line in f if line.strip()] clean_words = [] for word in words: url = target.rstrip("/") + "/" + word try: resp = requests.get(url, timeout=5, headers={"User-Agent": "Mozilla/5.0"}) if resp.status_code != 404 and len(resp.content) != baseline_size: clean_words.append(word) except requests.RequestException: continue with open(output_file, "w") as f: f.write("\n".join(clean_words)) print(f"raw: {len(words)}, cleaned: {len(clean_words)}")

这个脚本会逐个请求字典里的词条,把返回 404 或响应大小等于基线值的词条过滤掉,剩下的写入新文件。第一次跑完你会看到清洗前后数量差距非常大,尤其是那些从别的字典里合并过来的词条。

清洗前的准备步骤很重要:先手动请求一个不存在的路径拿到 baseline_size,再用第 3.3 节的 curl 方法确认这个 size 在多次请求下是稳定的。如果目标有负载均衡,不同节点返回的 404 页面大小可能不同,这时候要把 baseline 设成区间而不是单一值,脚本也要相应改成abs(len(resp.content) - baseline_size) > threshold这种写法。

5.2 按响应码做二次筛选,生成场景子字典

第一次清洗完成之后,字典的体积会小很多,但还不够精致。接下来按响应码把词条归成“确定存在”“疑似存在”“被拦截”三类。这个阶段不需要再发请求,直接消费上一次扫描的应答记录即可。常见做法是让 ffuf 输出 JSON 格式的结果文件,再用脚本处理:

ffuf -u http://target.com/FUZZ -w cleaned-dict.txt \ -mc 200,301,403 -o result.json -of json

然后写一个简短的分析脚本,按状态码统计词条:

import json from collections import defaultdict with open("result.json") as f: data = json.load(f) groups = defaultdict(list) for item in data["results"]: groups[item["status"]].append(item["input"]["FUZZ"]) for status, words in groups.items(): filename = f"dict_status_{status}.txt" with open(filename, "w") as f: f.write("\n".join(sorted(set(words)))) print(f"status {status}: {len(words)} words -> {filename}")

这样做的好处是,后续再碰到同类目标时可以直接按响应码选用对应字典。我之前对某跨平台系统的后台做了两轮扫描,第一次用了混合字典,跑了很长时间,回头用这份“按状态码归档”后的 403 和 301 字典复扫,结果近一半的有效路径在首轮被混在噪声里没细看。

5.3 用核心词库交叉验证覆盖完整性

字典清洗到一定程度后,要回答一个核心问题:该有的路径覆盖到了没有?交叉验证的办法是准备一个小而精的核心词库,包含一定数量在同类目标上必然存在的路径,比如 /robots.txt、/favicon.ico、/.well-known/security.txt、/sitemap.xml。先用核心词库跑一遍目标,确认工具链和字典都能正常命中,再换大字典,最后对比两次结果的差异。

差异部分需要人工确认:如果大字典跑出来的结果没有包含核心词库的命中项,说明大字典被过度清洗了,或者过滤条件写得太严格把真实路径也滤掉了。另外,交叉验证还有一个附加价值:能帮你判断目标站点的路径风格。比如核心词库里有个词条在 A 站返回 200、在 B 站返回 302、在 C 站返回 404,这本身就是一种信息——不同站点的路径处理逻辑不同,后续选字典时可以根据这个特征做倾向性调整。

6. 把字典变成自己的知识库:版本管理与增量更新习惯

字典不是下下来就完事了,它需要持续维护才能真正变成自己的东西。我现在的做法是:保留原始压缩包,单独建一个 working 目录做日常使用,任何清洗和分类都在 working 里完成,不动原始文件。配合 git 做版本管理,每次往字典里加词条都留一条提交记录。这样做的价值在于,当某次扫描出现奇怪结果时,能通过 git diff 回看最近改了什么。

增量更新的主要来源有三个:一是授权测试中真实出现的路径每次都记录到一个“新词”文件里;二是阅读历史报告,把高价值路径摘出来;三是看目标响应特征,比如返回 403 的路径往往结构相似,这些规律适合手工归纳成模式词条。这套字典用顺手之后,扫描的命中率会有明显提升——因为它的词条都是经过真实场景检验的,而不是单纯堆量。从那以后我每次拿到一份新字典,都会强制走一遍“分层、清洗、交叉验证、归档”这套流程,虽然前期多花一点时间,但后面每次扫描都能省回好几倍时间,希望帮到你。

本文还有配套的精品资源,点击获取

相关新闻

SolidWorks二次开发:用.NET API实现参数化建模与装配体联动

SolidWorks二次开发:用.NET API实现参数化建模与装配体联动

简介:本资源是一套基于SolidWorks 2000–2003时代VC6开发环境的二次开发实践项目,面向机械设计自动化初学者与CAD软件集成开发者,聚焦参数化建模这一核心工程需求。项目通过COM接口调用SolidWorks API,实现零件尺寸驱动、特征自动…

2026/10/21 6:22:33 阅读更多 →
ObjectARX中文字符集配置:zh-chs语言包安装与避坑指南

ObjectARX中文字符集配置:zh-chs语言包安装与避坑指南

简介:针对AutoCAD 2010二次开发中ObjectARX向导工具条图标在VS2008下无法显示的问题,这份zh-chs中文语言包提供了轻量而直接的修复方案。它面向需要在Visual Studio 2008中正常使用ObjectARX向导模板的开发者,无论是初次搭建开发环境&#xf…

2026/10/21 6:22:33 阅读更多 →
litellm统一多模型调用:从碎片化适配到统一网关的工程实践

litellm统一多模型调用:从碎片化适配到统一网关的工程实践

1. 从一个真实困境说起:多模型调用的碎片化之痛如果你正在做AI应用开发,大概率遇到过这样的场景:项目初期用某家的大模型API跑通了原型,效果不错,上线后想加一个备用模型做降级容错,结果发现两家的接口参数…

2026/10/21 6:21:33 阅读更多 →

最新新闻

华为云Hadoop伪分布式安装实战指南

华为云Hadoop伪分布式安装实战指南

1. 项目概述:为什么从伪分布式开始学Hadoop,而不是直接上集群?“华为云hadoop伪分布式安装学习笔记(一)”这个标题里藏着一个非常务实的起点——它没写“高可用集群部署”,也没提“PB级数据处理实战”&…

2026/10/21 7:09:51 阅读更多 →
Cursor找不到的SQL表和PDF文档,Graphify建图后一次查询全定位

Cursor找不到的SQL表和PDF文档,Graphify建图后一次查询全定位

本文摘要:新增 SQL 或 PDF 文档后,向量索引滞后让 AI 答非所问。Graphify 以 AST 确定性建图,单次查询穿透代码、SQL 与文档。 一、问题与结论 周三下午切到 feature/billing 分支,往 db/schema.sql 加了 CREATE TABLE user_prof…

2026/10/21 7:09:51 阅读更多 →
从极简命名到响应式核心:轻量级前端工具库rea的设计与实现

从极简命名到响应式核心:轻量级前端工具库rea的设计与实现

1. 从“rea”这个标题说起:一个极简命名背后的完整项目思维第一次看到“rea”这个标题的时候,我脑子里蹦出来的第一反应是——这大概率又是一个被随手起的项目代号。做技术的人都有这个毛病,项目文件夹命名从来不走心,test、demo、…

2026/10/21 7:09:51 阅读更多 →
从rea命名到响应式核心:实时数据处理与状态同步实战

从rea命名到响应式核心:实时数据处理与状态同步实战

1. 从“rea”这个标题说起:一个极简命名背后的完整项目思维第一次看到“rea”这个标题的时候,我脑子里蹦出来的第一反应是——这大概率又是一个被随手命名的项目。做技术的人都有这个毛病,项目文件夹建好的那一刻,名字往往就是脑子…

2026/10/21 7:09:51 阅读更多 →
Docker基础入门:从环境一致性到生产就绪镜像构建

Docker基础入门:从环境一致性到生产就绪镜像构建

1. 这不是“学个命令就完事”的 Docker 入门——它是一次对软件交付逻辑的重新理解很多人点开“Docker基础入门”这个标题,心里想的是:“哦,又一个教 pull、run、build 的教程。”结果学完发现,自己还是写不好 Dockerfile&#xf…

2026/10/21 7:09:51 阅读更多 →
lingbot-map建图项目实战:从零跑通SLAM与地图构建

lingbot-map建图项目实战:从零跑通SLAM与地图构建

1. 从“lingbot-map”这个名字说起:它到底想解决什么问题第一次看到“lingbot-map”这个项目名,我脑子里冒出来的第一个念头是:这大概率是一个跟“地图构建”或者“空间映射”相关的机器人项目。拆开来看,“ling”可能是某个前缀缩…

2026/10/21 7:08:51 阅读更多 →

日新闻

统一内存+量化:锐龙AI Max PRO 400如何本地跑320B大模型

统一内存+量化:锐龙AI Max PRO 400如何本地跑320B大模型

这段时间硬件圈和AI圈都在传一个事:AMD锐龙AI Max PRO 400系列把最高192GB统一内存搬进了PC形态的产品里,按宣传口径,本地跑320B参数的大家伙不再是纸面概念。我第一反应倒不是“内存真大”,而是这话背后的含金量——它把过去只能…

2026/10/21 0:00:11 阅读更多 →
AI助手深度使用体验:对话质量、长文本处理与指令遵循如何留住用户

AI助手深度使用体验:对话质量、长文本处理与指令遵循如何留住用户

1. 从“封号重开”这个行为说起:用户到底在追求什么“封号重开”这四个字,放在任何产品语境里都带着一股决绝的味道。一个账号从零开始积累使用记录、调教偏好、沉淀工作流,背后是大量的时间和精力成本。正常情况下,没有人愿意主动…

2026/10/21 0:00:11 阅读更多 →
ROS中YOLOv3工程落地:通信同步、坐标变换与性能调优

ROS中YOLOv3工程落地:通信同步、坐标变换与性能调优

1. 为什么在ROS里硬刚YOLOv3不是“炫技”,而是工程落地的必经之路我第一次在某高校机器人实验室看到那台搭载Jetson TX2的移动底盘原地打转、反复识别错垃圾桶时,就意识到:单纯跑通darknet_ros demo和真正让YOLOv3在ROS里“干活”&#xff0c…

2026/10/21 0:00:11 阅读更多 →

周新闻

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

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

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

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

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

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

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

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

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

2026/10/21 4:27:17 阅读更多 →

月新闻

我发现了一个新思路:用 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/20 10:02:08 阅读更多 →
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/20 9:50:17 阅读更多 →
黑夜航拍船只数据集训练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/20 9:50:45 阅读更多 →