news 2026/10/8 1:05:06

Python课设实战:文字点选验证码识别与自动点击全流程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python课设实战:文字点选验证码识别与自动点击全流程

简介:这是一套用于Python课程设计的文字点选验证码识别方案,面向需要完成选字类验证码课设或入门OCR方向的学生与开发者。整个工程围绕“点击选择文字”这一交互式验证码场景展开,覆盖从训练样本准备、模型加载、图像预处理到识别结果输出的完整链路。方案基于小样本训练,仅用约300张验证码图片即可达到96%准确率,单次识别约100~300ms,并已在Windows下的Python 3.6、3.8、3.10环境中测试通过。代码经编译后可在1核2G低配服务器上稳定运行,适合部署演示。压缩包共48个文件,约121.82MB,主要包含19个py源码文件、10个png图片样本、4个pyd编译模块、4个jpg示意图、bin模型文件、txt/md说明文档以及Web服务相关配置等,另有动图演示,便于快速核对效果。已有437人学习下载,适合作为课设参考、算法复现或后续扩展的基础工程。

1. 为什么点选验证码是Python课设里的“硬骨头”

文字点选验证码是现在很多业务系统还在用的交互式验证码:页面上给出一张带文字的图片,上面散落着若干汉字或词语,用户必须按照提示文字的顺序,逐个点击图片中对应的文字。对键盘侠来说,这就是拼眼力;对写Python课设的人来说,这就是一条完整的“图像检测 + OCR识别 + 坐标映射”流水线。很多人初看觉得简单,不就是找到文字再点吗?真上手才发现,干扰线、字体变形、文字旋转、背景纹理,能把一个看似入门级的目标检测题变成调参玄学。

这篇笔记就是要把“点击选择文字验证码识别”这条链路讲透:从方案选型、数据集制作、模型训练,到避坑和演示,全部落到可复现的代码和参数上。适合正在做Python大作业、毕业设计或想练手计算机视觉的同学,也适合想快速评估“这个方向值不值得投入时间”的工程师。接下来直接从选型开始。

2. 先选方案:为什么模板匹配在点选验证码上必然翻车

2.1 模板匹配的问题:位置变化和字体变形

很多人在刚接到“文字点选验证码识别”这个需求时,第一反应是用模板匹配。理由很朴素:提示文字是给定的,我提前把每个字的模板截下来,在图片里滑窗找相似度不就行了。

模板匹配在纯白底、字间距大、字体固定的验证码上确实能跑。但点选验证码为了防脚本,通常不会让你这么舒服:文字会旋转、加粗、加干扰线、用不同背景纹理,甚至同一个字在不同图片里用了不同字体。模板匹配的本质是像素级相关性计算,一旦字体轮廓或颜色变化超过阈值,相似度就断崖下跌。我见过一组实测数据:同一字体、不同旋转角度下,模板匹配的置信度能从0.9掉到0.5以下,完全不够用来做点击决策。

2.2 目标检测负责“在哪”,OCR负责“是什么”

所以现在做文字点选验证码,主流做法是拆成两个子问题:先用目标检测模型把图片里每个候选文字的位置框出来,再对每个框里的文字做识别,得到“文字内容 + 框坐标”的列表。最后拿提示文字去这个列表里匹配,找到对应的坐标,再换算成点击位置。

这正好是两条成熟技术线的组合:

  • 目标检测:YOLOv5/v8、SSD或者更轻量的关键点检测都行。课设场景我建议YOLOv5或v8,部署简单,训练快,显存要求低。
  • 文字识别:CRNN、PaddleOCR,或者直接用PaddleOCR的det+rec流程。中文点选场景优先考虑PaddleOCR,中文识别效果好,而且有现成的Python部署方案。

为什么不直接用OCR的检测头一起做?因为两者任务目标不同:OCR检测是把“文字行”当成一个区域,而点选验证码要把“单个字”当成独立目标。直接用OCR检测头,经常会把相邻两个字合并成一个框,导致后续点击坐标错误。

2.3 课设的选型优先级:先看数据量,再选模型

