news 2026/9/16 19:32:16

ddddocr中文验证码识别实战:开箱即用的自动化登录方案

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ddddocr中文验证码识别实战:开箱即用的自动化登录方案

1. 项目概述:为什么是 ddddocr,而不是其他方案?

最近帮一个做电商数据采集的朋友解决登录问题,他卡在验证码这一步整整三天——手动输入太慢,用传统 OpenCV + Tesseract 做二值化+OCR,对扭曲、粘连、带干扰线的验证码识别率不到35%,换几个网站就全崩。直到我甩给他一行命令pip install ddddocr,再贴上20行代码,他盯着控制台输出的识别结果愣了三秒:“这就完了?”——没错,这就是 ddddocr 的真实体验:它不是“又一个OCR库”,而是专为中文互联网场景打磨出来的验证码识别“快拆工具包”。

核心关键词里,“Python”是语言载体,“ddddocr”是核心引擎,“验证码识别”是功能本质,“网站登录自动化”是典型落地场景,“完整代码”是交付底线。这五个词串起来,就是一线开发者每天面对的真实战场:不是实验室里的标准MNIST手写数字,而是淘宝登录页上那串带旋转、加噪点、字母大小写混排、还故意把O和0、l和1塞在一起的“防机器”验证码。我试过至少7种主流方案:tesserocr(依赖Tesseract训练,中文识别差)、easyocr(通用强但速度慢、内存吃紧)、chinese_ocr(模型老旧、不维护)、PaddleOCR(功能全但部署重),最后全被 ddddocr 按在地上摩擦。它不追求学术SOTA,只死磕“能跑通、识别准、不崩溃、上手快”这四条命脉。

为什么它能做到?关键在三个设计哲学:第一,模型即服务——内置的CNN+CRNN双模型不是摆设,而是针对国内主流网站(京东、拼多多、12306、政府服务平台)的验证码做过千次微调;第二,零训练门槛——你不需要懂反向传播、不用配GPU、不碰labelImg打标,import ddddocr后直接ocr.classification(img)就出结果;第三,抗干扰直觉化——它默认开启灰度自适应、高斯去噪、投影分割三重预处理,对80%的“人眼勉强能认”的验证码,识别率稳定在92%以上(实测1000张京东登录图,927张一次通过)。这不是玄学,是作者把十年爬虫对抗经验,焊进了模型权重和预处理逻辑里。如果你正被登录自动化卡住,别折腾模型训练了,先试试这个“开箱即用的扳手”。

2. 核心技术解析:ddddocr到底在后台干了什么?

2.1 模型架构与训练数据真相

很多人以为 ddddocr 就是个封装好的黑盒,其实它的底层非常透明。官方文档虽简略,但源码里藏着关键线索:它用的是ResNet18 + CRNN(CNN+RNN+CTC)的混合架构。ResNet18 负责从原始图像中提取鲁棒特征(比如扭曲字符的轮廓、噪点分布规律),CRNN 则负责序列建模——把分割后的字符块按顺序识别出来。重点来了:它的训练数据不是公开数据集,而是作者团队从2019年起,持续抓取国内32个高频网站的验证码,人工清洗后构建的私有数据集,共127万张样本,覆盖4类典型变体:

  • 扭曲型(如12306的波浪线字符,占比38%)
  • 粘连型(如拼多多的字母紧贴,占比29%)
  • 干扰型(如政府网的密集噪点+细线,占比22%)
  • 混淆型(如淘宝的O/0/l/1故意混淆,占比11%)

这个数据构成,直接决定了它对国内网站的“亲和力”。我拿它和PaddleOCR对比过:同一张带旋转的京东验证码,ddddocr 输出K7m9X(正确),PaddleOCR 输出K7m9XK7m9X(两个结果,置信度0.61),而tesserocr直接返回空字符串。差距在哪?就在训练数据的“土味适配”——PaddleOCR 训练数据以英文文档、街景文字为主,对中文验证码的字体、抗锯齿、背景融合毫无针对性。

2.2 预处理流水线:三步扼杀干扰

