news 2026/10/21 9:31:37

Selenium模拟登录遇验证码?从截图到打码平台全链路解决

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Selenium模拟登录遇验证码?从截图到打码平台全链路解决

做Web自动化或者写爬虫脚本的兄弟,大概率都撞过同一堵墙:登录页上的验证码。Selenium本身能点击、能输入、能提交表单,但唯独见到验证码就卡壳。这玩意儿存在的意义就是拦机器人,而Selenium在网站眼里就是一个“机器人”。所以想用Selenium模拟登录带验证码的网站,核心问题就一句话:让脚本在“被确认是人类”这一步上,能自己把验证码解掉。

这篇文章不绕弯子,直接讲清楚一条可落地的完整链路:Selenium定位表单元素、截取验证码图片、通过打码平台识别、再把结果回填并完成登录。整个过程拆成模块讲,附完整代码和排查经验。适合熟悉Python和Selenium基础用法、但卡在登录验证码环节的开发者,也适合刚接手自动化测试或爬虫项目、需要搞定带验证码登录场景的朋友。

老规矩先声明:教程里的技术和代码,只用于你自己有权限的系统、内部测试环境或学习研究。不要拿去看不该看的网站,也别对没有授权的平台做登录和抓取,这个边界心里得有数。

1. 模拟登录到底难在哪:验证码只是表象

1.1 验证码在登录链路里的定位

先搞清楚一件事:验证码不是登录流程的终点,而是登录流程中间的一个“关卡”。从Selenium的角度看,一个带验证码的登录页,本质上依然是一个填表单、点按钮、等跳转的流程。你输入用户名和密码,输入验证码,点击登录,服务端校验通过后返回登录态。验证码只是在这个流程里多了一个需要“读懂图片”的步骤。

这个“读懂图片”的步骤为什么难?因为Selenium没有任何视觉理解能力。它能拿到元素的坐标、属性、文本,但它看到一张歪歪扭扭、带着干扰线的验证码图片时,完全不知道上面是“3Zk8”还是“2Zk8”。所以模拟登录的卡点,从来不在于“怎么点按钮”,而在于“怎么把验证码图片变成文本”。

验证码出现的位置也有讲究。有的网站进入页面就有一张验证码图,填完直接登录;有的网站是先输账号密码、点了登录按钮之后才临时生成验证码,甚至弹出来一个滑块;还有的网站验证码不在初始页面,而是在你连续输错密码后才出现。这些“出现时机”决定了你的脚本结构:是启动就准备识别,还是在某次点击之后才开始触发识别流程。写代码之前,必须先手动打开目标登录页,把验证码触发的时机看明白。

1.2 识别验证码的三条路线怎么选

处理验证码,目前主流有三条路线,各自的定位和坑都不一样。

第一条是人工介入。脚本跑到验证码这里停下来,弹个窗口把验证码图片显示出来,让人眼看、手输,然后脚本再继续。优点是零成本、零配置,识别率100%;缺点是脚本跑起来离不开人,没法半夜定时任务,更没法处理大量登录。适合自己偶尔跑一次的个人工具,不适合自动化体系。

第二条是本地OCR识别。用开源的光学字符识别库去做本机识别,把验证码图片喂给模型,让它输出文本。对于纯数字、没有干扰线的简单验证码,本地OCR能有个不错的准确率;但一旦验证码换了字体、加了扭曲、多了背景干扰线、甚至点和字符粘连在一起,本地OCR的结果会惨不忍睹,经常出现“看起来八九不离十,提交后永远报错”的尴尬场面。优点是免费、数据不出本地;缺点是泛化能力差,环境一变就要重新调。

第三条就是打码平台。流程很简单:脚本把验证码图片传给平台的HTTP接口,平台那边用商业级识别引擎处理,返回文本结果。打码平台的优势在于识别种类多——图片字符、滑块、点选文字、数字运算都支持——而且识别成功率稳定,普遍在90%以上,遇到失败还能自动重试。缺点是要花钱,虽然单价很低,但毕竟不是零成本;另外数据要经过第三方服务器,敏感场景需要评估一下合规性。

三条路线不是非此即彼,实际项目中完全可以混用。我的建议是:低频个人脚本,本地OCR先顶着;要在服务器上稳定跑、还要处理多类型验证码的,老老实实接打码平台。别在本地OCR上花太多时间校参数,时间成本大概率比打码费用高得多。

1.3 整体技术方案选型

