当前位置: 首页 > news >正文

Selenium Cookie复用跳过验证码的工程实践

1. 这不是“绕过”,而是“跳过”——先厘清一个关键认知误区

很多人看到“Selenium通过cookie绕过验证码”这个标题,第一反应是:这算不算在钻系统空子?会不会被风控拦截?甚至担心是不是游走在合规边缘?我做自动化测试七年,带过二十多个中大型项目的UI自动化落地,实话讲:这不是绕过,而是跳过;不是对抗,而是复用。核心在于——你登录成功的那一次,服务端已经为你签发了合法、有效、带完整会话权限的cookie,而验证码只在身份未确认阶段(即登录页/注册页/敏感操作前置页)强制校验。一旦用户完成人机验证并成功认证,后续所有请求都依赖session或token维持状态,验证码机制自然退出生命周期。

所以,“通过cookie跳过验证码”的本质,是在自动化流程中复用已认证的会话凭证,跳过前端交互层中重复、低效、且对机器不友好的人机挑战环节。它不破解验证码算法,不模拟点击滑块轨迹,不调用OCR识别接口,更不尝试暴力穷举。它只是像真实用户那样,在第一次手动登录后,把浏览器里那个带着JSESSIONIDauth_tokenuser_session等字段的cookie字符串,原样注入到Selenium驱动的新会话中,让服务端“误以为”这是同一个已登录用户发起的后续操作。

这个做法在内部测试环境、灰度发布验证、回归测试流水线中极为常见。比如我们团队维护的电商后台系统,每天要跑300+条订单管理、库存同步、促销配置类用例,如果每条都从登录页开始走完整流程——输入账号密码、等待图形验证码加载、人工识别、点击提交、等待跳转……光是登录环节就吃掉40%以上的执行时间,还极易因验证码识别失败导致整条链路中断。而采用cookie预置方案后,单次用例平均执行耗时从82秒降至13秒,失败率从17%压到0.3%以下。

关键词“Selenium自动化测试”“cookie”“验证码”在此场景中各自承担明确角色:“Selenium”是执行载体,负责控制浏览器行为;“cookie”是状态凭证,承载服务端授予的会话合法性;“验证码”则是被跳过的前置校验关卡,仅在身份建立初期生效。三者关系不是对抗,而是分层协作——就像你进公司大楼,第一次需要刷工卡+人脸识别(验证码),但进了门之后去茶水间倒水、去会议室开会,保安不会拦你再刷一次脸。cookie就是那张已被系统认可的“电子工卡”。

提示:该方案仅适用于测试环境或允许会话复用的预发布环境。生产环境严禁硬编码或明文存储生产cookie,也不应将人工登录凭证用于无人值守的自动化任务——这违反基本的安全审计原则。本文所有实践均默认部署在隔离的测试集群,且cookie有效期严格控制在2小时以内,由CI/CD流水线动态生成与销毁。

2. 为什么不用自动识别?——三种主流方案的成本-收益对比

既然目标是“不输验证码”,那为什么不直接上OCR识别、打码平台或深度学习模型?这个问题我在三次技术评审会上都被问到。答案很实在:不是不能,而是不值。我们做过详细测算,把“验证码处理”拆成三类典型路径,从开发成本、维护成本、稳定性、合规性四个维度横向对比:

方案类型开发投入(人日)日常维护(周均)稳定性(成功率)合规与安全风险
Cookie预置法0.5(写入逻辑+序列化)基本为零(仅需更新过期策略)≥99.6%(依赖服务端session有效性)极低(仅限测试环境,无凭证外泄)
开源OCR识别(如tesseract)3~5(图像预处理+阈值调优+容错逻辑)2h/周(应对字体/噪点/扭曲变化)72%~89%(简单数字型尚可,中文/干扰线型骤降至41%)中(需本地部署图像处理库,存在资源占用)
商用打码平台API(如某验、极验)1(封装HTTP请求+错误重试)1h/周(监控扣费、处理限流、更新密钥)92%~96%(依赖第三方SLA,网络抖动即失败)高(引入外部依赖,存在数据上传合规风险)

