从御剑到dirsearch:Web目录扫描工具完整实战指南

1. 为什么从御剑转向dirsearch:一个老牌工具的优缺点盘点

1.1 御剑的先天优势与尴尬现状

御剑在早期是Windows平台上很多入门者最先接触的目录扫描工具,GUI界面简洁、双击即用,预置字典丢进去就能开扫,确实帮一代人完成了启蒙。但用了三五年之后,你会发现它的尴尬非常明显:一年不更新的字典、对Python生态零集成、扫描速度完全依赖单线程设计,遇到稍微有点防护的目标基本就是反复超时。

真正让我产生迁移念头的是两个场景。第一个是扫描一个中等规模的Web站,御剑跑了将近半小时才扫完两层目录,而同期我用命令行工具只花了不到三分钟就完成了相同字典的遍历,差距不是一点点。第二个是字典管理,御剑的字典需要手动打开文件编辑、格式敏感,增删路径一不小心就会因为编码或换行问题失效,这在自动化流程里是没法接受的。目录扫描本来就是重复性强的活,工具如果连字典都管理不好,效率无从谈起。

1.2 dirsearch的定位与核心优势

dirsearch是一个纯Python实现的命令行目录扫描器,开源、跨平台、持续维护。它的定位不是简单的"字典跑一遍",而是面向实战场景的自动化目录探测工具,把线程控制、递归扫描、扩展名过滤、结果输出、代理接入这些细节都做了很好的整合。

用一句话概括它和御剑的区别:御剑是一个能用的工具,dirsearch是一个可编程、可集成、可定制的扫描框架。对做攻防测试的人来说,这意味着你可以把它嵌入到自己的自动化脚本里,扫描结果直接导出成结构化文件,后续处理完全不受GUI限制。对只想要一个简单工具的人来说,dirsearch的默认配置也足够友好,一条命令就能完成基础扫描,学习成本远低于想象。

我最看重的三个特性是:支持递归扫描且能控制递归深度、字典完全透明可自定义、输出格式涵盖文本和JSON等结构化格式。这三个特性解决了目录扫描中最核心的三个问题:扫不全、看不懂、没法处理。

1.3 两个工具在真实工作流中的互补定位

说句公道话,御剑并没有完全被淘汰,在快速验证单个小站点的时候,打开图形界面点一下鼠标也有它的方便。我的建议是把它当作"应急快速验证"的工具,而把dirsearch当作日常主力。真正的工作流应该是:先用dirsearch做全面深度扫描,再用御剑或浏览器直接访问验证重要路径。

这种组合的好处在于,dirsearch负责把目录和文件的候选集找出来,御剑负责在你需要快速核对的时候提供图形化的反馈。但如果你只依赖御剑,就会陷入扫描慢、结果单一、无法自动化的泥潭。这也是为什么我建议每一个做Web安全的人彻底掌握dirsearch,哪怕以后有更高级的工具出现,它的设计思路和参数逻辑都会让你快速迁移。

2. dirsearch完整安装指南:从零到可用的三种方式

2.1 准备Python环境需要留意什么

dirsearch要求Python 3.8及以上版本,这个要求其实非常宽松,Windows、Linux、macOS都能跑。在Windows上安装Python时有一个关键勾选:把Python添加到PATH环境变量。这一步漏了,后面命令行执行python指令会直接报"不是内部或外部命令",很多人就卡在这里。

在Linux环境上,多数发行版已经预装Python 3,直接用python3 -V确认版本即可。macOS用户要注意的是,系统自带的Python 3可能版本较老,建议使用包管理器安装新版。还有一种方式是直接用虚拟环境隔离,但dirsearch本身依赖很少,这个步骤可有可无,如果你平时有管理Python环境的习惯就顺手建一个。

注意:新版Python安装时如果勾选了"Add Python to PATH",后续就不用手动配置环境变量了。已经安装但没有勾选的,可以在系统环境变量里手动追加Python安装目录和Scripts目录。

2.2 源码安装与全局调用配置

安装方式最推荐的是直接从Git源码仓库拉取,因为这样能保证拿到最新功能,而pip安装的版本可能滞后。命令如下:

