新闻详情

新闻详情

首页 / 资讯中心 / 详情

朴素贝叶斯全解析:原理、三种形态与垃圾邮件分类实战

发布时间:2026/9/28 14:17:22来源:尧图网络
朴素贝叶斯全解析:原理、三种形态与垃圾邮件分类实战
朴素贝叶斯可能是我带过的实习生里最容易被“低估”的一个算法。第一次给团队做技术分享时我提了句“线上垃圾评论拦截用的是朴素贝叶斯”底下一个小伙子脱口而出“那不是教材里的老古董吗”结果三个月后我们把同批数据拉出来跑了一轮对比——当时很火的一个深度文本分类方案和朴素贝叶斯同场竞技没做任何特殊调优朴素贝叶斯的精确率领先了约两个点单条推理耗时连对方模型的零头都不到。小伙子后来在复盘文档里写了一句“当年对分类算法的理解太浅了。”这篇文章想做的事是把朴素贝叶斯真正拆开揉碎讲清楚它的数学原理、三种常见形态如何选型、怎么用它从头搭一个垃圾邮件分类器以及我这些年踩过的坑和上线之后的调优习惯。适合三类人看准备面试、想把分类算法体系补齐的同学业务里急需一个可解释强基线模型的人以及在大模型时代依然需要低成本、高可靠方案的工程师。1. 为什么朴素贝叶斯这个“老古董”还值得精读很多团队现在一上来就奔着深度模型去好像不用BERT就矮人一头。但在真实业务里至少八成场景根本轮不到这些重武器登场。朴素贝叶斯这种几十年前就成型的算法至今活跃在垃圾邮件过滤、垃圾评论识别、推荐召回、异常检测、辅助诊断等方向而且往往是以一个非常不起眼但极其稳定的姿势存在。它训练快、内存占用小、可解释性强还能在小样本场景下给出不错的效果。我一直有个习惯接到任何文本分类任务先花半小时搭一个朴素贝叶斯基线。如果它在干净特征下能跑到90%以上的准确率那就说明数据质量没问题后续换复杂模型是在“增量优化”如果连朴素贝叶斯都一塌糊涂那大概率不是模型不够强而是数据清洗、标签定义或者特征工程出了问题。它是用来区分“数据问题”和“模型问题”的试金石。1.1 在真实业务里它至今活跃的四个战场第一个战场是垃圾邮件和垃圾评论过滤。文本特征天然是高维离散词袋朴素贝叶斯对这种数据的建模非常自然而且需要拦截的类别往往只占少数先验概率的引入让模型一开始就站在一个合理的位置上。第二个战场是推荐系统的冷启动召回。新用户没有行为记录协同过滤无从谈起但可以用朴素贝叶斯根据用户画像和内容类目的先验关系先粗筛一批候选集。它不追求精确排序只要别漏掉太多可能感兴趣的内容就行。第三个战场是医疗辅助诊断和异常检测这类“需要给解释”的场景。医生或风控人员不只想看结果还想知道“为什么判断是阳性”朴素贝叶斯可以直接输出条件概率告诉你是哪个特征贡献了最大权重。神经网络能给出概率但很难给出这样直观的归因。第四个战场是作为复杂模型的底座。很多看似“智能”的规则引擎底层其实就是一张朴素贝叶斯的条件概率表线上跑了几年都没换。原因很简单出问题了能定位指标波动了能解释这些特性在生产环境里比“又提了两个点”更稀缺。1.2 它其实是理解“生成模型”的最佳入口朴素贝叶斯是生成式模型的代表和逻辑回归这种判别式模型有本质区别。判别式模型直接学习P(类别|特征)相当于画一条边界把这个样本分到左边或右边生成式模型学的是P(特征|类别)先弄明白“垃圾邮件长什么样”“正常邮件长什么样”再来判断新邮件更像哪个类别。这个区别在项目里的实际意义是生成式模型可以处理训练数据里没有出现过的特征组合——只要各个词单独见过组合起来也能算概率判别式模型则需要更大数据量去拟合特征之间的交互。朴素贝叶斯的“朴素”假设虽然粗糙但它用极低方差换来了极低偏差尤其是在小样本、高稀疏场景下这个交换非常划算。很多人都没意识到朴素贝叶斯取对数之后其实是一个线性分类器比较的是特征的线性加权和权重就是条件概率的对数比。这一点在面试里经常被问到在工程里也意味着它的决策边界非常简单不容易过拟合。2. 从贝叶斯定理到“朴素”假设拆开看它到底在算什么讲朴素贝叶斯之前必须先把贝叶斯定理这层地基打牢。很多人公式背得滚瓜烂熟但问一句“先验是什么”“似然是什么”就卡住了。这里我用垃圾邮件的场景把每个名词落到实地上。2.1 先验、似然、证据三个名词一次搞懂条件概率是基础P(A|B)表示在B发生的情况下A发生的概率。贝叶斯定理就是用它做一次“因果反转”把P(A|B)转换成P(B|A)的表达式P(A|B) P(B|A) × P(A) / P(B)在分类任务里我们把A换成“类别C”把B换成“样本特征x”。于是想要求的是看到一封邮件的词频特征x之后它属于垃圾邮件C1的概率有多大用公式写是P(C1|x) P(x|C1) × P(C1) / P(x)这里面有三个关键量。P(C1)叫先验概率表示在完全没看内容之前一封邮件是垃圾邮件的概率。简单说就是业务大盘里垃圾邮件占多少。如果历史数据里10封邮件有1封垃圾那P(C1)就是0.1。P(x|C1)叫似然表示如果这封邮件真的是垃圾邮件它的内容长成x这个样子有多大的可能性。放到词袋模型里就是在“垃圾邮件”这个类别下各个词按当前频率出现的联合概率。P(x)叫证据表示不管什么类别一封邮件内容长成x的概率。它是个归一化常数用来保证概率加起来等于1。做分类时有个关键简化对C1和C2分别算P(C1|x)和P(C2|x)这两个分数的分母都是P(x)一模一样。既然只比较大小分母就可以直接扔掉最终决策规则变成预测类别 argmax P(Ck) × P(x|Ck)这个式子意思很直白在“类别常见程度”和“特征对类别的贴合度”之间取一个综合得分谁得分高就把样本判给谁。2.2 “假装独立”为什么常常不影响分类结果麻烦出在P(x|C1)上。x包含几百个词如果要精确计算“这些词同时出现的联合概率”就得知道词与词之间的所有相关关系这在现实中根本算不了。朴素贝叶斯狠就狠在一个假设所有特征在给定类别时互相独立。也就是说P(x1, x2, ..., xn|C) P(x1|C) × P(x2|C) × ... × P(xn|C)“免费”和“领取”在真实垃圾邮件里明明是强相关的但算法假装它们没关系各自单独统计出现概率然后连乘。我最早学到这里也觉得这假设也太随便了效果应该很差。但后来在实践里慢慢理解了为什么它“歪打正着”。第一分类任务真正关心的是argmax也就是最大概率对应的那一个类别。只要独立假设造成的概率偏差没有颠倒各类别之间的排序最终分类结果就是对的。第二特征之间的相关结构往往在不同类别里是“同方向”存在的——比如“免费”和“领取”在垃圾邮件里一起出现在正常邮件里也因为活动文案而一起出现误差在连乘过程里有一部分会互相抵消。第三独立假设本质上是一个极强的正则化它逼着模型简化问题反而在小样本场景下不容易过拟合。当然说“不影响”是相对的后面我会讲到独立性失效时到底会踩什么坑。但至少现阶段你应该理解朴素贝叶斯不是“算得准”的代表而是“算得巧”的代表。3. 三种朴素贝叶斯形态高斯、多项式、伯努利的选型课朴素贝叶斯不是只有一个固定公式根据特征类型的不同它演化出了三种主流形态。选错形态是新手最常见的错误我见过有人拿到数值型特征就默认用高斯朴素贝叶斯结果效果还不如随机猜测。3.1 高斯朴素贝叶斯连续特征与正态假设当特征是连续值比如身高、体重、温度、传感器读数、设备功耗等高斯朴素贝叶斯假设每个类别下每个特征都服从正态分布P(xi|C) 1 / √(2πσ²) × exp(-(xi-μ)² / (2σ²))其中μ和σ²是根据训练数据按类别分别估计得到的均值和方差。训练过程本质上就是算每一类的μ和σ然后拿它们去拟合测试样本。用高斯朴素贝叶斯时有个细节要注意它要求特征分布接近正态。如果某个连续特征严重偏斜比如大部分值集中在0附近偶尔冒出几个巨大的离群值最好先做log变换、Box-Cox变换或者直接分箱离散化。另外sklearn里的GaussianNB有一个var_smoothing参数作用是给所有类别共享的方差下限防止某个特征在某类里方差为0导致概率炸掉。调参时可以在1e-9到1e-6这个量级上试。不过要特别提醒把TF-IDF向量这种稀疏统计量直接喂给高斯朴素贝叶斯是一个经典错误。TF-IDF虽然数值上是连续的但它根本不是正态分布而且大量值为0用多项式或伯努利形态会合理得多。3.2 多项式朴素贝叶斯词频计数的天然搭档多项式朴素贝叶斯的特征是离散计数最常见的就是词频某封邮件里“免费”这个词出现了3次向量里对应位置就是3。它假设特征服从多项式分布概率估计公式带一项平滑P(xi|C) (N_Ci α) / (N_C α × n)N_Ci表示类别C下特征i出现的总次数N_C表示类别C下所有特征出现次数之和n是特征总数α是平滑系数。为什么必须有平滑因为如果某个词在训练集的垃圾邮件里从未出现过N_Ci就是0概率一乘整个类别变成0这显然不合理。平滑相当于给每个可能性都垫了一点底。α1就是拉普拉斯平滑这也是默认值α越大概率越往均匀方向靠拢对稀有词越宽容α越小模型越相信训练集但也越容易过拟合。在实际调参时alpha我不会只试1.0。短文本场景下我曾调到3.0到5.0之间模型明显对口语化表达更稳而长文本分类里alpha接近0.5反而能让强区分词的话语权更突出。这需要在验证集上搜。3.3 伯努利朴素贝叶斯二值化特征下的行为差异伯努利朴素贝叶斯处理的是布尔特征只管“出现”还是“没出现”不管出现几次。它对每个词计算的是“在类别C下这个词是否出现”的概率因此每个特征只有两个取值。计算P(xi|C)时如果xi1就用出现概率P如果xi0就用1-P。这个微小差别带来的行为差异很大多项式朴素贝叶斯在计算时只累加出现词的贡献根本没出现的词不参与伯努利朴素贝叶斯则会把“未出现”也当成证据参与决策。在短文本里比如标题、弹幕、短信这种只有几十个字的内容里词的“是否存在”往往比“出现几次”更有信号价值伯努利因而表现更好。如果同一封垃圾邮件里“点击”出现12次多项式朴素贝叶斯很容易被这个重复词带偏判定一切包含“点击”的文本都是垃圾伯努利模型只记一次命中反而能避开这种局部轰炸。选择哪个形态本质上取决于你的业务更关心“词出现几次”还是“词有没有出现”。三种形态的选型我用一个表格总结变体特征类型分布假设常见类典型场景高斯朴素贝叶斯连续实数正态分布GaussianNB医疗指标、传感器数据、故障诊断多项式朴素贝叶斯离散计数多项式分布MultinomialNB长文本分类、垃圾邮件过滤、情感分析伯努利朴素贝叶斯布尔二值伯努利分布BernoulliNB短文本、关键词命中、点击购买行为4. 垃圾邮件分类实战从预处理到概率输出的完整回路理论说再多不如直接跑一遍。这一节我用中文垃圾邮件分类作为案例带你把整条链路走通中文分词、向量化、多项式朴素贝叶斯训练、评估。这套流程改改就能复用到新闻分类、评论审核、工单打标等场景。4.1 数据准备与中文分词细节先造一份小数据集用来演示流程。真实项目里你至少要准备几万封带标注的邮件但结构和下面的代码完全一致data [ (恭喜您获得万元大奖点击链接立即领取, spam), (免费领取限量优惠券仅限今天, spam), (视频会员到期提醒请尽快续费, spam), (您的账户存在异常登录请点击验证, spam), (今天下午三点开周会别忘了带报告, ham), (项目进度更新文档已上传到共享盘, ham), (妈妈问你周末回家吃饭吗, ham), (新版产品说明书已发到邮箱请注意查收, ham), ]中文文本和英文最大的区别是英文天然按空格分词中文必须用分词工具。我日常用的是jieba分词后把词用空格重新拼起来这样后面接sklearn的向量化组件非常顺畅import jieba def tokenize(text): return .join(jieba.cut(text)) X [tokenize(text) for text, _ in data] y [label for _, label in data]预处理阶段还有几个容易被忽略的细节。第一停用词表不是万能的像“免费”“点击”“领取”这类高频词恰恰就是垃圾邮件的强信号不能无脑删。第二URL和数字可以统一替换成特殊占位符避免同一链接的不同变化分裂特征空间。第三大小写要统一中文虽然没有这个问题但邮件里混着English的时候要处理。4.2 向量化与模型训练把关键参数说明白向量化我优先用CountVectorizer因为多项式朴素贝叶斯面向的就是“计数”特征。这里有个容易踩的坑中文分词后一开始不能直接套默认的正则分词规则。最稳妥的方式是显式告诉向量化器“按空格切分”from sklearn.feature_extraction.text import CountVectorizer vectorizer CountVectorizer(analyzerlambda x: x.split(), min_df1, max_df0.9) X_vec vectorizer.fit_transform(X)min_df1表示只出现过一次的词也保留min_df2可以把极低频的噪音词滤掉max_df0.9表示去掉90%以上文档都出现的词这些词往往是没有区分度的套话。在真实项目里我会优先试min_df2它能显著压缩特征维度而准确率几乎不降。接下来切分训练集和测试集训练多项式朴素贝叶斯from sklearn.model_selection import train_test_split from sklearn.naive_bayes import MultinomialNB X_train, X_test, y_train, y_test train_test_split( X_vec, y, test_size0.25, random_state42, stratifyy ) model MultinomialNB(alpha1.0, fit_priorTrue) model.fit(X_train, y_train)stratifyy是为了在样本量小的时候保证垃圾邮件和正常邮件的比例在训练集、测试集中一致别切完之后测试集里全是正常邮件那就没法看了。fit_priorTrue表示让模型从训练数据里学习先验概率P(C)。如果训练集里的垃圾邮件比例和真实业务分布一致就保持True如果你为了标注方便在训练集里把垃圾邮件采样到了50%而真实业务里垃圾邮件只有5%就必须改成fit_priorFalse或者手动传入class_prior[0.95, 0.05]否则模型会严重高估垃圾邮件出现的可能性。4.3 评估看什么别只盯着准确率跑完训练很多人喜欢顺手打印一个accuracy就收工。在垃圾邮件场景里准确率是有迷惑性的。假如正常邮件占95%你哪怕把所有邮件都判成正常准确率也有95%但这个模型毫无用处。所以我会看精确率、召回率和混淆矩阵from sklearn.metrics import classification_report, confusion_matrix y_pred model.predict(X_test) print(classification_report(y_test, y_pred, target_names[ham, spam])) print(confusion_matrix(y_test, y_pred))垃圾邮件场景里漏判的代价是用户收到骚扰误判的代价是正常邮件被吞掉。大多数情况下误判的代价远高于漏判因为用户可以不看垃圾邮件但绝不允许自己银行账单被扔进垃圾箱。所以评估时要重点关注spam这一类别的精确率宁可多漏一点也不要过多误杀。以上数据集非常小跑出来的分数肯定不具备统计意义但它把完整链路跑通了。你只需要把这个壳子套到真实标注数据上把预处理部分换成对应的清洗规则就能得到一个能上线的强基线模型。5. 最容易翻车的四个坑以及我在线上环境里的修复记录朴素贝叶斯看起来简单真正上线时每一个细节都可能让你在凌晨被报警电话吵醒。下面这几个坑都是我或者团队同事实际踩过的每一条都有血泪成分。5.1 零概率不是小概率平滑参数怎么调无论是多项式还是伯努利形态只要训练语料里某个词没和某个类别一起出现过它的条件概率就会被估成0。测试阶段一封新邮件如果恰好带着这个词出现连乘之后这个类别的整体概率直接归零。这不是“概率很小”而是变成彻底的零排序直接被颠覆。我见过一个生产事故某封正常邮件里包含一个公司新上线的产品名这个产品名在训练集里从未出现过结果整个正常类别的概率被清零邮件被送进垃圾箱。用户投诉之后我们排查了很久才发现问题。修复手段有两层第一层是拉普拉斯平滑alpha最小给1.0第二层是向量化阶段限制词表用min_df滤掉只出现过一两次的长尾词因为它们带来的更多是噪音而不是信息。5.2 连乘下溢为什么我建议永远在log空间计算如果你有兴趣自己手写一遍朴素贝叶斯一定会在这一步栽跟头。一封邮件有几百个词每个词的概率都远小于1几百个小于1的数连乘之后结果会小得突破浮点数下限变成0。这不是数学上错了而是计算机表示不下了。正确的做法是全程序用对数。把乘法变成加法log P(C|x) ∝ log P(C) Σ log P(xi|C)这样一来原本小到不可表示的数值变成了一堆负数的和数值稳定性完全可控。sklearn内部其实就是这样实现的所以MultinomialNB.fit之后直接.predict没有任何问题。如果你要自己实现验证记得写log版本和原始版本分别跑一遍对比你一定会看到log版本稳如老狗。5.3 独立性假设失效的补救方案这是朴素贝叶斯的“命门”。当两个强相关词在某个类别里频繁共现时独立假设会把它们当作两个独立证据重复加权导致模型对某些词过度敏感。最典型的一次事故是一封正常邮件里写着“点击率数据分析报告”发送人是同事但因为“点击”这个词在垃圾邮件训练集里被反复强化整个正常邮件类别被压到了极低概率。后来我们把向量化方式改成二值化用伯努利朴素贝叶斯重新训练误伤问题立刻缓解。另外一条补救路径是引入ngram_range(1,2)把“点击率”作为一个整体特征纳入词表这样“点击”单字出现时就不会孤零零地触发警报。5.4 样本不均衡对先验的扭曲训练时如果把垃圾邮件比例采样到50%模型学到的P(spam)就是0.5但真实业务里可能只有0.05。先验被扭曲后模型的概率输出整体偏移你再看predict_proba的数值做阈值判断时会把一大批正常邮件推到垃圾侧。我在项目中常用的处理方式有两种一种是让fit_priorFalse强制所有类别等概率把“垃圾邮件究竟占多少”的判断完全交给业务阈值另一种是手动传入真实业务的先验class_prior[0.95, 0.05]让模型的内部排序从一开始就贴近真实世界。这两种方式在不同项目里各有千秋但都比让模型吸一口“假的先验”要好。把四个坑汇总成一张排查表方便你在现场对照问题现象根因修复方案零概率某类得分整体为0未登录词导致条件概率为0拉普拉斯平滑、min_df限制词表下溢手写实现时概率为0浮点数连乘精度不足全log空间计算独立性失效某个词一出现就误杀强相关特征被重复加权二值化、加bigram、特征去重先验扭曲概率输出整体偏离业务训练集类别比例失真fit_priorFalse或手动传class_prior6. 朴素贝叶斯上线之后的进阶调优经验模型跑通只是开始。真正让它适合业务还需要在概率输出层面和模型搭配层面多花心思。6.1 阈值调整与精确率召回率博弈predict()方法默认按0.5概率做硬切分但这个阈值基本不可直接用。垃圾邮件过滤里我通常会把垃圾判定阈值往上抬比如0.6甚至0.7只有模型足够自信才真正拦截。低置信样本落到“疑似垃圾”区间让用户二次确认或让规则引擎再兜一轮。代码上其实就是拿到各类别概率后自己划阈值spam_index list(model.classes_).index(spam) prob_spam model.predict_proba(X_test)[:, spam_index] pred_custom (prob_spam 0.65).astype(int)这里需要注意classes_里的顺序不一定和你的标签顺序一致直接用[1]取spam概率很可能取错列。先通过list(model.classes_)定位再取列是我反复踩过之后养成的习惯。6.2 朴素贝叶斯和逻辑回归怎么搭配使用朴素贝叶斯和逻辑回归在数学上是远亲取对数后的朴素贝叶斯决策边界是线性的逻辑回归也是线性的。区别在于朴素贝叶斯用独立假设和条件概率表来定权重逻辑回归则用优化算法自由学习权重。前者适合小样本、强稀疏、需要解释的场景后者在特征交互复杂、数据量充足时上限更高。在实际工程里我通常不会只选一个。朴素贝叶斯因为速度快、召回稳常被我放在第一层做粗召回一口气从几百万条内容里捞出候选集再用逻辑回归甚至梯度提升树对候选做精排。还有一种很巧妙的用法把朴素贝叶斯输出的概率作为一个特征喂给逻辑回归让上层模型学习“什么时候该相信朴素贝叶斯的判断”。这种堆叠方式在文本分类比赛里经常出现效果往往意外地好。最后说点我自己的习惯。每次接手一个文本二分类任务我都会先花半小时搭一个上面这样的朴素贝叶斯链路把数据质量问题和特征工程问题先暴露出来。它一旦效果好我才有底气继续往复杂模型上走它一旦效果差我通常会先回头查数据标注和预处理而不是急着换算法。最近一次项目里我们甚至用朴素贝叶斯做了一个“可疑评论召回器”每天把几百条低置信评论送给人工审核线上效果比一开始直接上深度模型的方案更省心。常听到有人讨论这个算法够不够先进我的体会是能落地、好维护、出了问题能讲清楚为什么的算法永远都不过时。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