课设和工业项目最大的区别是:你只有有限的时间,大概率没有现成数据集。所以我一般按这个优先级选:

  • 数据量少于500张:不要自己训检测模型,直接用轻量文字检测模型(PaddleOCR自带的可控性更高),或基于YOLO做小样本微调。
  • 数据量1000张以上:YOLOv8n(nano版)训练,分类头用PaddleOCR的文本识别做二次识别。
  • 数据量极少又没有采样渠道:先用程序合成数据,用合成数据训练检测模型,再用少量真实数据微调。

这里插一个重要前提:不管选哪个模型,你都要先把“点选验证码”当成一个图像检测问题来理解,而不是一个“识别整张图然后输出点击顺序”的黑匣子任务。不要相信端到端输出,要相信可解释的中间结果。

2.4 整体流程:粗定位、细识别、坐标映射

整个识别流程我建议按这条线走:

  1. 图片输入:读入验证码图,记录原始宽高。
  2. 目标检测:检测图中所有候选文字框,输出框坐标和尺寸。
  3. 单字识别:把每个框裁剪出来,缩放或保持原有比例,送入文字识别模型,输出字符串。
  4. 提示匹配:把提示文字(比如“点击 清明节 中的 清 明 节”)按字拆分,与识别结果做匹配。
  5. 坐标转换:把匹配到的框中心点从模型坐标系映射回原图坐标系,输出点击顺序。

第2、3步是模型,第4、5步才是大学问。很多翻车案例就出在第5步:模型训练和推理用的图片尺寸是640x640,但页面原图是320x240,你如果不做坐标缩放,点击位置会偏得离谱。后面避坑章我会专门讲这个。

核心代码如下:

def solve_captcha(image_path, prompt_text): # 1. 读原图,记录尺寸 img = cv2.imread(image_path) h, w = img.shape[:2] # 2. 检测 -> 得到候选框列表 boxes boxes = detect_text_boxes(img) # 3. 识别每个候选框 -> (box, char) result = [] for box in boxes: crop = crop_box(img, box) char = recognize_char(crop) result.append((box, char)) # 4. 匹配提示文字 target_chars = list(prompt_text.replace(" ", "")) matched = match_chars(result, target_chars) # 5. 映射坐标 clicks = [] for box, char in matched: cx, cy = box_center(box) clicks.append((int(cx * w / IMG_SIZE), int(cy * h / IMG_SIZE))) return clicks

逻辑说明:这一段把所有关键步骤抽象成了五个函数,其中detect_text_boxes和recognize_char后续可以用 YOLO 和 PaddleOCR 替换实现。IMG_SIZE是检测模型的输入边长,代码里我用w / IMG_SIZE做了等比缩放,实际上如果检测前没有做letterbox,这里要用具体缩放比例。参数说明放在真正实现的时候再展开。

3. 数据准备:没有数据集,就先“人造”一套

3.1 数据来源:采集、合成、标注怎么选

点选验证码的课设,卡住大部分人的不是模型,而是数据。你可以有几个来源:

  • 手动从公开网页采集:需要写爬虫,但注意很多验证码图片是接口动态返回的,采集时一定要保存原图,不要存截图。截图的色彩空间和分辨率变化会影响训练。
  • 程序合成:用PIL或OpenCV“画”出文字点选图,这是课设最稳的方案,可以精确控制字体、旋转、背景纹理、干扰线数量。
  • 公开数据集:确实有一些带文字标注的检测数据集,但和“点选验证码”的分布差异很大,直接拿来训练,换到真实图片上经常泛化失败。

对课设来说,我推荐“合成为主、少量真实样本校准”的组合。合成数据能解决“有没有”的问题,真实数据才能解决“好不好”的问题。

3.2 标注格式:用YOLO的txt格式,还是VOC的xml?

如果你用YOLO,那标注格式是每个图片一个txt文件,每行内容为:

class_id x_center y_center width height

坐标是归一化到[0,1]的相对值,x_center和y_center是框中心的相对坐标,width和height是框宽高相对图片宽高的比例。这个格式有一个很大的优势:即使图像被缩放或做letterbox,坐标仍然是相对的,不容易出错。缺点是看txt文件不能直观确定框在哪,所以标注工具很重要。