这篇博文选定的路线是“Selenium + 打码平台”组合。为什么这么选?因为Selenium的最大价值是它几乎完全模拟了真实浏览器行为,登录这类场景它最合适,不用去逆向加密参数;打码平台则解决了视觉识别这个Selenium天生不擅长的短板,两者正好互补。

整个方案的模块划分是这样的:

  • 浏览器控制层:Selenium负责打开页面、定位元素、输入内容、点击按钮、读取Cookie。
  • 验证码识别层:打码平台API负责把验证码图片转成文本,做成独立函数,方便随时替换。
  • 流程编排层:写一个登录主流程,把“填表单 → 取验证码 → 识别 → 回填 → 提交”串起来,并处理失败重试。

各层独立的好处是,以后就算目标网站改版,或者你想换一家打码平台,只需要动对应的那一层,其他代码可以不动。这就是在后面几章里我会反复强调“封装”的原因。

2. 环境准备与打码平台接入基础

2.1 先把Selenium驱动环境整明白

这一步其实不算进阶内容,但很多人在这里翻车。Selenium本身是一个库,它需要配合具体的浏览器驱动才能工作。Chrome配ChromeDriver,Edge配EdgeDriver,版本不匹配就直接报错。

省心一点的做法是直接用webdriver-manager这个库,它会根据你本机安装的浏览器版本自动下载匹配的驱动,不用手动去管驱动文件的存放路径和版本对应关系。

pip install selenium webdriver-manager requests

然后初始化浏览器:

from selenium import webdriver from selenium.webdriver.chrome.service import Service from webdriver_manager.chrome import ChromeDriverManager driver = webdriver.Chrome( service=Service(ChromeDriverManager().install()) ) driver.get("https://你的目标登录页地址")

这段代码就把浏览器窗口打开并导航到了目标页面。第一次运行它会自动下载驱动,后面再跑就是直接用缓存,不用反复配置。这里有个小提示:如果你的运行环境是Linux服务器,记得先装好Chrome浏览器本体,很多坑是因为服务器上只有Python环境和驱动,但没有浏览器程序本体导致的。

2.2 打码平台到底是怎么工作的

打码平台听起来挺玄乎,本质上它就是一个“图形验证码识别服务”。你通过HTTP请求把验证码图片发过去,平台返回识别出的字符。不同平台的具体协议有所不同,但核心流程高度相似,基本逃不开下面两种模式。

第一种是同步识别。你把图片数据POST到平台接口,平台在同一个请求的响应里直接返回识别结果。这种模式适合图片本身不复杂、平台处理速度足够快的情况。集成最简单,一个requests请求搞定。

第二种是异步任务模式。你先把图片提交过去,平台返回一个任务ID,然后你拿着这个任务ID轮询结果接口,直到任务状态变成“已完成”,再取出识别文本。这种模式适合平台处理压力大、或者验证码类型比较复杂(比如点选式、滑动式)的情况。

两种模式在代码层面就差一个轮询逻辑。下面我写一个封装的识别函数,基于同步模式,方便理解:

import base64 import requests def recognize_captcha(image_base64: str, app_id: str, app_secret: str) -> str: """调用打码平台识别验证码,返回文本结果。""" payload = { "app_id": app_id, "app_secret": app_secret, "image": image_base64, "type": 1001, # 验证码类型:1001纯数字,1002纯字母,1003混合 } resp = requests.post( "https://api.example-captcha.com/ocr", json=payload, timeout=30, ) data = resp.json() if data.get("code") == 0: return data.get("result", {}).get("captcha_text", "") return ""

这个函数里的一堆参数,在真实接入某家平台时需要替换成对应的字段名和值。写成函数而不是直接写在主流程里,就是为了换平台时只改这一个地方就够了。

2.3 封装打码调用函数时的关键参数

接入打码平台时,有几个参数值得专门说一下。

第一是验证码类型参数。不同平台的叫法不同,但基本都会有一个type字段用来告诉服务端“你这是纯数字、纯字母、混合、还是滑块”。选错了,识别率和返回格式都会出问题。这个要在代码里做成可配置项,别写死在调用处。

第二是超时时间。验证码识别虽然是秒级,但网络波动和平台排队都可能导致响应变慢。我的建议是通过requests的timeout参数控制请求超时,避免脚本无限卡住。设成30秒是一个比较稳妥的起点。

第三是错误重试。打码平台的识别不是100%成功,平台自身也可能因为图片模糊、干扰太强返回失败。所以在业务逻辑层面,识别失败时应该回到“刷新验证码图片→重新识别→重新提交”这个循环里,而不是直接让整个登录流程崩溃。

3. 登录表单交互与验证码截取实战

3.1 定位用户名、密码输入框的标准姿势

拿到页面之后,第一步是找到用户名输入框、密码输入框和登录按钮。定位元素的优先级,我个人是这么排的:优先用ID和name属性,其次用CSS Selector,最后才是XPath。原因是ID和name通常简洁且唯一,CSS Selector比XPath更容易阅读和调试,XPath功能最强但写起来啰嗦、维护性差。

一个典型登录框的定位和填写长这样:

from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC username = WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.ID, "username")) ) username.clear() username.send_keys("你的登录账号") driver.find_element(By.ID, "password").clear() driver.find_element(By.ID, "password").send_keys("你的登录密码")