识别不准,80%的问题出在预处理。ddddocr 的classification()方法背后,自动执行一套精妙的流水线:

  1. 自适应灰度化:不用固定阈值,而是用局部均值法(Local Mean Thresholding)。比如一张背景渐变的验证码,全局二值化会丢失边缘,而它会把图像分块,每块独立计算阈值,确保深色字符和浅色背景都能清晰分离。实测比OpenCV的cv2.threshold(img, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)在复杂背景下提升17%的字符完整性。

  2. 高斯-中值混合去噪:先用3×3高斯模糊柔化噪点,再用3×3中值滤波剔除椒盐噪声。这里有个细节:高斯核的标准差σ不是固定值,而是根据图像方差动态调整——方差大(噪点多)时σ=1.2,方差小(干净图)时σ=0.6。这个自适应逻辑,让同一段代码在不同网站验证码上表现稳定。

  3. 投影分割优化:传统水平投影分割常被干扰线打断。ddddocr 改用“双峰投影法”:先做垂直投影找字符列,再在每列内做水平投影,但只取投影值超过峰值70%的连续区域作为字符块。这招对“字母中间加一横”的干扰(如某银行验证码)特别有效,分割准确率从63%拉到94%。

提示:你可以用ocr.set_words(['a','b','c'])强制限定字符集,比如知道某网站只用数字,就设set_words('0123456789'),识别速度能快40%,且杜绝字母误判。

2.3 为什么它不依赖GPU也能快?

很多新手看到“OCR”就默认要CUDA,ddddocr 却坚持纯CPU推理。原因很实在:登录自动化场景下,单次识别耗时必须压到200ms内,否则整个登录流程卡顿感明显。它用三个手段达成这点:

  • 模型轻量化:ResNet18 的通道数砍半(64→32),参数量仅1.2M,比PaddleOCR最小模型小5倍;
  • ONNX Runtime 加速:所有模型导出为ONNX格式,用onnxruntime执行,比原生PyTorch快3.2倍(实测i5-8250U上单图平均112ms);
  • 缓存机制:首次加载模型后,后续调用直接复用内存中的推理会话,避免重复初始化开销。

我测过:在无GPU的树莓派4B上,它识别一张120×50的验证码,平均耗时186ms,完全满足自动化节奏。而PaddleOCR同配置下要1.2秒——这已经不是“慢”,是“不可用”。

3. 实操全流程:从环境搭建到登录成功

3.1 环境准备:三步到位,拒绝玄学报错

别被网上那些“装了三天还缺dll”的教程吓到。ddddocr 对环境极其宽容,但有几个关键点必须卡死:

  1. Python 版本锁定:必须是Python 3.7~3.11。3.12刚发布不久,其C API有变动,ddddocr尚未适配(作者issue里明确写了“wait for next release”)。我建议直接用3.10,兼容性最稳。验证命令:python --version

  2. pip 升级与源切换:国内网络下,pip install ddddocr极易超时或校验失败。务必先升级pip并切清华源:

    python -m pip install --upgrade pip pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple

    这步省掉,后面90%的安装失败都源于此。

  3. Windows 用户的隐藏雷区:如果你用的是Windows 10旧版(1809之前)或某些精简版系统,可能缺vcruntime140.dll。别去网上乱下DLL,直接装微软官方运行库:下载 Microsoft Visual C++ 2015-2022 Redistributable ,运行安装。这是唯一需要手动干预的系统级依赖。

注意:不要用conda install!conda-forge上的ddddocr版本滞后严重(最新是1.4.6,而PyPI已是2.1.0),且预编译wheel缺失,容易触发源码编译,进而引发Visual Studio编译器报错。坚持用pip,这是血泪教训。

3.2 完整代码实现:带注释的可运行脚本

下面这段代码,是我压箱底的“登录自动化模板”,已通过京东、拼多多、某省政务网三站实测。它不是玩具,是能直接扔进生产环境的脚本:

# -*- coding: utf-8 -*- """ 网站登录自动化核心脚本(ddddocr版) 支持:自动截图、验证码识别、表单填充、登录状态校验 作者:一线爬虫工程师 | 2024年实测可用 """ import time import requests from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC import ddddocr # ==================== 1. 初始化OCR引擎 ==================== # 创建OCR实例,关闭日志减少干扰(生产环境必加) ocr = ddddocr.DdddOcr(show_api=False, beta=False) # 可选:加载自定义模型(如你有特定网站的验证码,可训练后替换) # ocr = ddddocr.DdddOcr(det_model_fp='path/to/det.onnx', # rec_model_fp='path/to/rec.onnx') # ==================== 2. 启动浏览器并访问登录页 ==================== options = webdriver.ChromeOptions() options.add_argument('--headless') # 无头模式,服务器上跑必备 options.add_argument('--no-sandbox') options.add_argument('--disable-dev-shm-usage') # 关键:禁用图片加载,提速300% options.add_experimental_option("prefs", {"profile.managed_default_content_settings.images": 2}) driver = webdriver.Chrome(options=options) wait = WebDriverWait(driver, 10) # 显式等待,超时10秒 try: # 访问目标网站(以京东为例) driver.get("https://passport.jd.com/new/login.aspx") # 等待验证码图片加载完成 captcha_img = wait.until( EC.presence_of_element_located((By.XPATH, "//img[@id='JD_Verification1']")) ) # ==================== 3. 截图并裁剪验证码区域 ==================== # 全屏截图(Selenium原生方法最稳) screenshot_path = "full_screenshot.png" driver.save_screenshot(screenshot_path) # 获取验证码元素位置和尺寸 location = captcha_img.location_once_scrolled_into_view size = captcha_img.size # 计算截图坐标(注意:Selenium返回的是页面坐标,需转为屏幕坐标) left = int(location['x']) top = int(location['y']) right = int(location['x'] + size['width']) bottom = int(location['y'] + size['height']) # 用PIL裁剪(比OpenCV更轻量,无需额外依赖) from PIL import Image full_img = Image.open(screenshot_path) captcha_crop = full_img.crop((left, top, right, bottom)) captcha_crop.save("captcha.png") # 保存用于调试 # ==================== 4. 调用ddddocr识别 ==================== with open("captcha.png", "rb") as f: img_bytes = f.read() # 核心识别!返回字符串 result = ocr.classification(img_bytes) print(f"[INFO] 识别结果: {result}") # ==================== 5. 填充表单并提交 ==================== # 输入用户名(示例,实际需替换为你的账号) username_input = wait.until( EC.element_to_be_clickable((By.ID, "loginname")) ) username_input.send_keys("your_username") # 输入密码 password_input = driver.find_element(By.ID, "nloginpwd") password_input.send_keys("your_password") # 输入验证码 verify_input = driver.find_element(By.ID, "authcode") verify_input.send_keys(result) # 点击登录按钮 login_btn = driver.find_element(By.CLASS_NAME, "btn-img") login_btn.click() # ==================== 6. 登录状态校验 ==================== # 等待跳转或错误提示出现 try: # 成功登录后通常跳转到首页,检查是否有"我的京东"链接 my_jd = wait.until( EC.presence_of_element_located((By.LINK_TEXT, "我的京东")) ) print("[SUCCESS] 登录成功!") except: # 检查验证码错误提示 error_msg = driver.find_elements(By.CLASS_NAME, "error-msg") if error_msg: print(f"[ERROR] 验证码识别失败: {error_msg[0].text}") # 这里可以加重试逻辑,比如刷新验证码后重试 else: print("[ERROR] 登录失败,未知原因") finally: driver.quit() # 必须关闭,防止僵尸进程

这段代码的实操价值在于:它把“识别”这个动作,无缝嵌入到完整的自动化链条里。不是孤立地跑OCR,而是和Selenium深度协同——截图坐标计算、元素等待、状态校验,全是生产环境必需的健壮性设计。你复制粘贴就能跑,但真正值钱的是注释里的每一句“为什么”。

3.3 关键参数调优:让识别率从92%冲到98%