我一般用Labelme先标注成JSON,再写一个脚本转YOLO格式。这样可以在标注时直接看到文字内容,方便后续核对。转换脚本的关键代码如下:

import json import glob import os def labelme_to_yolo(json_path, img_w, img_h, class_map, out_dir): with open(json_path, "r", encoding="utf-8") as f: data = json.load(f) lines = [] for shape in data["shapes"]: label = shape["label"] points = shape["points"] # [[x1,y1], [x2,y2]] xs = [p[0] for p in points] ys = [p[1] for p in points] x_min, x_max = min(xs), max(xs) y_min, y_max = min(ys), max(ys) # 归一化 cx = ((x_min + x_max) / 2) / img_w cy = ((y_min + y_max) / 2) / img_h bw = (x_max - x_min) / img_w bh = (y_max - y_min) / img_h lines.append(f"{class_map[label]:d} {cx:.6f} {cy:.6f} {bw:.6f} {bh:.6f}") out_name = os.path.basename(json_path).replace(".json", ".txt") with open(os.path.join(out_dir, out_name), "w", encoding="utf-8") as f: f.write("\n".join(lines))

参数说明:class_map是字典,把“清”“明”“节”这样的文字映射到0、1、2的类别编号;img_w和img_h是原图尺寸。这里要注意,Labelme标注的坐标是像素坐标,YOLO需要的是归一化坐标,所以必须除以宽高。如果标注框是旋转框,YOLO标准格式不直接支持,需要先转成外接矩形;点选验证码的文字通常没有大角度旋转,用外接矩形足够。

3.3 合成数据脚本:用PIL画出可控制的验证码图

合成数据是课设能不能在两天内跑起来的生命线。我提供一个自己常用的生成脚本骨架:

from PIL import Image, ImageDraw, ImageFont import random import os FONT_PATH = "simhei.ttf" # 中文字体,Windows可用 C:/Windows/Fonts/simhei.ttf def synth_captcha(out_dir, chars_pool, num_images=1000): os.makedirs(out_dir, exist_ok=True) for i in range(num_images): # 随机选3~4个汉字作为目标 n = random.randint(3, 4) target_chars = random.sample(chars_pool, n) # 画布,背景用浅色纹理 img = Image.new("RGB", (320, 180), (random.randint(230, 250), random.randint(230, 250), random.randint(230, 250))) draw = ImageDraw.Draw(img) # 随机放置目标汉字 for idx, ch in enumerate(target_chars): font = ImageFont.truetype(FONT_PATH, random.randint(22, 32)) x = random.randint(10, 240) y = random.randint(10, 120) draw.text((x, y), ch, font=font, fill=(random.randint(10, 90), random.randint(10, 90), random.randint(10, 90))) # 干扰线 for _ in range(random.randint(3, 8)): x1, y1 = random.randint(0, 320), random.randint(0, 180) x2, y2 = random.randint(0, 320), random.randint(0, 180) draw.line((x1, y1, x2, y2), fill=(random.randint(100, 200), random.randint(100, 200), random.randint(100, 200)), width=1) img.save(os.path.join(out_dir, f"syn_{i:05d}.png"))

参数说明:chars_pool是你准备生成的目标汉字集合,建议写20-50个常用字,与提示文字的“点击 XXX 中的 X”保持一致;FONT_PATH必须指向真实存在的中文字体文件,否则PIL会直接抛异常;干扰线数量和文字尺寸可以调节,但不要让文字旋转角度超过15度,否则YOLO检测框不稳定。合成图片建议保存原图和对应的提示文本,因为训练检测模型只需要图片和框标签,但之后调试匹配逻辑时需要提示文本。

3.4 数据增强:让模型不那么“脆”

只靠合成数据训练,模型很容易在真实图片上翻车。原因很简单:合成的图片太“干净”了。真实验证码会把文字压扁、拉长、加噪点、叠加背景图案。所以训练之前要做增强,至少包含:

  • 随机旋转:-15度到+15度。
  • 随机亮度/对比度:模拟不同屏幕截图的色彩差异。
  • 高斯噪声:模拟压缩伪影。
  • 随机裁剪:增强模型对文字位置的鲁棒性,注意裁剪后要同步更新标注框。