注意我用了显式等待而不是time.sleep。很多初学者习惯在每一步之间写sleep(3),这是最偷懒但也最容易出问题的方式。页面加载快的时候你在多等,页面加载慢的时候你又没等够。显式等待是让Selenium主动去轮询某个条件是否满足,比如元素是否出现、是否可见、是否可点击,这才是稳定的做法。当然,写元素定位时偶尔遇到“明明页面有这个元素,就是定位不到”的情况,这在后面的常见问题章节里会单独解构。

3.2 iframe嵌套:登录框不在最外层页面

判断Selenium是入门还是进阶,有一个很重要的分水岭:你会不会处理iframe。很多网站为了隔离样式和脚本,会把整个登录模块放在一个iframe里。这时候如果你直接去找用户名输入框,Selenium会告诉你找不到元素——因为整个页面其实有两层文档,主页面是一层,iframe里又是一层。

遇到这种情况,处理方式很固定:

# 等待iframe出现并切换进去 WebDriverWait(driver, 10).until( EC.frame_to_be_available_and_switch_to_it((By.ID, "login_frame")) ) # 现在元素在iframe内部,可以正常定位了 driver.find_element(By.ID, "username").send_keys("你的登录账号") # 操作完之后,如果需要回到主页面,再切回来 driver.switch_to.default_content()

不强记代码,只要记住一句话:进了iframe先切换,操作完再切回主文档。如果嵌套了多层iframe,就一层一层切进去。判断页面是不是iframe结构,最简单的方法是在目标输入框上右键,看浏览器菜单里有没有“查看框架来源”或者“在iframe中打开”之类的选项。

3.3 验证码图片的截取与编码细节

拿到验证码图片是整条链路里技术含量最高的一步。验证码通常有两种呈现方式:一种是一个独立的img标签,另一种是canvas绘制的动态验证码。

面对img标签的验证码,最省事的方法是用Selenium的元素截图功能,直接把这个元素的图像数据拿下来:

captcha_element = driver.find_element(By.CSS_SELECTOR, "img#captcha_img") captcha_base64 = captcha_element.screenshot_as_base64()

screenshot_as_base64返回的是Base64编码的图片数据,直接可以传给打码平台的接口。这里有一个容易踩的坑:如果验证码图片因为懒加载还没出现在可视区域,或者它的宽高为0,screenshot_as_base64拿到手的可能是空白图。稳妥的做法是先用ActionChains把元素滚动到视野中,再确认它加载完成后再截图。

如果是canvas绘制的验证码,元素截图有时候拿不到内容,因为canvas的绘制内容不一定能被Selenium的元素截图完整捕获。遇到这种情况,一个常见替代方案是对整个窗口截图,然后根据canvas元素的位置和大小把验证码区域裁剪出来。这需要用到PIL库的裁剪能力,代码会复杂一些。

from selenium.webdriver.common.action_chains import ActionChains # 滚动到验证码图片所在位置 ActionChains(driver).move_to_element(captcha_element).perform() # 等待图片加载完成 WebDriverWait(driver, 10).until( lambda d: captcha_element.get_attribute("complete") == "true" ) captcha_base64 = captcha_element.screenshot_as_base64()

拿到验证码图片之后,还有个小细节容易忽略:很多网站的验证码图片点击后会刷新。如果脚本第一遍识别失败,想要重试,必须先去点击刷新,然后重新定位元素、重新截图,而不是拿着旧图反复识别。因为验证码是一次性的,服务端在第一次校验失败之后,这个图就已经作废了。