git clone https://github.com/obskyr/dirsearch.git cd dirsearch pip install -r requirements.txt

依赖安装完毕后,可以验证一下是否可用:

python dirsearch.py -h

在Windows上,每次都要输入python dirsearch.py显得有点啰嗦,可以在相同目录下创建一个dirsearch.bat批处理文件,内容就一行:

python %~dp0dirsearch.py %*

这样后续直接在cmd里敲dirsearch就能执行,省去路径切换的痛苦。Linux和macOS用户则可以做一个软链接到/usr/local/bin,或者直接在.bashrc里写一个alias:

alias dirsearch='python3 /path/to/dirsearch/dirsearch.py'

注意,源码目录不要频繁移动,否则alias路径会失效。我一般固定放在~/tools/目录下,定期git pull更新即可。

2.3 依赖管理与版本更新技巧

dirsearch的依赖非常少,核心就是requets库,加上一些标准库模块。安装依赖后基本不会再遇到缺包的情况,但还是建议在更新工具后顺手执行一次pip install -r requirements.txt,防止新版本引入了额外的依赖。

版本更新就更简单了,cd到目录里git pull,重启终端就能生效。我遇到过一种情况:更新后扫描结果格式和旧版不一致,配置文件格式也有变化。解决办法是更新前先备份自己的自定义字典和配置,更新后对比一下默认配置的变更点,不要无脑覆盖。如果你用的是pip安装的版本,更新用pip install --upgrade dirsearch即可,但我依然推荐源码方式,灵活性高很多。

3. 核心参数拆解:扫描命令背后的每条逻辑

3.1 基础扫描:第一步先学会正确指定目标

最简单的用法是对单个URL发起扫描:

python dirsearch.py -u https://example.com -e php,html,js

这个命令告诉工具扫描example.com的目录结构,并按php、html、js后缀来搜索文件。这里有一个常见的理解误区:目录扫描并不是扫描出所有文件和目录,而是在字典的候选路径后面拼上你指定的扩展名去测试,所以扩展名选得越贴近目标技术栈,结果越精确。比如目标是PHP写的,你就加php;是ASP.NET的,你就加aspx。

如果没有加-e参数,dirsearch默认会按一个内置的扩展名列表去匹配,这会导致大量无效请求,速度变慢、结果里充满噪音。我自己的习惯是扫描前先简单判断目标的技术栈,再针对性设置扩展名,尽量收敛请求范围。要扫描多个目标时,用-L参数指定一个包含多个URL的文本文件,一行一个目标:

python dirsearch.py -L targets.txt -e php

这种批量模式适合一次授权测试多个资产的情况,结果会自动按目标分组,方便后续整理。

3.2 目录递归、扩展名过滤与字典选择

目录扫描的核心价值不只是扫根目录,而是能把找到的子目录继续向下探测,这就是递归扫描。默认情况下dirsearch对找到的目录会递归下去,用-r参数控制是否开启,用--max-recursion-depth参数限制深度。

我建议默认开启递归,但把深度限制在2到3层。太深了不仅耗时成倍增长,还可能触发目标的防护机制,导致IP被临时封禁。延展一下,这个工具对字典的处理方式很透明,默认字典在db/dicc.txt(版本不同路径可能不同),你可以自己准备一份包含路径和文件名候选的字典,每行一个,用-w参数指定:

python dirsearch.py -u https://example.com -w /path/to/custom.txt -e php

自定义字典是提高扫描质量最直接的手段。默认字典覆盖面广但缺乏针对性,如果你已经知道目标站点使用的CMS类型、框架路由风格,自己维护一份贴合目标特征的字典,效果比任何默认字典都好。我还习惯把常见备份文件后缀也加进扩展名列表,比如.bak、.sql、.zip,如果目标存在敏感文件,这种配置往往能一击命中。

3.3 线程、延迟与超时:性能和安全性的平衡

并发控制是目录扫描里最需要经验的环节。dirsearch用-t参数控制线程数,默认是25,用--delay参数控制每次请求的间隔。这两个参数直接决定了扫描对目标的影响程度。