用OpenCV或albumentations都能实现增强,但albumentations更省事。

import albumentations as A import cv2 transform = A.Compose([ A.Rotate(limit=15, border_mode=0, p=0.5), A.RandomBrightnessContrast(p=0.6), A.GaussNoise(p=0.3), A.RandomSizedCrop(min_max_height=(100, 160), height=180, width=320, p=0.5), ], bbox_params=A.BboxParams(format="yolo", min_visibility=0.5)) # 读图和对应txt,做增强 # boxes格式: [[cx, cy, w, h]...] augmented = transform(image=img, bboxes=boxes)

参数说明:border_mode=0表示旋转后补黑边,不要用白色补边,因为验证码背景不是纯黑;min_visibility=0.5表示裁剪后框至少有50%区域在图中,否则丢弃,避免出现半个字。这个参数直接影响训练稳定性,如果设太低,模型会学到“半个字也是字”,检测框会偏。

4. 训练与识别实现:从YOLO检测到点击坐标输出

4.1 检测模型的训练参数选择

YOLOv8训练点选文字检测,参数不用太夸张。我这里给出一个课设级别的配置思路:

  • 模型:yolov8n.pt 预训练权重。
  • 图片尺寸:640x640。如果原图是320x180,YOLO会自动letterbox到640,训练时不需要你手动resize。
  • batch size:显存不够就8,够就16。
  • epochs:合成数据500张左右,训练80-100轮足够,多了反而过拟合。

训练命令:

from ultralytics import YOLO model = YOLO("yolov8n.pt") model.train( data="captcha.yaml", epochs=100, imgsz=640, batch=8, patience=20, project="./runs", name="captcha_det" )

参数说明:patience=20是早停阈值,如果20轮内验证集没有提升就停止训练,防止课设时间被浪费在无效迭代上。data是YAML配置,里面至少要有train标签、val标签和类别列表,格式如下:

train: dataset/images/train val: dataset/images/val nc: 20 names: ["清", "明", "节", ...]

这里有个很容易踩的坑:nc必须和names长度完全一致,一旦不一致,训练会直接报错,或者类别错乱。我自己遇到过一次,训练出来的模型把“清”识别成“节”,看概率曲线又很正常,最后检查发现是YAML里类别顺序和标注文本不一致。这个坑我放在避坑章再展开说。

4.2 单字识别:用PaddleOCR还是自训CRNN?

检测框出来后,每个框就是一个文字图片。这里有两种路线:

路线A:直接用PaddleOCR的识别接口。好处是中文识别开箱即用,不挑字体;坏处是模型较重,CPU推理慢,单字识别反而要几毫秒到几十毫秒,且它对单字没有上下文,偶尔会把“末”识别成“未”。

路线B:用简单的CRNN或MobileNet分类器。点选验证码的文字集合是有限的,你完全可以把“识别几十个汉字”当成一个图像分类任务来解。每个框缩放到统一大小,用MobileNetV3或ResNet18微调。这个路线在课设里更可控,准确率能达到95%以上。

我建议课设选路线B,原因有二:第一,分类模型对“字库”的边界把握清晰,题外字不会乱识别,这很重要;第二,答辩时你可以解释“我用了一个轻量分类网络,把检测到的文字图块映射到预定义的字库”,比端到端OCR更好讲。

下面是一个基于PIL和PyTorch的分类器构建骨架:

import torch import torch.nn as nn from torchvision import models, transforms def build_classifier(num_classes): model = models.mobilenet_v3_small(weights=None) model.classifier[3] = nn.Linear(model.classifier[3].in_features, num_classes) return model # 预处理:所有裁剪图缩放到 64x64 transform = transforms.Compose([ transforms.Resize((64, 64)), transforms.ToTensor(), ])

参数说明:mobilenet_v3_small输入要求64x64,这个尺寸已足够识别单个汉字,再大只会增加计算量。num_classes对应字库大小,和检测模型的类别数保持一致。训练时用交叉熵损失,优化器用Adam,学习率1e-3,10轮左右就能收敛。

4.3 匹配与坐标映射:这个函数决定了你能拿多少分