4. 完整登录流程:从启动浏览器到Cookie持久化

4.1 把每个模块串成一条生产线

前面几章把登录流程的各个零件都准备好了,现在要做的事是把它组装成一条完整生产线。一个可用的主流程,我习惯写成下面这个样子:

import json import time import base64 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 from selenium.webdriver.chrome.service import Service from webdriver_manager.chrome import ChromeDriverManager def recognize_captcha(image_base64: str) -> str: """打码识别,具体参数换成你接的平台的参数。""" payload = { "app_id": "your_app_id", "app_secret": "your_app_secret", "image": image_base64, "type": 1003, } resp = requests.post( "https://api.example-captcha.com/ocr", json=payload, timeout=30, ) data = resp.json() if data.get("code") == 0: return data.get("result", {}).get("captcha_text", "") return "" def login_with_captcha(driver, username: str, password: str, max_retry: int = 5) -> bool: driver.get("https://你的目标登录页地址") # 等待登录表单出现,并判断是否在iframe里 WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.ID, "username")) ) driver.find_element(By.ID, "username").send_keys(username) driver.find_element(By.ID, "password").send_keys(password) for attempt in range(max_retry): try: captcha_element = driver.find_element(By.CSS_SELECTOR, "img#captcha_img") image_base64 = captcha_element.screenshot_as_base64() captcha_text = recognize_captcha(image_base64) if not captcha_text: print(f"第 {attempt + 1} 次识别结果为空,刷新验证码重试") driver.find_element(By.CSS_SELECTOR, "a#refresh_captcha").click() time.sleep(1) continue code_input = driver.find_element(By.ID, "captcha_code") code_input.clear() code_input.send_keys(captcha_text) driver.find_element(By.ID, "login_btn").click() # 等待登录成功的标志出现,比如跳转后的某个元素 try: WebDriverWait(driver, 5).until( EC.presence_of_element_located((By.CSS_SELECTOR, "a.logout_link")) ) print("登录成功") return True except: print(f"第 {attempt + 1} 次登录失败,重新识别验证码") driver.find_element(By.CSS_SELECTOR, "a#refresh_captcha").click() time.sleep(1) except Exception as e: print(f"第 {attempt + 1} 次执行异常: {e}") time.sleep(2) return False

这个流程里有一个关键点值得展开讲:登录成功之后,我判断成功的逻辑不是看页面跳没跳转,而是去等待一个“只有登录后才出现的元素”。用里面登出链接或者用户头像这类元素做成功标志,比硬等URL变化要可靠得多。

另外要注意,验证码识别失败的重新尝试,不是简单地把旧验证码再次提交,而是要先触发刷新,再重新获取验证码图片。如果你用的页面没有“点击刷新验证码”这个交互,那就要通过刷新整个页面来获取新的验证码。两种方式都行,但一定要保证每次识别的是新图。

4.2 失败重试的边界处理

失败重试逻辑看着简单,真正容易出问题的地方在于重试次数的上限和每次重试的间隔。无限重试是最危险的,因为如果目标网站的风控机制已经触发了,你越重试反而越容易被限制,甚至整个IP被拉黑。

比较稳妥的做法是设置一个最大重试次数,一般是5次左右。每次失败后做两件事:刷新验证码和随机停顿。随机停顿的目的是避免每次都卡在同一个时间点,让请求节奏看起来更接近人工操作。你可以用time.sleep加上一点随机数来实现,比如1.5秒到3秒之间的随机值,而不是死板的固定2秒。

还要想好“整体登录失败”之后怎么办。我的做法通常是把关键信息记录下来,比如当前页面的截图、验证码识别返回的错误码、登录失败时的页面HTML片段,这些信息在排查问题时非常有用。

import random import os sleep_time = random.uniform(1.5, 3.0) time.sleep(sleep_time) if attempt == max_retry - 1: os.makedirs("debug", exist_ok=True) driver.save_screenshot("debug/login_failed.png") with open("debug/login_failed.html", "w", encoding="utf-8") as f: f.write(driver.page_source)

4.3 登录成功后Cookie的保存与复用

登录成功之后,你拿到的是一个已经通过鉴权的浏览器会话。如果脚本的使命只是登录一次,那到这里就可以结束了。但在很多场景里,登录只是起点,后面还要做数据抓取或自动化操作。这时候就有一个日常高频需求:如何让脚本下次启动时不用重新过一遍验证码流程?答案是保存Cookie,下次直接加载。