默认参数够用,但想榨干性能,得懂这几个开关:

  • beta=True:启用Beta版模型。它比默认模型多一个“字符关系校验”层,对粘连字符(如ab连成αb)识别更强,但速度慢15%。我的建议:首次调试用beta=False快速验证流程,确认网站结构后,再开beta=True提精度。

  • show_api=False:必须关!开启后每次识别会打印一堆调试信息到stdout,在自动化脚本里会污染日志,还可能触发某些CI系统的超长输出警告。

  • det_model_fprec_model_fp:高级玩法。如果你要攻破某个特殊验证码(比如某银行的SVG动态验证码),可以自己用标注工具打1000张图,用ddddocr的训练脚本微调模型,然后在这里指定路径。但95%的场景,内置模型已足够。

  • old_version=True:兼容老版本(1.x)的API。如果你在维护旧项目,保留它;新项目一律用默认False

我做过AB测试:在某政务网(干扰线密集)上,beta=True+old_version=False组合,将识别率从89.3%提升到97.6%,重试次数从平均2.4次降到1.1次。这省下的时间,就是自动化脚本的吞吐量。

4. 常见问题与硬核排查技巧

4.1 “ImportError: DLL load failed” —— Windows用户的头号噩梦

现象:pip install ddddocr成功,但import ddddocr报错,提示找不到onnxruntimeddddocr的DLL。

根源:不是ddddocr的问题,是你的Python环境和系统运行库不匹配。Windows上,Python的ABI(应用二进制接口)版本必须和编译ddddocr wheel的VC版本一致。常见组合:

Python版本对应VC版本必装运行库
3.7~3.9VC14.2vcruntime140.dll
3.10~3.11VC14.3vcruntime143.dll

解决方案:不要重装Python,只装对应运行库。去微软官网下载 Visual C++ Redistributable for Visual Studio 2015-2022 ,选x64版本安装。装完重启终端,100%解决。这是我帮客户远程处理的第37个同类问题,无一失手。

4.2 “识别结果为空字符串” —— 图像质量陷阱

现象:ocr.classification(img_bytes)返回"",不是识别错,是根本没识别。

排查三步法:

  1. 检查图像格式:ddddocr只接受PNG、JPG、BMP。如果你用Selenium截图后直接传bytes,没问题;但若用OpenCV读图再转bytes,OpenCV默认BGR通道,必须转RGB:

    import cv2 img = cv2.imread("captcha.jpg") img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # 关键! _, img_bytes = cv2.imencode('.png', img_rgb)
  2. 检查图像尺寸:ddddocr内部会对过小图像(<20px高)自动跳过。用PIL检查:

    from PIL import Image img = Image.open("captcha.png") print(f"Image size: {img.size}") # 确保 height > 20
  3. 检查图像内容:截图时验证码还没加载出来!Selenium的save_screenshot()是同步的,但元素渲染是异步的。必须加显式等待:

    # 错误:直接截图 # driver.save_screenshot("bad.png") # 正确:等验证码图片加载完成再截 wait.until(EC.presence_of_element_located((By.ID, "captcha_img_id"))) driver.save_screenshot("good.png")

4.3 “识别率忽高忽低” —— 网站反爬的隐性信号

现象:同一段代码,今天识别率95%,明天掉到60%,重启脚本也没用。

真相:网站在动态调整验证码策略。比如京东会在检测到高频请求后,临时切换到“滑动拼图”或“文字点选”,而你的脚本还在傻等图片验证码。这时,captcha_img元素可能已不存在,find_element抛异常,但你的代码没捕获,导致后续逻辑错乱。

硬核解法:加一层“验证码类型探测”:

# 检查当前是哪种验证码 captcha_types = { "img": driver.find_elements(By.XPATH, "//img[contains(@src, 'captcha') or @id='captcha']"), "slide": driver.find_elements(By.CLASS_NAME, "tc-slider"), "click": driver.find_elements(By.XPATH, "//*[contains(text(), '点击')]"), } if captcha_types["img"]: # 走ddddocr流程 pass elif captcha_types["slide"]: print("检测到滑动验证码,需集成极验SDK") # 这里调用你的滑动破解模块 else: print("未知验证码类型,退出") exit(1)

这招让我把某电商后台的自动化成功率,从不稳定波动,拉升到长期99.2%的SLA水平。

4.4 性能瓶颈:为什么并发识别会变慢?

现象:单线程识别100ms,但开10个线程并发,每个识别耗时飙到300ms以上。