AI大模型Java集成学习笔记:上下文管理与LLMOps配置实战 2026/9/28 18:15:19

AI大模型Java集成学习笔记:上下文管理与LLMOps配置实战

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

阅读更多 →
数据分析师必看!TaoToken 统一 Key 接入 Excel AI 工具链的 config.toml 骨架 2026/9/28 18:15:19

数据分析师必看!TaoToken 统一 Key 接入 Excel AI 工具链的 config.toml 骨架

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

阅读更多 →
DBC导入AUTOSAR避坑指南:ISOLAR-A实战五大高频问题解析 2026/9/28 18:15:13

DBC导入AUTOSAR避坑指南:ISOLAR-A实战五大高频问题解析

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

阅读更多 →
Moonshot Kimi K3 2.8万亿参数深度解析:百万词元上下文+原生视觉,TaoToken 统一 Key 接入配置实战 2026/9/28 18:15:13

Moonshot Kimi K3 2.8万亿参数深度解析:百万词元上下文+原生视觉,TaoToken 统一 Key 接入配置实战

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

阅读更多 →
Buck-Boost升降压Plecs闭环仿真探索:TaoToken统一Key接入与RC网络参数整定 2026/9/28 18:15:13

Buck-Boost升降压Plecs闭环仿真探索:TaoToken统一Key接入与RC网络参数整定

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

阅读更多 →
GitHub Copilot VSCode配置指南:TaoToken统一Key接入与settings.json骨架 2026/9/28 18:15:13

GitHub Copilot VSCode配置指南:TaoToken统一Key接入与settings.json骨架

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

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