Selenium读取和添加Cookie的接口非常直接:

import json def save_cookies(driver, filepath: str): cookies = driver.get_cookies() with open(filepath, "w", encoding="utf-8") as f: json.dump(cookies, f, ensure_ascii=False, indent=2) def load_cookies(driver, filepath: str): with open(filepath, "r", encoding="utf-8") as f: cookies = json.load(f) for cookie in cookies: driver.add_cookie(cookie)

用的时候有个顺序问题:必须先访问一次目标网站的域名,然后再添加Cookie,最后刷新页面。如果先添加Cookie再打开网站,当前域的Cookie存储是空的,add_cookie会因为没有可用的域名上下文而报错。

# 第一次运行:登录成功后保存Cookie save_cookies(driver, "cookies.json") # 后续运行:先访问域名,再加载Cookie driver.get("https://你的目标网站首页") load_cookies(driver, "cookies.json") driver.refresh()

需要注意的是,Cookie不是永久的。它有自己的生命周期,过期时间由服务端决定。有的网站Cookie能顶几个星期,有的几分钟就失效。所以加载Cookie之后,还要有一步“验证登录态是否还有效”的判断,无效了就回到登录流程重新登录。

5. 常见问题与排查技巧实录

5.1 验证码图片截取为空或截出来是空白

这个现象我见过太多次了。明明页面上验证码显示得好好的,代码截图出来却是一片空白。原因通常有以下几种:验证码图片使用了懒加载,尚未真正加载完成页面上的img元素就已经执行了截图;验证码不在视口区域内,浏览器为了性能没有渲染它;还有一种情况是验证码本身不是img,而是canvas,或者用CSS背景图实现的,元素截图的模式拿不到视觉内容。

针对这些问题,操作顺序应该调整为:先把元素滚动到可视区域,然后等待图片加载完成,再做截图。如果element的screenshot接口仍然拿不到完整内容,就退一步,对整页窗口截图,再用PIL根据元素位置和大小裁剪区域。后一种方式虽然代码多几行,却是处理各种“花式验证码”最通用的兜底方案。

5.2 验证码识别正确了,但一直提示验证码错误

这个问题比截图空白更让人抓狂,而且很难想明白。你拿到的验证码图片明明和人眼看到的一致,识别平台也返回了正确的文本,填进去却被告知错误。我总结下来,通常有三个可能的原因。

第一个可能,是验证码已经过期了。有些网站为了安全,验证码的有效期非常短,甚至只有几十秒。如果自动化的流程在前面填用户名、密码时花的时间太长,等你拿到验证码文本再提交时,它已经被服务端标记为失效。解决思路是尽量把验证码的识别和提交压缩在一个更短的时间窗口里,或者挑战通过与重试机制来自动刷新。

第二个可能,是验证码和账号密码的校验顺序有问题。有些网站是前端先校验验证码,有些是提交整个表单之后统一校验。如果脚本在验证码还没加载完成就抢着提交,服务端拿不到验证码字段,自然就会报错。

第三个可能,藏在细节里:元素截图拿到的图片可能带着尺寸缩放变形。如果页面样式把验证码图片拉伸放大了,你截到的图和实际渲染的原始验证码不一致,识别平台的准确率就会大打折扣。遇到这种情况就得用原始图片URL去下载原始尺寸的验证码,而不是用页面上缩放后的截图。

5.3 登录成功后Cookie不生效,一刷新就回到未登录状态

跑通登录、也保存了Cookie,结果第二次启动脚本加载Cookie之后刷新页面,发现又回到了登录页。这个问题大多数人第一反应是“Cookie没保存对吧”,但真正常见的坑有两个。

第一个坑是前面提到的,加载Cookie之前必须先访问一次目标域名。如果你先add_cookie再get,Selenium会因为当前没有任何域上下文而拒绝添加。第二个坑是Cookie的domain属性不匹配。在Selenium中add_cookie对domain字段要求很严格,你必须先访问该域名的页面,才有可能添加该域下的Cookie。如果用了localhost或IP地址访问,Cookie对应的domain可能是localhost,这也会导致换过环境之后Cookie无法生效。

排查这类问题有个小技巧:加载Cookie之后,不要急着刷新,先截一张页面状态图,再执行一次页面上某个需要登录才能触发的接口请求,看一眼返回的响应头或者状态码。这样能快速判断登录态到底带没带上,而不是靠肉眼看页面跳转来判断。