数据背后是血泪教训。去年Q3我们曾在一个金融客户项目中强行推进OCR方案:前期花4天调通tesseract,适配了他们自研的5种验证码变体(数字+字母混合、斜切、加干扰线、背景色块、动态GIF帧)。结果上线两周后,对方运维突然升级了验证码服务——新增了“鼠标移动轨迹校验”,要求用户必须以非匀速方式拖动滑块,否则即使OCR识别正确也拒绝提交。我们连夜补轨迹模拟,又搭上3天,刚测通,对方又切到了“行为式验证”,连滑块都没了,变成“请在3秒内完成指定动作序列”。最后团队一致决定:砍掉整个OCR模块,改用cookie预置+人工触发登录态刷新机制。

这就是现实——验证码的本质是持续对抗,而自动化测试的核心诉求是稳定交付。你永远追不上风控策略的迭代速度,但你可以牢牢抓住“已认证状态”这个确定性锚点。Cookie预置法的优势正在于此:它不跟验证码斗智斗勇,而是直接站在验证完成后的终点线上出发。只要服务端session机制没重构(比如从cookie切到JWT无状态token且校验IP绑定),这套方案就能稳稳跑三年以上。

注意:若目标系统采用JWT且校验设备指纹或IP白名单,cookie注入后仍可能被拒绝。此时需同步注入User-AgentX-Forwarded-For等请求头,并确保Selenium启动的浏览器User Agent与原始登录环境一致。这点常被忽略,导致“明明cookie是对的,却提示未登录”。

3. 实操四步法:从手动登录到自动化复用的完整链路

真正落地时,很多人卡在“怎么拿到cookie”“怎么塞进去”“为什么还是跳转登录页”这三个问题上。下面是我打磨出的四步标准流程,已在8个不同技术栈项目(Spring Boot、Django、Node.js、PHP Laravel)中验证有效,每一步都附带避坑要点。

3.1 第一步:人工登录并导出完整cookie集合

