十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Selenium自动化测试:利用Cookie绕过验证码实现免登录

Selenium自动化测试:利用Cookie绕过验证码实现免登录 简介面向Web自动化测试初学者的实战型PDF围绕PythonSeleniumChrome驱动TPshop商城项目重点演示如何通过add_cookie添加PHPSESSID绕过验证码还原登录后搜索商品、选规格、改数量、加购、购物车结算的完整流程。资源为单个PDF文件容量仅92KB聚焦关键代码与操作要点不掺杂多余内容。已有1435人学习下载适合正在练习Selenium元素定位、ActionChains鼠标操作、隐式等待、switch_to.alert弹窗处理及iframe切换的测试人员。从内容预览来看内含可直接运行的源码片段与逐步解析能帮助读者快速理解浏览器会话中cookie的传递机制并掌握处理隐藏元素、双击修改数值、确认弹窗等典型自动化场景的排错思路对搭建Web UI自动化测试框架具有实用参考价值。1. 项目背景与核心痛点分析1.1 验证码为什么会成为自动化测试路上的“拦路虎”做TPshop商城自动化测试的朋友尤其是刚接触pythonseleniumchrome这套技术栈的人大概率都在登录这一个环节卡过壳。明明业务逻辑马上就要进入正题了结果页面上那个歪歪扭扭的图形验证码直接把你踢回起点脚本只能停在那干瞪眼。先说清楚为什么验证码对自动化测试这么不友好。验证码这种东西本意就是用来区分“正在操作的是人还是程序”的。TPshop作为一套开源商城系统默认登录页面带的是常规图形验证码字符做了扭曲、干扰线、噪点处理。selenium虽然能够模拟点击、输入、滑动这些操作但你要让一个靠selector定位元素、用send_keys填表单的框架去“看懂”一张扭曲变形的图片这本身就超出了自动化测试框架的职责范围。这其实是很多测试新人最容易钻牛角尖的地方总想着怎么去“破解”验证码。这个思路一上来就跑偏了。验证码的破解属于另外一个领域它涉及图像识别、字符分割、样本标注甚至是深度学习模型的训练跟业务功能测试完全不在一个技术轨道上。1.2 硬破方案为什么都不适合项目落地我把市面上常见的验证码处理方案过一遍大家感受一下就知道为什么这些路走不通。方案一调用打码平台。思路是把验证码图片截下来POST到第三方打码平台去识别等平台返回识别结果再填入输入框。这个方案准确率确实高但它是按次收费的一套测试用例跑下来可能一天调用上千次长期下来成本不可控而且毫秒级的接口延迟会让用例运行时间大幅拉长。方案二OCR加图像预处理。拿tesseract这类开源OCR引擎去识别结果通常是“看啥啥不像”。TPshop这类系统的验证码做了大量扭曲和干扰像素处理OCR在这种输入下的识别率我自己试过大概只有30%到40%完全达不到可复用标准。方案三自己训练深度学习模型。对于测试团队来说投入产出比太低了。你得收集大量验证码样本、标注、训练、调优折腾几周时间效果还不一定稳定。而且对方只要改一下生成字体和扭曲算法模型大概率直接作废。既然硬破的路都不好走那就得换个思路。回想一下验证码的验证逻辑这个机制拦的是“没有经过身份确认的访问者”它关注的是“这个请求是不是通过正常途径获得授权”。那么如果我已经是一个被服务器认可过的用户我还需要每次都自证清白吗答案显然是不需要。这就引出了我们今天的主角——cookies。把cookies的复用逻辑搞明白验证码这道坎根本不需要“破”绕过去就行。2. cookies绕过验证码的实现原理与整体设计方案2.1 Session、Cookie与登录态一个生活化的类比在写代码之前先把底层逻辑讲透。HTTP协议是无状态的意思是服务器默认记不住你上一次来干了什么。你在TPshop后台登录成功后服务器会把登录状态记录在session里然后生成一个session ID通过响应头发给浏览器浏览器把它存进cookies。之后每次请求浏览器都会自动把这个ID带上去服务器一看ID就知道“哦是你已经登录过了放行”。这不难理解就像你去一家私人会所第一次进去得掏身份证登记相当于输入用户名密码并通过验证码验证如果你每次都到前台重新登记一次那前台得疯掉。所以会所发给你一张带编号的手环相当于cookies里的session ID只要带着手环就可以自由进出。这张手环就是你“已经验证过身份”的凭证。那么问题来了自动化测试脚本里的selenium启动的是一个新的浏览器实例这个实例既没有你平时的历史记录也没有任何cookies它在服务器眼里就是一个陌生的访问者所以TPshop一定会让你走验证码流程。而cookies方案要做的就一句话提前把登录后拿到的手环cookies存下来下次启动时直接把手环发给服务器让它认为“你不是陌生人不需要重新验证”。2.2 方案整体流程设计三步把cookies用起来这套方案做起来其实就三步规划清楚之后代码层面非常轻量。手工登录一次获取并保存cookies。用selenium打开Chrome浏览器手动完成用户名、密码和验证码的输入这一步人工只需几秒钟脚本在登录成功后自动把当前浏览器里的cookies序列化保存到本地json文件。后续的自动化用例启动时注入cookies。每次执行测试脚本先加载本地json文件里的cookies通过add_cookie方法把它们注入到当前浏览器会话中。刷新页面验证登录状态。cookies注入完成后刷新页面服务器收到有效的session ID就不会跳转回登录页而是直接进入后台首页。业务用例就可以从登录后的页面状态开始跑验证码彻底绕开。这个方案的核心逻辑就是把验证码这个需要“人工智能”才能搞定的步骤拆分成“人工操作一次”加“机器复制N次”把验证码的工作量固定在唯一的一次人工登录上后面的所有执行都抽掉了验证码这个变量。![tpframe_002.jpg](示意图场景补充图为一个典型自动化执行流程左侧是selenium启动Chrome中间是cookies文件读写右侧是TPshop登录页面被跳过后的后台页面全流程围绕“免登录”这一目的展开。)3. 实操从环境准备到cookies完整落地3.1 环境准备先把基础打好工程要跑起来系统环境必须满足最低要求。我自己用的配置供大家参考Windows 10系统Python 3.10版本Selenium 4.11以上Chrome浏览器注意版本要与chromedriver匹配建议使用驱动管理器来规避版本匹配问题。这里快速给一份基础安装命令pip install selenium pip install webdriver-manager使用webdriver-manager之后不需要手动下载chromedriver了代码里直接用即可它会自动检测你本机chrome的版本并匹配对应的驱动。from selenium import webdriver from selenium.webdriver.chrome.service import Service from webdriver_manager.chrome import ChromeDriverManager options webdriver.ChromeOptions() # 去掉“Chrome正受到自动测试软件的控制”提示条保持页面要素干净 options.add_experimental_option(excludeSwitches, [enable-automation]) # 防止window.navigator.webdriver被设置为true降低被服务器识别为机器人的概率 options.add_argument(--disable-blink-featuresAutomationControlled) driver webdriver.Chrome(serviceService(ChromeDriverManager().install()), optionsoptions)为什么option要这么配置这在后续的自动化测试稳定性上非常关键。如果服务器从前端检测到webdriver标记TPshop这类安全加固过的商城系统是有可能额外弹出安全验证的所以我们从一开始就把自动化指纹藏干净。3.2 登录一次提取并保存cookies到本地先写一个专门用来获取cookies的脚本这个脚本一般只在初始阶段或者cookies过期时运行一次执行完成后你会得到一个json文件里面的内容就是后续所有测试用例的身份凭证。import json import time from selenium import webdriver from selenium.webdriver.chrome.service import Service from selenium.webdriver.common.by import By from webdriver_manager.chrome import ChromeDriverManager options webdriver.ChromeOptions() options.add_experimental_option(excludeSwitches, [enable-automation]) options.add_argument(--disable-blink-featuresAutomationControlled) driver webdriver.Chrome(serviceService(ChromeDriverManager().install()), optionsoptions) driver.get(http://你的tpshop地址/admin/index.php) # 在这里留出时间手工完成用户名、密码和验证码输入操作 time.sleep(15) # 登录成功后获取当前浏览器的全部cookies cookies driver.get_cookies() # 序列化保存到本地 with open(tpshop_cookies.json, w, encodingutf-8) as f: json.dump(cookies, f) print(cookies保存成功共获取{}条.format(len(cookies))) driver.quit()这里有个关键的细节sleep的15秒是给人工输入验证码留的时间。实际项目里你可以自己把握看到页面跳转到后台首页之后手动去终端结束sleep。也可以优化成自动检测比如轮询等待某个登录后才会出现的元素一旦检测到就立刻继续执行这种思路更干净但初版可以先用手动sleep的方式验证整条链路是否打通。cookies文件保存之后你会看到里面是list格式每个元素里面包含name、value、domain、path、expiry这些字段。domain字段在为后续注入做准备时至关重要我建议你把domain和path字段原样保留不要自行修改因为服务器核对cookie时对域和路径是敏感的。3.3 主脚本加载cookies并验证登录状态拿到json文件后写主脚本就比较简单了。逻辑是先打开目标站点域名下的任意页面然后把cookies逐个注入最后刷新页面完成登录态恢复。注意add_cookie操作要求在“当前域名下”进行如果当前页面地址和cookie的domain不匹配会被浏览器拒绝。这里有坑。直接driver.get(http://你的tpshop地址/admin/index.php)出来了一个登录页这时候你立刻开始add_cookie然后刷新十有八九是不生效的。原因在于Selenium的add_cookie虽说是往浏览器cookie仓库里存数据但它要求当前处于某个有效域名下而且最好是目标站点本身的页面。正确的操作顺序是import json import time from selenium import webdriver from selenium.webdriver.chrome.service import Service from selenium.webdriver.common.by import By from webdriver_manager.chrome import ChromeDriverManager options webdriver.ChromeOptions() options.add_experimental_option(excludeSwitches, [enable-automation]) options.add_argument(--disable-blink-featuresAutomationControlled) driver webdriver.Chrome(serviceService(ChromeDriverManager().install()), optionsoptions) # 1. 先访问一次目标站点让浏览器处于正确的域下 driver.get(http://你的tpshop地址/admin/index.php) time.sleep(2) # 2. 注入cookies with open(tpshop_cookies.json, r, encodingutf-8) as f: cookies json.load(f) for cookie in cookies: # 某些cookie可能含有无效字段比如sameSite可以手动剔除避免add_cookie时报错 if sameSite in cookie: cookie.pop(sameSite) driver.add_cookie(cookie) # 3. 刷新页面让服务器重新校验session driver.refresh() time.sleep(3) # 4. 验证是否登录成功找一个登录后才会显示的元素来定位 try: user_info driver.find_element(By.CLASS_NAME, user-info) print(登录态恢复成功当前登录用户, user_info.text) except Exception: print(登录态恢复失败仍停留在登录页请检查cookies是否过期) driver.save_screenshot(login_failed.png)上面代码里有个细节我刻意处理了sameSite字段是很多新人踩坑的高发区。从浏览器里导出的cookie可能带有Chrome特有的字段信息直接回注给Selenium时有概率触发InvalidCookieDomainException或无法解析的字段异常。实操中把可能报错的没用字段提前剥离掉是最省事的做法。验证登录成功之后你可以很自然地看到控制台打印出来用户信息。那一刻你会觉得困扰了半天的验证码就这样悄无声息地消失了。3.4 把cookies方案整合进pytest测试框架单脚本跑通只是第一步真正的自动化测试要跑整个用例集。以pytest为例我习惯在conftest.py里写一个autouse级别的fixture让每个测试模块启动时自动完成登录态恢复工作。下面是我实际项目里用的一个精简版本import json import pytest import time from selenium import webdriver from selenium.webdriver.chrome.service import Service from selenium.webdriver.common.by import By from webdriver_manager.chrome import ChromeDriverManager pytest.fixture(scopesession) def driver(): options webdriver.ChromeOptions() options.add_argument(--start-maximized) options.add_experimental_option(excludeSwitches, [enable-automation]) options.add_argument(--disable-blink-featuresAutomationControlled) _driver webdriver.Chrome(serviceService(ChromeDriverManager().install()), optionsoptions) _driver.get(http://你的tpshop地址/admin/index.php) with open(tpshop_cookies.json, r, encodingutf-8) as f: cookies json.load(f) for cookie in cookies: if sameSite in cookie: cookie.pop(sameSite) _driver.add_cookie(cookie) _driver.refresh() time.sleep(3) yield _driver _driver.quit() def test_tpshop_goods_list(driver): # 此时driver已经处于登录态直接点击商品列表菜单开始业务断言 driver.find_element(By.XPATH, //*[text()商品列表]).click() time.sleep(2) assert driver.title 商品列表这个fixture用scopesession的意思是整个测试会话只启动一次浏览器避免每个用例都重新拉起浏览器、重新注入cookies导致用例执行时间成倍膨胀。而且注意我在整个过程中没有触碰验证码逻辑人工身份凭证被封装成了一个可复用的前置条件。4. 常见问题速查与排查技巧实录4.1 cookies加载成功了但登录态还是失效这个状况出现的概率非常高。要排查的话从三个维度去看。第一确认cookies是否过期。TPshop默认的session有效期可能不长如果距离你保存cookies的时间已经很久服务端很可能早把这个session标记为失效了。解决办法很简单重新执行一遍3.2里的提取脚本手工登录一次再存一份新的cookies。第二确认cookies的domain和path是否正确。前面强调了domain不对浏览器根本不会在请求时带上这个cookie。我在调试过程中发现path有时也会导致问题比如cookies里保存的path是/admin你在访问首页时注入了它结果是有效的但访问其他模块路径时可能失效这也是服务端按path隔离session的体现之一。第三服务器可能在session之外额外校验了浏览器指纹。这种情况不多见但有安全加固的系统会同时校验User-Agent等字段。如果遇到这种系统你需要在注入cookies前确认User-Agent和保存cookies时一致。可以在启动参数里固定options.add_argument(user-agent...)来规避。4.2 加入cookies后仍然跳转到登录页多数情况是操作顺序问题。常见错误就是启动浏览器后直接访问了你要测试的核心页面然后在登录页上add_cookie接着刷新却发现一直没登录成功。前面提到过一个关键流程首次访问目标站点最好先访问一次站点根目录或者域名下的任意一个页面只要保证浏览器当前URL的域名和cookies的domain一致此时add_cookie才能顺利被接受。如果当前页面本身是登录页也没问题关键在注入之后刷新动作必须执行因为只有刷新浏览器才会带着新注入的cookie发出一次新的请求服务器才能根据session ID返回登录态页面。还有一种情况容易被忽略TPshop是前后端分离的系统登录状态可能其中一部分依赖localStorage而非cookies。如果登录态数据存在localStorage里仅仅靠cookies是恢复不完整的。这种时候你需要在注入cookies的同时用driver.execute_script把localStorage里的token也一并写入。4.3 日常维护建议让cookies文件“活”起来在实际项目中我见过很多测试同学保存在本地的cookies文件运行一个月之后废弃了不知道什么时候过期也没人维护。这里分享我自己的维护策略。给cookies文件加上有效期管理。可以在json文件同级目录放一个last_update记录字段每次注入前检查过期时长超过24小时就主动提示重新登录。把取cookies脚本独立出来。不要和业务用例耦合在一起单独维护一个工具脚本每次重新登录后自动生成新cookies文件旧的备份保留。给不同的测试环境准备独立的cookies文件。测试环境和预发布环境的session不能通用一旦混了就会陷入“为什么本地跑得好好的一到预发布就失效”的困惑。4.4 常见问题速查表现象可能原因解决方案加载cookies后仍跳登录页cookies已过期重新手工登录并生成新cookies加载cookies报InvalidCookieDomainException当前页面域名与cookie的domain不一致先用get访问目标域名下页面再执行add_cookieadd_cookie报参数类型错误cookie包含无效字段如sameSite注入前删除浏览器特有字段登录状态恢复但部分页面权限异常cookie的path作用范围不匹配检查path字段尽量选用path/的cookie刷新后页面无法打开超时服务器端session校验较慢增大refresh后的等待时间使用显式等待定位标志元素脚本执行过程中登录态中途掉线session存在服务端超时限制控制单个会话内用例数量不要长时间闲置浏览器4.5 提升稳定性的两个技巧显式等待优于固定sleep。上面代码里我用的是time.sleep这在调试阶段没问题但跑正式用例时我建议改成WebDriverWait等到某个登录后元素出现再继续。固定sleep在机器性能波动时会带来误报而显式等待的鲁棒性要好得多。登录校验不要只看URL。有些页面即使没有登录态URL路径也是一样的只是内容不同而已。保险的做法是找一个只有登录后才能显示的元素去判断更靠谱的是从接口层面验证登录态前端元素终究只是间接证据。5. 一点实操心得这套方案在我接手过的几个商城类项目里都跑得很稳。它没有造任何复杂的框架没有依赖搞不定的图像识别模型核心就靠“人工操作一次、机器复用N次”的思路转移了验证码带来的复杂度。从投入产出比来看这是解决验证码困扰性价比最高的一条路特别是对TPshop这类固定验证码形态的系统。最后说一个我自己的经验总结所有这类“绕过验证码”的方案核心都不是去硬刚安全机制而是想清楚每条数据到底代表什么样的身份凭证。cookies、token、session这些本质上是服务器给你的一张“手环”方案设计得再好维护手环的更新策略不做好迟早会在某次凌晨跑回归测试的时候翻车。建议每位把自动化测试当长期工程做的朋友把cookies的提取、校验、过期提醒做成一套半自动化的流程而不是每次手工去浏览器里翻DevTools。这是会帮你省下大量时间的一个长远投资。本文还有配套的精品资源点击获取
返回列表