原因:ddddocr的ONNX Runtime默认使用单线程推理。10个线程抢同一个CPU核心,互相阻塞。

解法:给每个OCR实例绑定独立的推理会话,并设置线程数:

# 创建多个OCR实例,每个独占资源 ocr_instances = [] for i in range(5): # 开5个实例 ocr = ddddocr.DdddOcr(show_api=False) # 强制ONNX Runtime使用1个线程 ocr.det_session_options.intra_op_num_threads = 1 ocr.rec_session_options.intra_op_num_threads = 1 ocr_instances.append(ocr) # 使用时轮询分配 def recognize_concurrent(img_bytes): ocr = ocr_instances.pop(0) result = ocr.classification(img_bytes) ocr_instances.append(ocr) # 放回队尾 return result

实测:5实例并发,单次识别稳定在115±5ms,吞吐量提升4.2倍。这才是真正的“自动化生产力”。

5. 进阶实战:绕过更复杂的验证码防线

5.1 对付“动态刷新”的验证码

有些网站(如某证券平台)的验证码图片URL带时间戳参数,且每30秒自动刷新。如果截图和识别之间间隔太久,识别的已是过期图片。

破局点:劫持网络请求,提前拿到最新验证码。用Selenium的DevTools协议:

# 启用Chrome DevTools Protocol driver.execute_cdp_cmd('Network.enable', {}) driver.execute_cdp_cmd('Network.setCacheDisabled', {'cacheDisabled': True}) # 监听验证码图片请求 def intercept_captcha_request(event): if "captcha" in event['request']['url'].lower(): # 保存最新图片到内存 import base64 response = driver.execute_cdp_cmd('Network.getResponseBody', {'requestId': event['requestId']}) img_bytes = base64.b64decode(response['body']) # 存入全局变量或队列 global latest_captcha_bytes latest_captcha_bytes = img_bytes # 注册监听 driver.add_cdp_listener('Network.responseReceived', intercept_captcha_request) # 访问登录页,触发验证码请求 driver.get("https://xxx.com/login") # 等待1秒,确保请求完成 time.sleep(1) # 直接用latest_captcha_bytes识别,绝对新鲜 result = ocr.classification(latest_captcha_bytes)

这招让识别时效性从“赌运气”变成“稳拿”,是高阶玩家的标配。

5.2 处理“无图验证码”:文字点选与滑动拼图

ddddocr只管图片,但现实是,越来越多网站用行为验证码。这时候,它要和别的工具配合:

  • 文字点选(如“点击图中所有的苹果”):用ddddocr先识别图中所有文字,再用NLP匹配题干。例如:

    # 识别图中所有文字(用detect模式) res = ocr.detection(img_bytes) # 返回坐标和文字列表 # 假设题干是"点击所有动物",res里有['苹果','狗','猫','香蕉'] # 用简单词典匹配:animals = ['狗','猫','鸟'] → 找到对应坐标点击
  • 滑动拼图(如极验):ddddocr无法直接破解,但可以辅助。拼图缺口的形状,往往和原图某块纹理一致。用ddddocr的detection模式,找出原图中与缺口最相似的区域,计算偏移量:

    # 缺口图和原图都送入detection,得到特征向量 gap_feat = ocr.get_feature(gap_img_bytes) bg_feat = ocr.get_feature(bg_img_bytes) # 用余弦相似度遍历原图每个10×10区域,找最高分匹配点

这不是银弹,但把“纯黑盒破解”变成了“可解释的辅助决策”,大幅降低开发成本。

5.3 生产环境部署:Docker容器化最佳实践

在服务器上跑自动化,必须容器化。我的Dockerfile经过23次迭代,最终版:

FROM python:3.10-slim # 安装系统依赖 RUN apt-get update && apt-get install -y \ libglib2.0-0 \ libsm6 \ libxext6 \ libxrender-dev \ && rm -rf /var/lib/apt/lists/* # 复制代码 COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt # requirements.txt 内容: # ddddocr==2.1.0 # selenium==4.15.0 # Pillow==10.1.0 # 复制脚本 COPY login_automation.py . # 关键:设置字体,避免中文乱码 ENV FONTCONFIG_PATH=/etc/fonts RUN mkdir -p /usr/share/fonts/truetype/dejavu && \ cp /usr/share/fonts/truetype/dejavu/DejaVuSans.ttf /usr/share/fonts/truetype/dejavu/ CMD ["python", "login_automation.py"]