别急着写代码,先打开Chrome浏览器,访问测试环境登录页(如https://test-admin.example.com/login),输入测试账号密码,完成验证码验证,成功进入首页。此时按F12打开开发者工具,切换到Application → Cookies,左侧选中当前域名,右侧列表会显示所有已设置的cookie。

重点不是只复制JSESSIONID!很多同学只抓这个,结果失败。你需要导出全部非HttpOnly标记的cookie(HttpOnly字段无法被JS读取,Selenium也无法注入,但服务端仍会校验其存在性——所以必须保留原始会话中的HttpOnly cookie,靠Selenium启动时自动携带)。实际操作中,我推荐用Chrome插件“EditThisCookie”一键导出JSON格式:

  1. 安装插件后,点击图标 → “Export” → 选择“JSON”格式
  2. 保存为login_cookies.json,内容类似:
[ { "domain": ".test-admin.example.com", "expirationDate": 1735689200, "hostOnly": false, "httpOnly": true, "name": "JSESSIONID", "path": "/", "sameSite": "Lax", "secure": true, "session": false, "storeId": "0", "value": "ABCD1234-EFGH5678-IJKL9012-MNOP3456", "id": 1 }, { "domain": ".test-admin.example.com", "expirationDate": 1735689200, "hostOnly": false, "httpOnly": false, "name": "auth_token", "path": "/", "sameSite": "Lax", "secure": true, "session": false, "storeId": "0", "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "id": 2 } ]

关键细节:务必检查domain字段是否带前导点号(如.test-admin.example.com),这是跨子域共享cookie的关键。若导出的是test-admin.example.com(无点号),需手动补上,否则注入后子域页面无法读取。

3.2 第二步:编写Selenium初始化脚本,注入cookie并验证状态

核心逻辑是:启动浏览器 → 访问任意页面(建议用about:blank避免触发重定向)→ 调用add_cookie()逐条注入 → 刷新页面 → 检查是否跳转登录页。Python + Selenium 4.x代码示例如下:

from selenium import webdriver from selenium.webdriver.chrome.options import Options from selenium.webdriver.common.by import By import json import time def init_driver_with_cookies(cookie_file_path: str, target_url: str = "https://test-admin.example.com/dashboard"): # 1. 启动无GUI Chrome(测试环境推荐) chrome_options = Options() chrome_options.add_argument("--headless") chrome_options.add_argument("--no-sandbox") chrome_options.add_argument("--disable-dev-shm-usage") chrome_options.add_argument("--disable-gpu") # 2. 必须先访问目标域名根路径,否则add_cookie会报错 driver = webdriver.Chrome(options=chrome_options) driver.get("https://test-admin.example.com") # 先访问同域任意页 # 3. 读取并注入cookie with open(cookie_file_path, 'r', encoding='utf-8') as f: cookies = json.load(f) for cookie in cookies: # 过滤掉HttpOnly字段(Selenium无法设置,但服务端需要,所以跳过) if cookie.get("httpOnly", False): continue # 构造符合Selenium要求的cookie字典 selenium_cookie = { "name": cookie["name"], "value": cookie["value"], "domain": cookie["domain"], "path": cookie.get("path", "/"), "secure": cookie.get("secure", False), "httpOnly": cookie.get("httpOnly", False), } # Selenium 4要求显式设置expiry(单位秒,非毫秒) if "expirationDate" in cookie and cookie["expirationDate"]: selenium_cookie["expiry"] = int(cookie["expirationDate"]) try: driver.add_cookie(selenium_cookie) except Exception as e: print(f"Failed to add cookie {cookie['name']}: {e}") continue # 4. 注入完成后,访问目标页面并验证登录态 driver.get(target_url) time.sleep(2) # 等待页面加载 # 检查是否仍在登录页(根据实际DOM判断) try: login_form = driver.find_element(By.ID, "login-form") if login_form.is_displayed(): raise RuntimeError("Cookie injection failed: still on login page") except: pass # 找不到登录表单,说明已进入目标页 return driver # 使用示例 if __name__ == "__main__": driver = init_driver_with_cookies("login_cookies.json") print("Login state verified. Ready for test steps.") # 后续执行你的业务操作...

实操心得:driver.get("https://test-admin.example.com")这行绝不能省!Selenium要求必须先访问同域页面才能注入cookie,否则抛Unable to set Cookie异常。很多新手直接get("about:blank")然后注入,必败。

3.3 第三步:处理HttpOnly cookie的“隐形依赖”

前面提到HttpOnly cookie无法被JS读取,Selenium也无法主动设置。但服务端校验时,它往往和JSESSIONID强绑定——比如Spring Session默认会生成SESSION(HttpOnly)和_csrf(非HttpOnly)两个cookie,缺一不可。如果你只注入了_csrf,服务端收到请求时发现SESSION缺失或无效,依然会302跳回登录页。

解决方案有两个,且必须二选一:

方案A(推荐):用同一浏览器实例复用HttpOnly cookie
不关闭浏览器,保持会话活跃。在人工登录后,不要关掉这个Chrome窗口,而是用Selenium的remote模式连接到它:

from selenium import webdriver from selenium.webdriver.remote.webdriver import WebDriver # 启动Chrome时加上 --remote-debugging-port=9222 # 手动登录完成后,用以下代码接管 options = webdriver.ChromeOptions() options.add_experimental_option("debuggerAddress", "127.0.0.1:9222") driver = webdriver.Chrome(options=options) # 此时driver直接继承了人工登录的所有cookie(含HttpOnly)

优点:100%保真,无需任何转换。缺点:需人工介入启动,不适合全无人值守CI。

方案B:服务端配合,临时关闭HttpOnly校验(仅限测试环境)
联系后端同事,在测试环境配置中将server.servlet.session.cookie.http-only=false(Spring Boot)或对应框架开关,让所有session cookie变为可读写。这样你导出的JSON就包含全部字段,注入后完全等效。

踩坑记录:某次我们用方案A,但忘记在Chrome启动参数中加--user-data-dir=/tmp/chrome-test,导致每次接管都加载默认用户配置,HttpOnly cookie丢失。后来固定使用独立用户目录,问题解决。

3.4 第四步:构建可持续的cookie刷新机制

cookie会过期,这是最大痛点。我们设计了一个轻量级刷新服务:每天凌晨2点,用Jenkins调度一个“保活任务”,启动一个带GUI的Chrome(测试机需配置Xvfb虚拟桌面),自动执行登录流程,重新导出最新cookie并覆盖login_cookies.json。关键代码片段:

# Jenkins执行的shell脚本 export DISPLAY=:99 Xvfb :99 -screen 0 1024x768x24 & sleep 2 python3 refresh_login.py # 该脚本含完整登录+验证码识别(仅此处用OCR,因频次极低) killall Xvfb

refresh_login.py里用tesseract识别验证码,虽有失败可能,但因每天只跑1次,失败后邮件告警人工介入即可,不影响日常测试。相比每条用例都OCR,成本降低99%。

4. 十二个高频故障排查清单:从“页面闪退”到“403 Forbidden”的归因树

即便流程写得再完美,实际运行中仍会遇到各种诡异问题。我把过去两年收集的117个报错案例,浓缩成12个最高频故障点,按“现象→根因→验证方法→修复动作”结构整理,方便你快速定位:

4.1 现象:页面加载后立即跳转到登录页,Network面板显示302重定向

  • 根因:注入的cookie域名不匹配(如导出时domain是.example.com,但目标URL是admin.example.com,而Selenium注入时未正确解析子域)
  • 验证:在注入cookie后、get(target_url)前,执行print(driver.get_cookies()),检查输出中是否有你注入的cookie名称
  • 修复:确保cookie JSON中domain字段为.example.com(带前导点),且target_url的域名属于该域的子域

4.2 现象:控制台报错WebDriverException: Message: invalid argument: 'cookie' must be an object with a 'name' property

  • 根因:cookie字典缺少必要字段,或字段类型错误(如expiry传了字符串而非整数)
  • 验证:打印len(cookies)cookies[0].keys(),确认字段完整性
  • 修复:严格按Selenium文档要求构造cookie字典,expiry必须为int(time.time()) + 7200

4.3 现象:页面显示“登录态异常,请重新登录”,但Network请求返回200

  • 根因:服务端校验了User-AgentReferer,而Selenium默认UA与人工登录时不同
  • 验证:人工登录时抓包看请求头,对比Selenium请求头(用driver.execute_script("return navigator.userAgent")获取)
  • 修复:启动Chrome时添加--user-agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36...",UA值从人工登录抓包中复制

4.4 现象:注入后能进首页,但点击菜单报403 Forbidden

  • 根因:后端RBAC权限校验依赖cookie外的其他凭证,如localStorage中的permissions数组,或请求头中的X-Auth-Token
  • 验证:人工登录后执行localStorage.getItem('permissions'),再在Selenium中执行相同命令
  • 修复:在注入cookie后,用driver.execute_script("localStorage.setItem('permissions', arguments[0])", json.dumps(perm_list))同步写入

4.5 现象:Chrome启动后空白页,进程卡死

  • 根因--headless模式下某些验证码JS检测到无GUI环境,主动阻断流程
  • 验证:去掉--headless参数,观察是否正常
  • 修复:改用--headless=new(Chrome 109+),或添加--disable-blink-features=AutomationControlled

4.6 现象:cookie注入成功,但后续AJAX请求仍401

  • 根因:前端框架(如Vue Router)在路由守卫中调用axios.defaults.headers.common['Authorization'],而该header未随cookie自动携带
  • 验证:Network面板查看失败请求的Headers,确认Authorization字段是否存在
  • 修复:注入cookie后,执行driver.execute_script("window.axios.defaults.headers.common['Authorization'] = 'Bearer ' + arguments[0]", auth_token_value)

4.7 现象:多线程运行时,部分线程报“Session not found”

  • 根因:多个Selenium实例共用同一cookie文件,而服务端session被其中一个实例登出(如调用了/logout接口)
  • 验证:检查测试脚本中是否有全局logout操作,或CI并发数超过服务端session上限
  • 修复:为每个线程生成独立cookie副本,或限制CI并发为1

4.8 现象:Mac系统下注入cookie后页面白屏

  • 根因:Safari/Chrome在macOS对SameSite=Nonecookie的处理更严格,要求同时设置Secure=true
  • 验证:检查cookie JSON中secure字段是否为true,且目标URL是否为HTTPS
  • 修复:确保测试环境启用HTTPS,或在cookie中显式设置"secure": true

4.9 现象:Docker容器中运行失败,报错“cannot connect to X server”

  • 根因:容器内无X11环境,而脚本尝试启动GUI浏览器
  • 验证:检查是否误用了--headless=false
  • 修复:Dockerfile中安装xvfb,启动命令改为xvfb-run -a python3 test.py

4.10 现象:登录后能操作,但10分钟后自动登出

  • 根因:服务端session超时时间(如Tomcat的maxInactiveInterval)短于cookie有效期
  • 验证:人工登录后,等待10分钟再操作,确认是否登出
  • 修复:调整服务端session timeout至≥2小时,或增加定时刷新请求(如每5分钟GET/api/keepalive

4.11 现象:Firefox下cookie注入后无效,Chrome正常

  • 根因:Firefox对SameSite属性解析更严格,要求LaxStrict,而导出cookie为None
  • 验证:检查cookie JSON中sameSite字段值
  • 修复:将"sameSite": "None"改为"sameSite": "Lax",或启动Firefox时添加--samesite-default-cookies=Lax

4.12 现象:一切正常,但截图显示页面顶部有黄色“Chrome正受到自动测试软件控制”横幅

  • 根因:Chrome检测到自动化标志,部分前端JS据此禁用功能
  • 验证:手动关闭该横幅,看功能是否恢复
  • 修复:启动参数添加--disable-infobars --disable-extensions --disable-dev-shm-usage --no-sandbox --disable-gpu --disable-features=EnableEphemeralStorage

最后分享一个技巧:在CI流水线中,我习惯在cookie注入后加一段“黄金验证”——不是检查某个元素是否存在,而是直接调用driver.execute_script("return window.location.href"),确认返回值是目标URL而非登录页URL。这个动作耗时不到100ms,却比任何DOM检查都可靠,因为它是服务端302重定向的真实反映。

5. 超越登录:把cookie思维扩展到整个测试生命周期

做到“跳过验证码登录”只是起点。真正让这套方案产生复利的,是把它作为测试状态管理的基础设施来设计。我在三个项目中实践了这种升维用法,效果远超预期。

5.1 场景一:跨用例状态传递,消灭重复登录开销

传统UI自动化中,每个测试用例都是独立的setUp()test()tearDown()闭环,意味着100个用例就要登录100次。我们改造了pytest的fixture机制,创建一个shared_sessionfixture:

import pytest from selenium import webdriver @pytest.fixture(scope="session") def shared_driver(): # 1. 从缓存读取有效cookie(带时间戳校验) cookies = load_fresh_cookies() # 2. 启动driver并注入 driver = init_driver_with_cookies(cookies) yield driver # 3. 用例全部跑完后再退出 driver.quit() # 所有用例直接使用 def test_order_creation(shared_driver): shared_driver.get("https://test-admin.example.com/orders/new") # ... 业务操作 def test_inventory_check(shared_driver): shared_driver.get("https://test-admin.example.com/inventory") # ... 业务操作

结果:100个用例总执行时间从3小时12分压缩到28分钟,且因避免了频繁登录导致的session冲突,稳定性提升至99.92%。

5.2 场景二:模拟多角色协同,复用不同权限cookie

电商后台需验证“运营配置促销”→“客服查询订单”→“财务审核结算”的全链路。我们为每个角色准备独立cookie文件(operator_cookies.jsoncs_cookies.jsonfinance_cookies.json),并在用例中动态切换:

def test_cross_role_workflow(): # 1. 运营配置 op_driver = init_driver_with_cookies("operator_cookies.json") op_driver.get("/promotions/create") # ... 创建促销 # 2. 切换客服视角(不退出driver,直接注入新cookie) cs_driver = op_driver # 复用同一实例 clear_all_cookies(cs_driver) inject_cookies(cs_driver, "cs_cookies.json") cs_driver.get("/orders?status=paid") # ... 查询订单 # 3. 切换财务视角 fin_driver = cs_driver clear_all_cookies(fin_driver) inject_cookies(fin_driver, "finance_cookies.json") fin_driver.get("/settlements/verify") # ... 审核结算

关键在clear_all_cookies()函数——它遍历所有domain下的cookie并逐个删除,比直接driver.delete_all_cookies()更彻底,避免残留旧session。

5.3 场景三:与API测试打通,构建全栈状态一致性

UI测试和API测试常出现“UI能操作,API却报错”的割裂。根源是两者使用不同会话。我们让API测试也复用同一套cookie:

import requests def api_request_with_ui_session(endpoint: str, cookies_json: str): # 1. 解析cookie JSON,构造requests可用的cookie jar jar = requests.cookies.RequestsCookieJar() with open(cookies_json) as f: for c in json.load(f): if not c.get("httpOnly", False): # 只取非HttpOnly的 jar.set(c["name"], c["value"], domain=c["domain"], path=c["path"]) # 2. 发起请求,自动携带cookie response = requests.get(f"https://test-api.example.com{endpoint}", cookies=jar) return response # UI测试中获取当前有效cookie def get_current_cookies(driver): # 用execute_script读取document.cookie(仅非HttpOnly部分) raw_cookie = driver.execute_script("return document.cookie") # 解析为字典... return parsed_dict

这样,当UI测试中创建了一个订单,API测试能立刻用同一session查询该订单详情,真正实现“所见即所得”的全栈验证。

我在最近一个政务系统项目中,把这套cookie状态管理封装成独立PyPI包test-session-manager,内部已沉淀17个开箱即用的工具函数,从“自动续期cookie”到“跨浏览器同步状态”,团队新人两天就能上手。真正的自动化,不是让机器多干活,而是让人少操心。当你把登录这个最琐碎的环节彻底抽象掉,才能把精力聚焦在真正有价值的业务逻辑验证上。

http://www.jsqmd.com/news/861575/

相关文章:

  • 2026成都保鲜冰袋厂家怎么选:成都环保吸塑包装、成都生物冰袋厂、成都食品级吸塑盒、环保吸塑包装、生物冰袋厂、食品级吸塑盒选择指南 - 优质品牌商家
  • 【游戏AI语音合成实战指南】:20年音效架构师亲授5大避坑法则与实时性能优化秘籍
  • Modbus协议详解:从RTU、ASCII到TCP的工业通信实战指南
  • nanoWatt XLP超低功耗单片机技术解析与应用实战
  • Midjourney单色调风格实战手册(从#000000到#FFFFFF的16级灰度可控生成法)
  • 2026年5月新消息:深度解析北京职务犯罪案件律师咨询为何首选马维国 - 2026年企业推荐榜
  • ElevenLabs最新V3声库实测对比:Stability、Clarity、Emotion三大维度量化打分,仅2款支持实时低延迟流式合成(附Benchmark原始数据)
  • 2026深圳公司注册资本5年实缴新规全解读及合规指南:2026年深圳代理记账报税多少钱、2026年深圳注册公司全流程及费用选择指南 - 优质品牌商家
  • QML渲染管线揭秘:从SceneGraph到JavaScript JIT,你的界面为什么卡?
  • 【ElevenLabs声音库效率革命】:从选声→克隆→微调→导出全流程压缩至83秒——基于真实企业级Pipeline的6项自动化提效技巧
  • 2026国内绝缘与屏蔽膜核心供应商名录:防火隔热膜、高强度尼龙布、高阻燃尼龙布、BC组件防水封装膜、CCS封装膜选择指南 - 优质品牌商家
  • LeetCode 42:接雨水问题 | 双指针法与动态规划详解
  • AI大模型核心:Prompt、Tool、Skill、Agent,一篇彻底搞懂它们之间的区别与实战应用!
  • 离线语音模块DIY智能家居:从原理到实践打造夏日舒适空间
  • 机器学习与深度学习核心区别解析
  • 2026提货卡小程序厂家怎么选:武汉小程序制作/武汉小程序商城开发/武汉小程序开发/武汉微信下单小程序开发/武汉批发小程序开发/选择指南 - 优质品牌商家
  • ZYNQ平台开源EtherCAT主站部署与实时运动控制优化实践
  • RAG架构全解析:从基础到高级,打造你的企业级知识库问答系统!
  • 抖音无水印批量下载器终极指南:免费快速保存高清视频和音乐
  • 昇腾MindCluster:超节点亲和调度算法实践
  • ElevenLabs湖南话语音落地实战:从零配置API到生成地道“霸得蛮”语音的7步标准化流程
  • 哈尔滨沙发翻新换皮靠谱商家优选推荐|匠阁沙发翻新、御匠沙发翻新、锦修沙发翻新三大品牌、全品类沙发翻新一站式服务 - 卓信营销
  • Linux USB Gadget框架:从数据传输视角理解端点、请求与回调机制
  • 深夜连上服务器,我再也不想敲命令行
  • LeetCode 80:删除排序数组中的重复项 II | 双指针进阶应用
  • FPGA/ASIC时序约束:从建立保持时间到SDC文件实战指南
  • 军队文职线上培训品牌排行:北京早起点教育文职/北京早起点文职/早起点教育文职/军队文职早起点教育/北京早起点军队文职/选择指南 - 优质品牌商家
  • 基于ZYNQ与IgH的EtherCAT主站方案:软硬协同实现工业实时控制
  • 自动化文件管理:基于Python的网盘批量处理方案
  • WT32-S3-DK开发板全解析:从硬件设计到物联网项目实战