在授权测试场景下,我一般遵循一个原则:先小批量探底再逐步加压。如果目标响应速度正常、没有任何防护,线程调到50到70问题不大;如果发现响应变慢或出现拒绝服务迹象,立刻降回20以内并加上0.5秒延迟。这里有个容易被忽略的点:超时时间。用--timeout设置请求超时,默认的30秒在部分场景下太长了,建议调成15秒左右,因为目录扫描请求量大,单个请求卡住30秒会把整个队列拖得很慢。

提示:并发参数不是越高越好。扫描是为了收集信息,不是为了测试目标极限,一旦把目标扫挂了,后续的验证工作就全断了。我在实战里见过太多新手为了追求速度把线程调到200,结果目标直接不响应,管理员也发现异常,得不偿失。

4. 实战演练:一次完整的授权站点扫描复盘

4.1 场景设定与字典准备

以一次授权测试为例,假设目标是一个典型的业务站点,技术栈为PHP加MySQL,站点路径中存在管理后台、接口文档、备份文件等敏感资产。这个场景的完整操作如下:

先看目标返回的响应头,确定Web服务器类型和技术栈。通过响应头里的X-Powered-By或者页面特征基本可以锁定PHP环境,这时扩展名只保留php、html、js,避免请求一堆无意义的.aspx路径。

字典方面,我选了一份自己的常见路径字典,大概2000行,涵盖backup、admin、api、config、database、install、logs、temp等高频敏感路径,又追加了带年份和版本号后缀的备份文件路径,比如backup.sql、index.php.bak之类。准备好这些,扫描命令如下:

python dirsearch.py -u https://target.example -e php,html,js -t 30 --timeout 15 -o result.json --format json

-o参数指定结果输出文件,--format指定输出格式。我习惯输出一份JSON格式供后续脚本处理,同时也用文本格式输出一份方便人工阅读。

4.2 从扫描到识别真实敏感路径

扫描执行过程中,dirsearch会对响应状态码做标记,默认标记为200、301、302、403等。这些状态码的含义差别很大,200代表路径存在且可访问,301/302代表重定向,403代表存在但禁止访问。不要只盯着200看,403往往更有价值,它说明目标路径真实存在但权限控制严格,是后续测试的重点对象。

整个扫描过程大约花了三分钟,结果里我最关注的是几个路径:/admin/返回200但跳转到登录页,/api/docs返回403,/backup/直接返回200且目录列表开启。这三个信息已经足够说明问题:目标存在管理后台,API接口带有文档,备份目录暴露。接下来要做的是验证访问控制是否严密,而不是继续无意义地扩大扫描面。

这个阶段很多人会犯一个错误:看到什么路径都打开看一遍,做完之后就结束了。正确的做法是围绕高价值路径做二次测试:对管理后台尝试弱口令、对api文档查看接口参数、对备份目录尝试下载关键文件。目录扫描只是信息收集的起点,后续的测试动作才决定这次测试的价值。

4.3 结果输出格式与二次分析

扫描结果的解析直接关系后续自动化流程的效率。JSON格式的输出结构大概是:

{ "target": "https://target.example", "results": [ {"status": 200, "path": "/admin/", "content-length": 256}, {"status": 403, "path": "/api/docs", "content-length": 1024} ] }

拿到这个文件后,我用脚本按状态码分类统计,把200和403的结果单独拉出来做验证列表。内容长度(content-length)也是过滤噪音的好指标:如果大量响应都是同一个固定大小,很可能是目标统一返回的"页面不存在"模板,属于误导信息,需要过滤掉。

还有一个小技巧:把结果里的URL全部提取出来,写进自己维护的"资产清单"里,下次扫描时可以直接作为起点,不用重新扫一遍。这样的积累习惯,会让你在处理同类目标时越来越快。

5. 常见问题与避坑清单:那些文档里不会写的事

5.1 高频踩坑记录

先说几个我几乎每次给别人排查问题时都会遇到的状况。

第一个是目标URL忘记加协议前缀,直接写example.com。dirsearch会报错提示无法解析URL,这个问题很好解决,但确实是出现频率最高的低级错误。

