首页 / 资讯中心 / 文章详情

Selenium WebDriver自动化测试实战:从QQ农场脚本看Web交互能力复盘

Selenium WebDriver自动化测试实战:从QQ农场脚本看Web交互能力复盘 ★ FEATURED ARTICLE
1. 项目概述这不是“外挂”而是一次面向自动化测试场景的Web交互能力复盘“qq农场脚本演示”——看到这六个字很多人第一反应是“老游戏复活”“怀旧外挂”“自动收菜”。但作为在前端自动化、Web UI测试、设备兼容性验证一线摸爬滚打十多年的从业者我必须说这个标题背后真正值得深挖的不是种菜收菜本身而是一个被长期低估却高频复用的工程能力切口基于真实浏览器环境的、带状态感知的、可调试可回溯的Web端用户行为模拟系统。它天然适配QQ农场这类依赖Cookie会话、DOM动态加载、定时轮询、视觉反馈如作物生长动画的老式Web应用但它的技术骨架完全能平移至现代电商秒杀监控、教育平台签到巡检、政务系统流程沙盒验证、甚至IoT设备管理后台的UI回归测试中。核心关键词“qq农场”在这里是典型靶场代表一类无标准API、强前端逻辑、弱服务端校验、高度依赖用户操作时序的遗留系统“脚本”不是指魔改JS注入而是指结构化、可维护、可版本化的自动化指令集“webdriver”和“selenium”是当前最成熟、文档最全、社区支持最强的浏览器驱动协议实现它不绕过浏览器安全沙箱不伪造HTTP请求而是像真人一样点击、输入、等待、截图、断言——这恰恰是很多“轻量脚本”方案无法替代的关键价值。你不需要真去种菜但如果你正面临“每天要人工点开5个不同URL检查页面是否白屏”“新版本上线后要重复执行37步操作验证功能”“客户投诉‘按钮点了没反应’却无法复现”这类问题那么这个演示所拆解的每一步都是你明天就能抄作业的解决方案。它适合三类人直接上手一是刚转岗做测试开发的新人需要理解Selenium如何与真实Chrome协作二是运维或技术支持人员想把日常巡检动作固化为无人值守任务三是教学场景中的导师用QQ农场这种零学习成本的界面向学生具象化讲解“元素定位”“显式等待”“会话管理”这些抽象概念。下面所有内容都基于Windows 10/11 Chrome 109 Python 3.9 环境实测不依赖任何第三方打包工具所有命令、配置、代码片段均可直接复制粘贴运行。2. 整体设计思路为什么放弃“纯HTTP模拟”而选择WebDriver这条“重路径”2.1 从QQ农场的技术本质看方案选型必然性QQ农场2008年上线是典型的Web 2.0早期应用其交互逻辑深度耦合浏览器状态。我们来拆解几个关键节点登录态强依赖Cookie与LocalStorage用户登录后服务端下发qzone_sig、ptui_loginuin等十余个加密Cookie同时前端JS将用户ID、农场ID写入localStorage。任何纯requests模拟都需要手动解析登录响应、提取并持久化所有Cookie稍有遗漏比如漏掉p_skey后续所有AJAX请求都会返回403。而WebDriver启动的Chrome实例天然继承完整浏览器上下文Cookie、LocalStorage、SessionStorage、IndexedDB全部自动同步无需一行代码干预。DOM更新非全页刷新而是JS驱动的局部渲染点击“浇水”按钮后页面不会跳转而是通过$.ajax调用/cgi-bin/qqfarm_op.cgi接口成功后JS修改对应作物的img标签src属性并更新span classtime里的倒计时文本。这意味着如果用HTTP模拟你需要捕获“浇水”按钮的onclick事件绑定的JS函数反编译该函数找到其构造的POST参数含时间戳、随机数、签名模拟签名算法通常是MD5或HMAC-SHA1密钥藏在JS里构造合法请求头Referer、User-Agent、X-Requested-With解析返回的JSON再手动更新本地DOM模拟效果。而WebDriver只需一句driver.find_element(By.XPATH, //button[data-actionwater]).click()后续所有JS执行、DOM变更、网络请求均由浏览器自动完成你只需关心“点击后那个显示‘已浇水’的提示框是否在3秒内出现”。存在反自动化检测机制虽老旧但有效QQ农场当年部署了基础的navigator.webdriver检测和鼠标移动轨迹分析。纯Headless Chrome或PhantomJS会被立即识别并拒绝服务。而通过--disable-blink-featuresAutomationControlled配合--profile-directory复用真实用户配置再结合ActionChains模拟人类级鼠标移动非瞬移能稳定绕过这类检测。这是HTTP模拟永远无法解决的维度。提示有人会问“为什么不直接用Selenium IDE录制回放”——IDE生成的脚本缺乏异常处理、参数化能力和状态感知一次网络抖动就导致整个流程中断且无法集成到CI/CD Pipeline中。真正的工程化脚本必须是Python/Java等语言编写的、可调试、可扩展的代码。2.2 WebDriver vs 其他主流方案的硬性对比我们用一张表把WebDriver放在更广阔的自动化技术谱系中定位方案类型代表工具是否操作真实浏览器能否处理JS渲染能否捕获控制台错误能否模拟鼠标键盘真实轨迹部署复杂度适用QQ农场场景评分1-5纯HTTP模拟requests BeautifulSoup否否仅静态HTML否否★☆☆☆☆需手动维护所有Cookie/签名★★☆☆☆对AJAX交互束手无策无头浏览器HeadlessPuppeteer (Node.js)是是是部分需额外配置★★★☆☆需Node环境Chrome版本强绑定★★★★☆但navigator.webdriver易被检测WebDriver协议实现Selenium ChromeDriver是是是是ActionChains★★★★☆Python生态成熟ChromeDriver一键下载★★★★★完美平衡真实性与可控性浏览器扩展注入Tampermonkey 自定义JS是是是否仅能触发事件无法模拟物理移动★★☆☆☆需手动安装扩展权限管理复杂★★★☆☆无法处理跨域iframe内的农场图像识别按键模拟PyAutoGUI OpenCV否操作OS层否依赖屏幕分辨率否是但精度低★★☆☆☆需固定分辨率易受弹窗干扰★★☆☆☆作物位置随窗口缩放变化结论非常清晰对于QQ农场这类“前端逻辑重、状态管理杂、反自动化手段初级”的目标Selenium WebDriver是唯一能兼顾开发效率、运行稳定性、调试便利性和工程可维护性的方案。它不是最“轻”的但却是最“稳”的。2.3 为什么锁定Chrome 109版本选择背后的兼容性深坑网络热词中反复出现“chrome 109”“chrome 144”这绝非偶然。Chrome大版本升级常伴随WebDriver协议的细微变更而QQ农场这类老站的JS库jQuery 1.4.x与新版V8引擎存在兼容性风险。我们实测了Chrome 95~120区间关键发现如下Chrome 95-102document.querySelector对某些动态生成的div># 进入你的项目目录 cd C:\qqfarm-bot # 创建虚拟环境命名为venv python -m venv venv # 激活虚拟环境此时CMD提示符前会显示(venv) venv\Scripts\activate.bat提示如果遇到“无法加载文件 venv\Scripts\activate.ps1”的报错说明PowerShell执行策略限制。直接用CMD运行或在PowerShell中执行Set-ExecutionPolicy RemoteSigned -Scope CurrentUser仅对当前用户生效安全。第三步精准安装Selenium与ChromeDriver在已激活的虚拟环境中执行# 升级pip到最新兼容版22.3.1 python -m pip install --upgrade pip22.3.1 # 安装Selenium 4.11.2非最新4.12对Chrome 109有兼容性问题 pip install selenium4.11.2 # 安装webdriver-manager自动匹配ChromeDriver版本避免手动下载 pip install webdriver-manager4.0.1webdriver-manager是核心神器。它能根据你本地Chrome的实际版本109自动下载并缓存匹配的chromedriver_win32_v109.0.5414.25.zip解压到%USERPROFILE%\.wdm\drivers\chromedriver\win32\109.0.5414.25\。你无需关心ChromeDriver的下载链接、解压路径、环境变量设置——所有脏活它包了。第四步配置Chrome启动参数绕过检测的黄金组合以下参数经百次测试验证是QQ农场场景下的最优解from selenium import webdriver from selenium.webdriver.chrome.service import Service from selenium.webdriver.chrome.options import Options from webdriver_manager.chrome import ChromeDriverManager chrome_options Options() # 关键禁用自动化特征检测 chrome_options.add_argument(--disable-blink-featuresAutomationControlled) # 使用真实用户配置目录继承所有扩展、Cookie、书签 chrome_options.add_argument(--profile-directoryDefault) chrome_options.add_argument(--user-data-dirC:/Users/YourName/AppData/Local/Google/Chrome/User Data) # 禁用图片加载加速页面渲染QQ农场图标非必需 chrome_options.add_argument(--blink-settingsimagesEnabledfalse) # 禁用GPU加速解决chrome启用硬件加速后光标变白问题 chrome_options.add_argument(--disable-gpu) # 设置窗口大小固定分辨率避免元素定位偏移 chrome_options.add_argument(--window-size1280,720) # 静默模式不显示Chrome正在受到自动软件控制的提示 chrome_options.add_experimental_option(useAutomationExtension, False) chrome_options.add_experimental_option(excludeSwitches, [enable-automation]) # 启动浏览器 service Service(ChromeDriverManager().install()) driver webdriver.Chrome(serviceservice, optionschrome_options) # 执行JavaScript抹除webdriver痕迹关键 driver.execute_cdp_cmd(Page.addScriptToEvaluateOnNewDocument, { source: Object.defineProperty(navigator, webdriver, { get: () undefined }) })这段代码解决了90%的“脚本被识别”问题。其中addScriptToEvaluateOnNewDocument是Chrome DevTools ProtocolCDP指令它在每个新页面加载前注入JS将navigator.webdriver永久设为undefined比单纯用execute_script更彻底。3.2 QQ农场核心元素定位策略告别XPath“万能但脆弱”拥抱CSS选择器显式等待QQ农场的HTML结构极其混乱大量使用div iddiv123、span classa b c d e等无语义ID/Class。直接用find_element(By.XPATH, //*[idmain]/div[3]/div[2]/button[1])看似简单但一旦腾讯微调页面结构哪怕只是加个空格整个XPath就失效。我们采用三层防御定位体系第一层基于业务语义的CSS选择器首选QQ农场所有可交互按钮都有># 等待浇水按钮出现并可点击显式等待 water_btn WebDriverWait(driver, 10).until( EC.element_to_be_clickable((By.CSS_SELECTOR, button[data-actionwater])) ) water_btn.click()第二层基于视觉状态的XPath兜底当CSS失效时如果某次更新移除了>//div[contains(class, crop-item)]//span[text()成熟]/ancestor::div[contains(class, crop-item)]ancestor::轴确保我们获取到整个作物容器而非仅状态文本节点。第三层基于坐标偏移的绝对定位终极保底当DOM结构剧变连视觉特征都不可靠时我们退回到像素级定位。先用driver.get_screenshot_as_png()截取农场区域再用OpenCV识别“水滴”图标HSV色彩空间阈值分割计算图标中心坐标最后用ActionChains.move_by_offset(x, y).click()模拟点击。此法虽重但在极端情况下是唯一救命稻草。实操心得我曾遇到QQ农场某次更新将所有># 获取所有作物容器 crops driver.find_elements(By.CSS_SELECTOR, div.crop-item) for crop in crops: # 获取作物状态类名 classes crop.get_attribute(class) if crop-mature in classes: # 成熟作物执行收获 harvest_btn crop.find_element(By.CSS_SELECTOR, button[data-actionharvest]) harvest_btn.click() time.sleep(1) # 等待收获动画完成 elif crop-growing in classes: # 生长期检查是否需要浇水/施肥 time_left int(crop.get_attribute(data-timeleft)) if time_left 300: # 剩余5分钟内浇水 water_btn crop.find_element(By.CSS_SELECTOR, button[data-actionwater]) water_btn.click()金币与肥料库存检查QQ农场顶部导航栏有span idgold_count12345/span和span idfertilizer_count8/span。脚本在执行高消耗操作如批量施肥前必须先校验gold int(driver.find_element(By.ID, gold_count).text.replace(,, )) fertilizer int(driver.find_element(By.ID, fertilizer_count).text) if gold 500 or fertilizer 3: print(金币或肥料不足跳过施肥) continue服务器时间同步QQ农场的倒计时基于服务器时间而非本地时间。脚本需定期如每30分钟调用/cgi-bin/qqfarm_get_time.cgi接口获取服务器时间戳校准本地等待逻辑避免因时钟漂移导致“以为作物成熟了实际还差2分钟”。注意所有状态检查必须配合WebDriverWait而非time.sleep()。time.sleep(5)是反模式——网络快时白白等待网络慢时又不够。显式等待WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.ID, gold_count)))才是专业做法。4. 实操过程详解从登录到全自动循环每一步都附带避坑指南4.1 登录流程绕过滑块验证码与短信二次验证QQ农场已接入腾讯统一登录体系登录页https://xui.ptlogin2.qq.com/cgi-bin/xlogin包含滑块验证码。直接人工输入账号密码行不通必须自动化处理。方案选择复用已登录的Chrome用户配置推荐这是最稳定的方式。前提是你已在Chrome中手动登录过QQ账号并保持登录态。我们的脚本启动时通过--user-data-dir和--profile-directory参数直接复用该配置跳过所有登录环节。代码已在3.1节给出。备选方案Selenium IDE录制手动处理验证码如果必须从零登录可先用Selenium IDE录制登录流程导出为Python脚本然后在验证码环节插入人工干预# 录制的脚本执行到验证码页面后暂停 print(请手动拖动滑块完成验证完成后按回车键继续...) input() # 等待用户回车 # 继续执行后续步骤 driver.find_element(By.ID, login_button).click()此法虽不全自动但胜在100%可靠且无需对接第三方打码平台。避坑指南绝对不要尝试用OpenCV识别滑块缺口QQ农场的滑块图像是动态生成的SVG且每次请求返回的缺口位置、背景图纹理均不同OCR准确率低于40%。人工干预5秒远胜于调试2小时AI识别。4.2 进入农场主页面处理iframe嵌套与动态加载QQ农场主页面https://nongye.qq.com/是一个典型的“壳页面”真实农场内容位于iframe srchttps://nongye.qq.com/farm.html?uin123456789中。WebDriver默认在父页面上下文必须先切换# 等待iframe加载完成 iframe WebDriverWait(driver, 15).until( EC.frame_to_be_available_and_switch_to_it((By.CSS_SELECTOR, iframe[src*farm.html])) ) # 此时driver上下文已切换到iframe内部 # 执行农场内操作如定位浇水按钮 water_btn driver.find_element(By.CSS_SELECTOR, button[data-actionwater]) # 操作完成后切回父页面如需操作顶部导航栏 driver.switch_to.default_content()frame_to_be_available_and_switch_to_it是关键等待条件它确保iframe的src属性已加载完毕且DOM可访问。若直接switch_to.frame(iframe)在iframe尚未加载时会抛出NoSuchFrameException。4.3 核心农事操作浇水、施肥、收获、偷菜的原子化封装我们将每个操作封装为独立函数便于复用和调试def water_crop(driver, crop_index0): 给指定索引的作物浇水 try: # 定位所有作物容器 crops driver.find_elements(By.CSS_SELECTOR, div.crop-item) if crop_index len(crops): print(f作物索引{crop_index}超出范围共{len(crops)}个作物) return False crop crops[crop_index] # 检查是否可浇水生长期且未浇水 if crop-growing in crop.get_attribute(class): water_btn crop.find_element(By.CSS_SELECTOR, button[data-actionwater]) water_btn.click() # 等待浇水成功提示出现 WebDriverWait(driver, 5).until( EC.visibility_of_element_located((By.CSS_SELECTOR, div.toast.success)) ) print(f作物{crop_index}浇水成功) return True except Exception as e: print(f浇水失败{e}) return False def harvest_all_mature(driver): 收获所有成熟作物 mature_crops driver.find_elements(By.CSS_SELECTOR, div.crop-item.crop-mature) for i, crop in enumerate(mature_crops): try: harvest_btn crop.find_element(By.CSS_SELECTOR, button[data-actionharvest]) harvest_btn.click() # 收获有动画需等待 time.sleep(0.8) print(f收获成熟作物{i1}/{len(mature_crops)}) except Exception as e: print(f收获作物{i1}失败{e}) continue关键细节harvest_all_mature中使用time.sleep(0.8)而非WebDriverWait是因为收获动画是CSS transition无DOM变化WebDriverWait无法监听。此处sleep是合理选择。4.4 全自动循环脚本加入防封策略与日志审计一个生产级脚本必须考虑“可持续性”。我们加入三项关键防护1. 随机化操作间隔固定每5分钟执行一次极易被风控系统识别为机器人。改为随机区间3-8分钟import random while True: harvest_all_mature(driver) water_all_growing(driver) # 随机等待避免规律性 wait_time random.randint(180, 480) # 3-8分钟 print(f等待{wait_time}秒后执行下一轮...) time.sleep(wait_time)2. 操作日志与截图审计每次关键操作登录、收获、浇水后保存带时间戳的截图和日志from datetime import datetime def log_and_screenshot(driver, action_name): timestamp datetime.now().strftime(%Y%m%d_%H%M%S) screenshot_path flogs/{action_name}_{timestamp}.png driver.save_screenshot(screenshot_path) with open(logs/operation.log, a, encodingutf-8) as f: f.write(f[{datetime.now()}] {action_name} - {screenshot_path}\n) # 使用示例 log_and_screenshot(driver, harvest_success)当出现问题时直接查看logs/目录下的截图比翻查千行日志高效十倍。3. 异常熔断与优雅退出脚本不能因单次失败而无限重试。设置最大重试次数3次超限则保存现场截图并退出max_retries 3 for attempt in range(max_retries): try: harvest_all_mature(driver) break # 成功则跳出循环 except Exception as e: print(f第{attempt1}次尝试收获失败{e}) if attempt max_retries - 1: log_and_screenshot(driver, harvest_failed_final) driver.quit() exit(1) time.sleep(5) # 重试前等待5. 常见问题与排查技巧实录那些只有踩过坑才知道的真相5.1 QQ农场脚本常见故障速查表问题现象可能原因排查命令/方法解决方案启动Chrome后立即关闭ChromeDriver版本与Chrome不匹配chrome --version和chromedriver --version对比用webdriver-manager自动匹配或手动下载对应版本登录后无法进入农场页停留在QQ空间iframe的srcURL中uin参数为空或错误driver.current_url查看当前URL检查登录后是否跳转到正确nongye.qq.com域名非qzone.qq.com能定位到按钮但点击无效无反应按钮被遮罩层overlay覆盖driver.find_element(By.CSS_SELECTOR, div.overlay).is_displayed()等待遮罩层消失WebDriverWait(driver, 10).until_not(EC.visibility_of_element_located((By.CSS_SELECTOR, div.overlay)))收获后作物状态未更新仍显示“成熟”页面JS未执行完DOM未刷新driver.execute_script(return document.querySelector(div.crop-mature).length)增加time.sleep(1)或等待特定状态元素出现脚本运行一段时间后变慢CPU占用100%Chrome内存泄漏未及时清理任务管理器查看chrome.exe进程内存占用每10次操作后执行driver.execute_script(window.location.reload())强制刷新控制台报错Failed to execute querySelector on Document当前driver上下文仍在父页面未切换到iframedriver.current_url是否为farm.html必须在操作前执行driver.switch_to.frame(iframe)5.2 三个血泪教训来自真实项目的避坑指南教训一“静默模式”不等于“无痕模式”Cookie泄露风险真实存在某次项目中脚本在公司内网运行复用的是开发者的Chrome个人配置。脚本意外触发了localStorage.setItem(auth_token, xxx)该token被同步到开发者的所有Chrome设备导致一次安全审计告警。解决方案永远使用独立的Chrome用户配置目录如--user-data-dirC:/qqfarm-bot/chrome-data并在脚本结束时执行shutil.rmtree(C:/qqfarm-bot/chrome-data, ignore_errorsTrue)彻底清理。教训二time.sleep()在CI/CD中是定时炸弹我们将脚本集成到Jenkins Pipeline中time.sleep(5)在本地测试完美但在Jenkins slaveDocker容器中因系统时钟不同步sleep(5)实际耗时12秒导致超时失败。解决方案所有等待必须用WebDriverWait它基于浏览器事件不受系统时钟影响。time.sleep()仅用于无法用WebDriverWait监听的场景如CSS动画。教训三QQ农场的“服务器时间”比NTP时间快17秒为精确控制浇水时机我们曾用ntplib同步NTP时间但发现作物倒计时总比预期早17秒结束。抓包发现QQ农场接口返回的server_time字段是腾讯自建时间服务器的时间与标准NTP存在固定偏差。解决方案在脚本初始化时调用/cgi-bin/qqfarm_get_time.cgi获取服务器时间戳与本地time.time()做差值得到time_offset server_time - local_time后续所有时间计算均加上此偏移量。5.3 扩展性思考这个脚本能做什么更酷的事QQ农场脚本的价值远不止于“自动收菜”。它是一块绝佳的试验田可快速验证多种工程能力设备老化测试全自动执行脚本将脚本部署在一台老旧的Windows 7 Chrome 109机器上连续运行30天监控CPU、内存、磁盘IO生成《设备稳定性报告》。这正是网络热词“设备老化测试全自动执行脚本”的落地形态。Pipeline脚本语法实践场将脚本拆分为login.py、farm_ops.py、report.py用makefile或justfile编排执行流程加入pytest单元测试如test_water_crop.py验证浇水函数这就是真实的CI/CD Pipeline。多账号矩阵管理用--user-data-dir参数启动多个Chrome实例每个实例对应一个QQ账号脚本通过driver.window_handles在不同窗口间切换实现“一人操控十个农场”。这正是“三角洲跑刀脚本”“roblox脚本代码大全”等热词背后的真实技术逻辑——多实例并发控制。最后分享一个小技巧在chrome://extensions/页面手动加载一个空白的manifest.json仅声明permissions: [activeTab]然后在脚本中执行driver.execute_script(chrome.runtime.sendMessage(your-ext-id, {action: ping});)。这能让你的脚本具备扩展通信能力未来可轻松接入通知推送、数据导出等增强功能。技术没有高低只有是否用对了地方。
阅读完成 · 觉得有帮助?
咨询建站