镜像大小仅328MB,启动秒级,内存占用<150MB。我们线上集群用它跑200个并发登录任务,CPU占用稳定在35%,从未因ddddocr崩溃过。

6. 最后一点掏心窝子的经验

干这行十年,我见过太多人把“验证码识别”当成一个技术点去攻克,结果陷在模型调参、数据增强、损失函数里出不来。但现实是:在自动化登录这个场景里,ddddocr的价值从来不在算法多先进,而在于它把“能用”这件事,做到了极致

我上个月帮一家做跨境选品的公司重构登录系统。他们之前用PaddleOCR,单次登录耗时2.3秒,失败率18%,运维天天救火。换成ddddocr后,耗时压到0.8秒,失败率降到1.2%,他们节省的服务器成本,半年就回本了。技术没有高低,只有适不适合。

所以,如果你正被这个问题困扰,别纠结“为什么不用YOLOv8做检测”或者“要不要自己训个ViT”,先下载ddddocr,跑通那段20行代码。当控制台第一次打出正确的验证码,那种“成了”的爽感,比任何论文指标都真实。

最后分享个小技巧:把验证码识别封装成一个独立的Flask API,用gunicorn跑3个worker。这样前端自动化脚本、后端调度系统、甚至手机App,都能统一调用。我们叫它“验证码中台”,上线三个月,支撑了日均47万次识别请求,没出过一次故障。技术的终点,永远是让事情变得简单。

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

MD5在线加密核心JS实现:从原理到文件校验的完整指南

做了这么多年前端&#xff0c;MD5这个算法算是绕不开的老熟人了。业务系统里要对文件做完整性校验、要对登录参数做签名、要根据内容生成唯一标识&#xff0c;后端跑个MD5很容易&#xff0c;但一旦场景切到纯前端——比如你要做一个把数据完全留在本地的在线工具、要离线使用&a…

作者头像 李华
网站建设 2026/9/16 19:31:05

银河麒麟V10 SP3双密码遗忘救援:GRUB与root密码重置实战指南

前阵子帮一家客户处理了一台银河麒麟V10 SP3服务器&#xff0c;情况很典型&#xff1a;上一任管理员给GRUB启动菜单加了密码&#xff0c;又把系统root密码改了&#xff0c;然后人直接失联。设备摆在机房里&#xff0c;业务验收在即&#xff0c;开机到GRUB菜单这一步就卡死&…

作者头像 李华
网站建设 2026/9/16 19:30:53

VS Code透明背景与背景图片设置:从插件到CSS的完整指南

说实话&#xff0c;很多人一看到“vscode透明背景以及背景图片设置”这类需求&#xff0c;第一反应是“花里胡哨&#xff0c;有什么用”。但我自己实际用下来&#xff0c;这还真不是纯粹的外观折腾。整天盯着代码的人&#xff0c;换一个柔和的背景图&#xff0c;或者把窗口搞成…

作者头像 李华
网站建设 2026/9/16 19:30:45

抓包证书不受信任?TLS信任链与多环境证书配置详解

1. 抓包证书“不受信任”不是 bug&#xff0c;是 TLS 信任链的刚性设计你用 Charles 或 Fiddler 抓包时&#xff0c;浏览器弹出“您的连接不是私密连接”&#xff0c;Android App 提示 SSLHandshakeException&#xff0c;Java 程序跑着跑着突然抛出javax.net.ssl.SSLHandshakeE…

作者头像 李华
网站建设 2026/9/16 19:30:22

SourceTree Git分支管理:创建分支与删除分支实操避坑

1. 先把SourceTree里"分支"这件事说透用 SourceTree 干了几年活&#xff0c;我发现一个挺普遍的现象&#xff1a;很多人装了 SourceTree&#xff0c;日常操作却还是 git 命令行那一套——打开 SourceTree 只是用来看提交图谱和 diff。问起来原因&#xff0c;答案基本…

作者头像 李华