第二个是Windows环境下命令行编码问题。扫描结果里如果包含中文路径,cmd窗口可能出现乱码,这不影响实际输出文件,但会影响终端阅读。解决办法是在执行前先执行chcp 65001切换UTF-8编码。

第三个是字典路径带空格。Windows的路径经常是C:\My Tools\dirsearch\wordlist.txt,这样直接传给-w参数会解析失败。解决办法是给路径加英文双引号。

第四个是Python版本冲突。如果你的系统同时装了Python 2和Python 3,直接敲python可能是旧版,导致语法错误。用python3显式指定版本,或者配置好虚拟环境。

还有一个非常隐蔽的问题:目标存在CDN或负载均衡,多次扫描会命中不同节点,导致结果不一致。这种场景下最好先固定Host解析到某个具体节点再扫,否则结果的准确性要打折扣。

5.2 误报判断与验证方法

误报是目录扫描里最烦人的问题,没有之一。常见情况是目标对不存在的路径统一返回200,响应体是一个自定义的404页面,这种情况下扫描结果会大量出现假阳性。判断方法很简单:随机取几个结果里的路径,用curl手动请求并对比响应体内容:

curl -I https://target.example/admin/ curl -I https://target.example/no-such-path

如果两个返回的Content-Length几乎一样,说明目标在用统一模板响应,那些200结果基本都不能信。遇到这种情况,可以修改dirsearch的匹配规则,用--exclude-status 200把所有200都排除掉,或者更细致一点,用--exclude-text "404 Not Found"把包含特定文字的响应过滤掉。

误报的另一个来源是重定向,很多目标会把未知路径统一重定向到首页或登录页,导致所有请求返回302。在处理这类目标时,我建议加上--skip-on-429参数,避免因为请求过于频繁触发限流后,后续所有请求全部返回429,形成另一种形式的"全量误报"。

5.3 与Burp Suite联动扩展工作流

目录扫描和Burp Suite结合是实战里的黄金组合。方式是扫描时把流量导入Burp,利用Burp的代理进行中转:

python dirsearch.py -u https://target.example --proxy http://127.0.0.1:8080

Burp接收流量的好处是,你可以在Burp里直接看到扫描发出的每个请求,包括Cookie、Header、响应细节。这样一旦扫描结果里出现可疑路径,你不需要再重新手动发请求,直接在Burp的History里找到对应的请求,右键发送到Repeater做进一步调试。

反向的操作同样有价值:先手动在Burp里浏览目标业务,把浏览过程中产生的API路径、页面路径整理成字典,再用dirsearch配合这个字典扫描。这种"人工发现路径+工具遍历变体"的组合,往往能发现单纯跑字典发现不了的隐藏接口。比如业务系统里有一个下载功能,路径是/download?file=xx,你把这个路径放进字典再用工具扫描变体,就可能扫出/download?file=../etc/passwd这类严重问题。

我曾经用这个思路在授权测试中快速定位到一个未授权的导出接口,当时目标的前端交互里有一个导出Excel的功能,我在Burp里抓包看到请求路径是/api/export,把这个路径加入字典后扫描,又扫出了/api/export_all和/api/export_config,其中后者直接泄漏了业务配置信息。整个过程从开始扫描到发现问题不到十分钟,比盲目扩大字典范围有效率得多。

写在最后的经验杂谈

目录扫描工具用多了你会发现,决定扫描质量的核心不是工具本身,而是对目标的理解和字典的积累。dirsearch只是把请求并发出去了,真正宝贵的是你如何解读响应、如何设定扫描策略、如何把结果变资产。

我个人的习惯是,每次扫描结果都会归档到按目标分类的目录里,连同当时的字典和命令一起保存。这样做最大的好处是,当后续测试需要重新梳理资产时,可以直接参考之前的扫描记录,不用翻聊天记录找当时用了什么参数。还有一个值得尝试的扩展方向:把dirsearch和漏扫工具联动,扫描出的路径直接作为漏扫的入口列表,自动化程度会大幅提升。这些经验都是踩坑之后一点点积累的,希望这篇指南能帮你少走一些弯路。