模型跑通之后,最后的匹配和坐标映射是纯逻辑代码。很多同学在这里栽跟头:检测出20个框,识别结果也对,但输出坐标就是点不到验证码的中心。

问题出在letterbox上。YOLO推理时会把输入图按比例缩放并填充灰边到640x640,模型输出的坐标是相对于640x640的,你需要逆运算得到原图坐标。有人直接用“原图宽高/640”来缩放,遇到非等比图片时坐标就会偏移。

正确做法是记录YOLO推理时的缩放因子和填充偏移。用ultralytics的API其实有更简单的方式:YOLO的predict返回的boxes坐标默认已经是原图坐标系了。

from ultralytics import YOLO model = YOLO("./runs/captcha_det/weights/best.pt") img = cv2.imread("demo.png") results = model.predict(img, imgsz=640, conf=0.5) # results[0].boxes.xyxy 已经是原图坐标 for box in results[0].boxes.xyxy.cpu().numpy(): x1, y1, x2, y2 = [int(v) for v in box] cx, cy = (x1 + x2) // 2, (y1 + y2) // 2 print(cx, cy)

逻辑说明:这段代码拿到的是原图坐标系下的点,可以直接用于后续点击。但如果验证码在页面中被CSS缩放显示,这里拿到的原图坐标还不等于页面坐标,需要在浏览器端再除以缩放比例。这个细节非常隐蔽,我在避坑章里会单独讲。

4.4 一个完整的“检测+识别+点击”入口

最后把检测、分类、匹配串起来。这里假设你已经训练好了检测模型best.pt和分类模型cls.pth。

def solve_captcha(img_path, prompt_text): # 1. 检测 results = det_model.predict(img_path, imgsz=640, conf=0.45) crop_boxes = results[0].boxes.xyxy.cpu().numpy() # 2. 识别每个框 char_map = [] for box in crop_boxes: x1, y1, x2, y2 = [int(v) for v in box] crop = img[y1:y2, x1:x2] char = classify_char(crop) # 返回字库idx char_map.append((char, (int((x1+x2)/2), int((y1+y2)/2)))) # 3. 提示匹配 targets = list(prompt_text.replace(" ", "")) result = [] for t in targets: for char, pos in char_map: if char == t: result.append(pos) break return result

参数说明:conf=0.45是检测置信度阈值,对点选验证码来说,0.4-0.5之间比较合适。太高会漏字,太低会多框。char_map里存的是字库索引和坐标,匹配提示时直接用字库索引比对,不要比对字符串,因为不同字体的同一个字,分类器输出的索引是一样的。提示文本拆字时要去掉空格,有些提示是“点击 清明 中的 清明”,两个词可能重叠,匹配时要设计一个优先级:按提示顺序依次找,找到就把该坐标从候选列表里移除。

5. 点选验证码识别避坑指南:五个典型翻车现场

5.1 现象:检测框莫名偏移,点击位置偏左上角

原因:训练时用了矩形标注,但实际文字是倾斜的,外接矩形中心不等于文字视觉中心;或者推理时图片被隐式缩放。

解决:如果文字旋转较多,标注时用旋转框,YOLOv8支持angle模式;如果只是推理时偏移,检查是否有letterbox。我自己的做法是:先输出检测框画在原图上,逐一核对,不要直接信坐标。

5.2 现象:分类器把“未”识别成“末”,准确率卡在92%

原因:字库里有形近字,且分类器输入分辨率太低,笔画差异被压缩掉。

解决:把分类器输入从64x64提到96x96,同时注意做归一化时不要丢失笔画的深浅信息。如果还不行,在字库里加一组成对样本做“刻意对比”,用两次训练或加三元组损失来拉大区分度。形近字问题在点选验证码场景里非常常见,尤其是“己、已、巳”这种三胞胎,靠分类器硬扛不如在匹配逻辑里做二次校验。

5.3 现象:训练时损失很低,真实图片上检测不到文字

原因:合成数据和真实数据分布不一致。合成图片背景干净,真实图片有纹理、压缩伪影、文字模糊。

解决:在合成脚本里增加背景纹理和模糊处理。我建议用一个简单的模糊增强:cv2.GaussianBlur(img, (3,3), 0),模拟验证码图片被二次压缩后的效果。更关键的是,训练集中至少要加入20-30张真实图片做微调,哪怕手动标注,这一步不能省。