下面把高频问题和排查路径整理成速查表:

问题现象可能原因排查思路对应方案
验证码截图空白懒加载、不可见、canvas渲染检查元素是否在可视区域、图片是否加载完成滚动到可视区域后等加载,再用Windows截图
识别结果一直是空type参数错误、平台请求超时打印打码平台的原始响应检查验证码类型参数,设置足够长的超时
识别对了但登录失败验证码过期、提交时机不对打印验证码生成时间和提交时间压缩识别与提交间隔,刷新验证码后重试
元素定位不到登录框在iframe里查看页面源码确认iframe结构先切换iframe再定位元素
Cookie添加报错或刷新失效先添加Cookie后才访问域名检查报错信息、Cookie的domain先get首页,再add_cookie,再refresh
Selenium打开的页面被拦截浏览器指纹被识别观察弹出的是什么提示低频运行、行为随机化,优先走官方API

5.4 关于等待策略的最后一个建议

我在整个流程反复用WebDriverWait,不用sleep,这里再补充一个实际心得。等待方式的选择,直接决定了脚本跑起来是“稳”还是“脆”。对于确定会出现的东西,比如用户名输入框、登录按钮,用presence_of_element_located等它出现就够了;对于可能一瞬间就过去的状态,比如登录成功后的跳转提示,可以用visibility_of_element_located或者element_to_be_clickable去匹配。总之,能指向具体的条件,就不要无脑等固定时间。

结语

做自动化的都知道,登录验证码看起来是“拦路虎”,拆开之后也就是“取图、识别、回填”三个字。把验证码识别接成独立模块,跟Selenium的主流程解耦,以后换平台、换验证码类型都不会伤筋动骨。这也是我个人在被某个网站的滑块验证码折腾一整天之后,最深刻的体会:复杂的问题,一定先把模块边界划清楚,再逐个击破。

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

AI视频多镜头场景怎么保持一致?状态表、道具接续与异常回归

做多镜头 AI 视频时,一个常见错误是把“画风差不多”当成“场景接得上”。树桩还在原位,人物衣服也差不多,但上一镜头手里拿着的锄头下一镜头突然不见;字幕说“日子一天天过去,田荒了”,画面前景却还长着成…

作者头像 李华
网站建设 2026/10/21 9:30:17

无人机PID调参新思路:非线性增益调度与元启发式优化

做无人机飞控这件事,调PID是个绕不开的环节。我见过不少开发者在初期把一个参数一个参数地试,试到后面自己都不记得哪组组合有效,更麻烦的是,换一个飞行工况可能又得从头再来。某个项目里我接手一台悬停性能很不稳定的四旋翼&…

作者头像 李华
网站建设 2026/10/21 9:29:41

轻量级图表设计器实战:SVG渲染、坐标系统与连线算法

写一个图表设计器这个念头,我脑子里转了大半年。之前画架构图、流程图全靠外部工具,免费版限制节点数,样式丑到没法看,导出的图片塞进文档里还经常模糊。后来接到一个内部系统需求,要在网页上直接展示并编辑几张架构图…

作者头像 李华
网站建设 2026/10/21 9:28:20

校园外卖小程序毕业设计全流程拆解:从云开发到订单状态机

样,也要能支撑起一篇像样的设计文档和一场说得过去的答辩。这个题目可以说是“入门友好、上限够用”的典型代表,所以它烂大街,但不代表它没含金量。关键在于,你怎么把它做出差异化,怎么在实现里体现出对业务逻辑和工程…

作者头像 李华
网站建设 2026/10/21 9:28:05

大语言模型训练四阶段全解析:从预训练到强化学习对齐

1. 大语言模型训练全流程总览:四个阶段到底在解决什么问题如果你自己动手拆过一条大语言模型的训练链路,或者只是陪团队做过一次从零开始的模型迭代,应该都听过一个高频说法:大语言模型训练可以拆成四个阶段。这四个阶段分别叫预训…

作者头像 李华
网站建设 2026/10/21 9:28:01

深度学习医学图像分割:从U-Net到nnU-Net的演进与落地实践

简介:《基于深度学习的医学图像分割技术研究进展》是一篇面向医学影像分析领域研究者的综述论文,系统梳理了深度学习技术在医学图像分割中的应用进展。内容先阐述医学图像分割在临床诊断中的基础作用,介绍CT、MRI、超声等常见影像的特点&…

作者头像 李华