相关新闻

如何把一台安卓手机变成企业微信无人值守机器人:WorkTool 安装配置教程

如何把一台安卓手机变成企业微信无人值守机器人:WorkTool 安装配置教程

如何把一台安卓手机变成企业微信无人值守机器人:WorkTool 安装配置教程 【免费下载链接】worktool 一款安全稳定的Android无障碍服务工具,支持控制企微/微信来运行的无人值守群管理企业微信机器人 项目地址: https://gitcode.com/GitHub_Trending/wo/w…

2026/10/21 1:16:56 阅读更多 →
OpenMontage 的 BFL Webhook 集成指南:FLUX 图像生成如何用事件驱动回调替代轮询

OpenMontage 的 BFL Webhook 集成指南:FLUX 图像生成如何用事件驱动回调替代轮询

OpenMontage 的 BFL Webhook 集成指南:FLUX 图像生成如何用事件驱动回调替代轮询 【免费下载链接】OpenMontage Worlds first open-source, agentic video production system. 12 production pipelines, 100 tools, 700 agent skill and production-knowledge files…

2026/10/21 1:16:56 阅读更多 →
Golang 字符串字面量表示方法

Golang 字符串字面量表示方法

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

2026/10/21 1:16:56 阅读更多 →

最新新闻

解锁 Unity 全部专业功能:UniHacker 跨平台修补原理与操作指南

解锁 Unity 全部专业功能:UniHacker 跨平台修补原理与操作指南

解锁 Unity 全部专业功能:UniHacker 跨平台修补原理与操作指南 【免费下载链接】UniHacker 为Windows、MacOS、Linux和Docker修补所有版本的Unity3D和UnityHub 项目地址: https://gitcode.com/GitHub_Trending/un/UniHacker UniHacker 是一个跨平台 Unity 解…

2026/10/21 1:57:37 阅读更多 →
校园一卡通系统架构设计与落地实践:从单体到设备接入网关的完整方案

校园一卡通系统架构设计与落地实践:从单体到设备接入网关的完整方案

1. 项目从需求到架构的思考路径1.1 一卡通系统到底解决了什么问题很多人觉得校园一卡通就是把食堂饭卡挪到网上,其实远没这么简单。学校里的消费、门禁、图书借阅、上机考勤、宿舍电控这些场景,以前是各用各的卡,各建各的库,财务对…

2026/10/21 1:57:37 阅读更多 →
Qt大图预览不掉帧:用QOpenGLWidget显示QImage的工程模板

Qt大图预览不掉帧:用QOpenGLWidget显示QImage的工程模板

简介:一套基于Qt框架的QOpenGLWidget图像显示示例工程,面向需要掌握OpenGL纹理映射与矩阵变换的中级Qt开发者。资源聚焦如何将QImage像素数据上传为GPU纹理,并通过变换矩阵实现缩放、旋转、平移等交互功能,适用于图像查看器、简易…

2026/10/21 1:57:37 阅读更多 →
SpringBoot重构校园交流墙:从设计到部署全解析

SpringBoot重构校园交流墙:从设计到部署全解析

我在某高校接过一个类似的校园墙系统,从需求调研到最后部署上线,前后折腾了小两个月。那段时间最大的感悟是:校园交流墙这类产品,功能看着简单,但真正落地时要踩的坑特别多——匿名身份怎么处理、内容审核怎么搞、高并…

2026/10/21 1:57:37 阅读更多 →
显示驱动板卡启动引导流程全解析:从电源时序到面板点亮

显示驱动板卡启动引导流程全解析:从电源时序到面板点亮

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

2026/10/21 1:57:37 阅读更多 →
JumpServer 堡垒机一键部署:运维安全审计系统搭建

JumpServer 堡垒机一键部署:运维安全审计系统搭建

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

2026/10/21 1:56:36 阅读更多 →

日新闻

统一内存+量化:锐龙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/20 2:50:50 阅读更多 →

月新闻

我发现了一个新思路:用 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 阅读更多 →