5.4 现象:点击坐标在图像上是对的,页面里就是点不中

原因:这是一个非常经典的课设翻车点。验证码图片在页面里被CSS缩放显示,而你点击的目标坐标是原图坐标。比如原图是320x180,页面显示成160x90,那所有坐标都要除以2。

解决:在Selenium或Playwright点击时,先获取验证码元素的rect,然后按scale_x = rect.width / img_w换算。注意验证码元素在页面中可能有边框或padding,坐标系基准不同,需要按元素content区域重新对齐。

我见过最隐蔽的一种情况:页面里验证码图片居中显示,但图片外层有一个内边距,导致图片左上角不是元素左上角。这时候你要在点击前scrollIntoView,然后取getBoundingClientRect(),用图片实际显示区域重新计算坐标。

5.5 现象:答辩时被问“模型为什么这么设计”,答不上来

原因:很多人直接把一个预训练YOLO拉过来训练,没记录选型依据,也没对比数据。

解决:这是一个“非技术坑”,但比技术坑更致命。做课设时建议保留一组对比数据:模板匹配的失败率、YOLO检测的准确率、分类器的混淆矩阵。至少做一组“有没有数据增强”的对比实验。不需要很严谨,但要把实验记录写进报告。这是最有效且省力的答辩准备方式。

6. 进阶玩法:把课设从“能跑”做到“能讲”

到这里,核心链路已经全部打通:合成数据 → 目标检测 → 单字分类 → 提示匹配 → 坐标映射 → 自动点击。但对于课设来说,“能跑”只算及格,“能讲清楚设计过程”才算优秀。最后一个章节,我分享几个能显著提升完成度的进阶做法。

第一,给识别过程加可视化。做一个简单的Python脚本,把检测框、识别结果、点击顺序按序号画在图片上,输出成一张带标注的图。这不仅是展示给老师看,更是你自己调试时最直观的工具。我每次调坐标偏移时都是看这张图,比看数字快得多。

第二,做一个函数式API,把识别流程封装成几个独立函数。这样在演示时,可以一条命令跑出结果,也能在答辩时流畅地展示“调参 → 重跑 → 看结果”的过程。

第三,增加一个“失败重试”机制。点选验证码的图片往往有多个候选批次,如果第一次点击失败,可以重新取一张图。这个机制在代码上很简单,但能极大提升体验感,也是课设报告里的一个亮点。

如果还有余力,可以考虑用ONNX把检测模型导出,做成一个可脱离训练环境的轻量推理文件。这样答辩时不用现场装PyTorch,也可以直观地说明“模型可以部署到生产环境”。这个细节在评审老师眼里非常加分。

回过头看,这个课设最核心的技巧不是模型调参,而是“把任务拆成检测、识别、匹配三步,然后分别验证”。我自己的教训是:一开始太相信端到端流程,跳过中间验证,结果在坐标映射上浪费了整整一天;后来老老实实把完整脚本按步骤拆开,每步打印中间结果,问题很快定位到是letterbox换算错误。希望这篇笔记对你也有同样的用处,能帮你绕过这些坑,把有限的时间花在真正有挑战的部分上。

希望帮到你。

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/8 1:04:51

eFuse+MCU电源路径保护设计:TPS259483与STM32L031C6实战

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

作者头像 李华
网站建设 2026/10/8 1:04:50

Beyond Compare 4 文件与文件夹对比实战:从命令行到 Git 集成

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

作者头像 李华
网站建设 2026/10/8 1:04:31

eFuse与STM32协同实现嵌入式电源路径保护设计

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

作者头像 李华
网站建设 2026/10/8 1:04:10

eFuse与MCU协同的电源路径保护设计:从原理到实现

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

作者头像 李华
网站建设 2026/10/8 1:04:10

eFuse+MCU智能电源防护:TPS259483与STM32L041组合实战

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

作者头像 李华
网站建设 2026/10/8 1:04:00

工业嵌入式系统电源路径保护:TPS259483AYWPR与MK20DX128VFM5协同设计

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

作者头像 李华