VNC 自动化测试代理_第1页
VNC 自动化测试代理_第2页
VNC 自动化测试代理_第3页
VNC 自动化测试代理_第4页
VNC 自动化测试代理_第5页
已阅读5页,还剩13页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

VNC自动化测试代理(VNC-Agent)用Python解析RFB协议,截获屏幕帧,并封装成CrewAI的Tool,让AI能“看见”远程桌面并执行点击/输入,实现GUI自动化。第一部分:架构设计(避开LibVNC的坑)在Python生态中,vncdotool

是命令行的封装(慢、依赖外部进程),而

pyvirtualdisplay

只能管显示。实战中,推荐直接操作

golang

rust-vnc

的绑定性太强。我们选用纯Python异步方案:aiovnc(异步RFB客户端)+

Pillow(图像处理)+

opencv-python(模板匹配)。架构分层:连接层:维护WebSocket或TCP长连接,处理VNC握手与认证(重点解决

tight

编码)。帧缓存层:将RFB协议传来的矩形更新(RectangleUpdates)合成为一张完整

PILImage。控制层:将绝对坐标(X,Y)转为VNC的

PointerEvent

KeyEvent。Agent接口层:封装为CrewAI的

BaseTool,提供

screenshot()

click()。第二部分:核心代码实战(纯Python实现)环境安装(请避开

vncdotool

的坑,直接用

aiovnc):pipinstallaiovncpillowopencv-pythonwebsocketscrewai1.异步VNC客户端封装(处理屏幕帧)aiovnc

官方例子较复杂,这里提供一个

极简单例模式

的客户端包装器:importasynciofromaiovncimportVNCClientfromPILimportImageimportioclassAsyncVNCController:def__init__(self,host,port=5900,password=""):self.host=hostself.port=portself.password=passwordself.client=Noneself._latest_frame=Noneasyncdefconnect(self):#注意:aiovnc需要传入eventloop和帧回调self.client=VNCClient(self.host,self.port,password=self.password,frame_cb=self._on_frame_received#每收到一帧回调)awaitself.client.connect()returnselfdef_on_frame_received(self,frame):#frame是bytes格式的rawRGB数据(取决于编码)#转换为PILImage并压缩为JPEG以便传给LLMifframe:img=Image.frombytes("RGB",(self.client.width,self.client.height),frame)self._latest_frame=imgasyncdefget_screenshot(self,quality=50):"""供外部调用,返回Base64编码的图像,减少Token消耗"""ifself._latest_frameisNone:returnNonebuffered=io.BytesIO()self._latest_frame.save(buffered,format="JPEG",quality=quality)returnbase64.b64encode(buffered.getvalue()).decode('utf-8')asyncdefclick(self,x,y,button=1):"""绝对坐标点击"""awaitself.client.pointer_event(x,y,button_mask=button)#1=左键awaitasyncio.sleep(0.1)awaitself.client.pointer_event(x,y,button_mask=0)#释放asyncdeftype_text(self,text):"""输入文本(仅支持ASCII,中文需剪贴板)"""forcharintext:#映射键码(这里简化处理,实际需用keysym)awaitself.client.key_event(ord(char),down=True)awaitself.client.key_event(ord(char),down=False)2.解决VNC最恶心的痛点:图像编码与光标乱码问题:VNC默认

raw

编码流量巨大,tight

编码在Python中解析常报错。实战解决方案:在

aiovnc

连接参数中强制指定

encodings=["hextile","copyrect"],放弃Tight压缩,换取稳定性。对于1080p屏幕,开启

only_updates=True

只获取变化区域。第三部分:将VNC植入CrewAI的Tool(杀手级应用)让AIAgent具备“视觉操作”能力。这里创建一个

VNCActionTool,输入自然语言,输出坐标点击。fromcrewai.toolsimportBaseToolfrompydanticimportBaseModel,Fieldimportcv2importnumpyasnpclassVNCActionSchema(BaseModel):action:str=Field(...,description="操作类型:'screenshot'或'click'或'find_and_click'")target_text:str=Field(None,description="如果action是find_and_click,描述要点击的按钮文字/图标特征")classVNCAutoTool(BaseTool):name:str="远程桌面操控器"description:str="截取远程Windows/Linux桌面截图,或根据视觉特征点击特定坐标"args_schema:type[BaseModel]=VNCActionSchemadef_run(self,action:str,target_text:str=None)->str:#由于CrewAI是同步调用,这里需要运行异步连接,用asyncio.run()包一层vnc=AsyncVNCController("00",password="123456")asyncio.run(vnc.connect())ifaction=="screenshot":img_b64=asyncio.run(vnc.get_screenshot())#关键技巧:为了节省LLMToken,不要把图片发给LLM,而是用OCR+目标检测#使用easyocr或paddleocr提取文本坐标importeasyocrreader=easyocr.Reader(['ch_sim','en'])result=reader.readtext(img_b64)#这里直接传base64会报错,实际要写临时文件returnf"识别到的文本及坐标:{result}"elifaction=="find_and_click":#简化版:使用OpenCV模板匹配(假设提前切了按钮图)#实际项目强烈建议接入GroundingDINO进行零样本检测asyncio.run(vnc.click(100,200))return"已点击坐标(100,200)"第四部分:高能实战——无头Chrome中的VNC录制很多场景下,VNC连接的是Linux无头服务器上的

Xvfb

虚拟显示器。1.启动虚拟显示器+VNCServer:Xvfb:99-screen01920x1080x24&x11vnc-display:99-forever-nopw-listenlocalhost-rfbport5900&2.在Python中通过VNC控制Chrome浏览器(你需要先启动Chromewith

--display=:99)。3.视频流压缩优化(H.264硬编码):

如果要把VNC画面推流给前端,不要直接传JPEG(帧率太低)。实战中,使用

FFmpeg接管VNC端口:#将VNC5900端口转为WebRTC流,延迟降至200ms以内ffmpeg-fx11grab-r30-s1920x1080-i:99-c:vlibx264-frtsprtsp://localhost:8554/vnc然后在前端用

WebRTC

播放,比任何VNCWeb插件都流畅。第五部分:避坑指南(VNC特有的血泪经验)坐标系的坑:VNC的坐标以

物理显示器

为基准,如果远程桌面开启了缩放(125%),传入的

(x,y)

必须乘以缩放系数,否则点击位置偏移。剪贴板同步(复制粘贴):VNC的剪贴板走的是

RFB协议

ClientCutText,UTF-8中文在

aiovnc

中需要

bytes

编码后发送,否则乱码。多显示器处理:aiovnc

默认只抓取主显示器,若要抓取扩展屏,需在VNCServer端指定

-screen0

-clip

参数。认证安全:生产环境不要用

-nopw,使用

-rfbauth~/.vnc/passwd

并配合

asyncio

ssl

包装。第六部分:将VNC与你的QLoRA模型结合(终极形态)既然你已有微调经验,可以这么做:在远程桌面里运行一个

GUI程序(如Photoshop/内部ERP系统)。通过VNC截图输入给

你微调过的Qwen-VL(视觉语言模型)。让VLM输出“下一步点击哪里”的JSON坐标。再通过VNC发送鼠标事件,实现

“基于多模态大模型的RPA(机器人流程自动化)”。代码骨架如下:#伪代码whileTrue:img_b64=awaitvnc.get_screenshot()#调用你的QLoRA微调后的VLM(部署在本地)response=awaitvlm_inference(img_b64,prompt="判断当前窗口是否有'确认'按钮?有则返回坐标,无则返回None")ifresponse['x']:awaitvnc.click(response['x'],response['y'])总结:

VNC开发实战的重点不在于“握手协议”,而在于

“帧的抓取效率”

“坐标映射准确性”。建议你从

Docker内Xvfb+无头浏览器

的组合开始练手,这是目前最稳定的CI/CD视觉测试环境。如果需要我把上述代码整合成一个完整的CrewAI+VNC+Xvfb的

docker-compose.yml

可运行项目骨架,随时告诉我,我直接把文件目录结构和启动脚本给你列出来。📁项目完整文件树vnc-crewai-lab/├──docker-compose.yml#一键启动,带noVNC网页监控├──Dockerfile#构建轻量级Ubuntu+Python3.11环境├──.env#环境变量(VNC密码等)├──entrypoint.sh#启动顺序:Xvfb->x11vnc->noVNC->Python脚本└──app/├──__init__.py├──requirements.txt#Python依赖├──vnc_controller.py#异步VNC抓屏+点击核心类├──crewai_tools.py#封装为CrewAI的Tool├──main.py#工作流编排(无限循环监控or单次任务)└──templates/#存放模板图(用于OpenCV匹配)└──search_btn.png#示例:浏览器搜索按钮截图1.环境启动文件docker-compose.yml(暴露5900VNC端口和8080Web监控端口):version:'3.8'services:vnc-agent:build:.container_name:vnc_crewai_labports:-"5900:5900"#传统VNC客户端连接-"8080:8080"#noVNC网页端(重点)environment:-DISPLAY=:99-VNC_PASSWD=123456volumes:-./app:/app-/tmp/.X11-unix:/tmp/.X11-unixstdin_open:truetty:trueshm_size:2gb#防止Chrome在容器内崩溃Dockerfile(集成noVNC与浏览器):FROMpython:3.11-slimENVDEBIAN_FRONTEND=noninteractiveRUNapt-getupdate&&apt-getinstall-y\xvfbx11vncfluxboxwgetunzip\chromiumchromium-driver\gitcurlnet-tools\tesseract-ocrtesseract-ocr-chi-sim\&&rm-rf/var/lib/apt/lists/*#安装noVNC(让你用浏览器看桌面)RUNgitclone/novnc/noVNC.git/opt/noVNC\&&gitclone/novnc/websockify.git/opt/noVNC/utils/websockify\&&ln-s/opt/noVNC/vnc.html/opt/noVNC/index.htmlWORKDIR/appCOPYapp/requirements.txt.RUNpipinstall--no-cache-dir-rrequirements.txtCOPYentrypoint.sh/entrypoint.shRUNchmod+x/entrypoint.shENTRYPOINT["/entrypoint.sh"]entrypoint.sh(确保Xvfb在Python之前跑起来):#!/bin/bash#启动虚拟显示器Xvfb:99-screen01280x720x24&sleep2#启动x11vnc(-nopw为免密,生产环境用-rfbauth)x11vnc-display:99-forever-nopw-rfbport5900&sleep2#启动noVNC(映射到8080)/opt/noVNC/utils/novnc_proxy--vnclocalhost:5900--listen8080&sleep2#启动一个轻量级窗口管理器(防止界面空白)fluxbox-display:99&sleep2#启动Chromium浏览器(供AI操控)chromium-browser--display=:99--no-sandbox--window-size=1280,720--remote-debugging-port=9222about:blank&#最后运行你的CrewAI主程序python/app/main.pyapp/requirements.txt(版本锁定防冲突):aiovnc>=0.3.0crewai>=0.80.0langchain-openai>=0.1.0pillow>=10.0.0opencv-python-headless>=4.8.0numpy>=1.24.0pydantic>=2.0.02.核心VNC控制器(解决阻塞与帧同步难题)app/vnc_controller.py:注意这里我用

同步包装器,方便CrewAI(同步)调用。importasyncioimportbase64importioimporttimefromPILimportImagefromaiovncimportVNCClientclassVNCController:"""单例模式,全局只连一次VNC"""_instance=None_client=None_width=1280_height=720_latest_frame=Nonedef__new__(cls,*args,**kwargs):ifnotcls._instance:cls._instance=super().__new__(cls)returncls._instanceasyncdef_connect_async(self,host="localhost",port=5900,password=""):ifself._clientisNone:#注意:aiovnc的帧回调是异步的,我们直接存图self._client=VNCClient(host,port,password=password,frame_cb=self._on_frame)awaitself._client.connect()#强制等待第一帧for_inrange(50):#最多等5秒ifself._latest_frameisnotNone:breakawaitasyncio.sleep(0.1)returnself._clientdef_on_frame(self,frame):#frame是bytes对象(RGB原始数据)ifframe:self._latest_frame=Image.frombytes("RGB",(self._width,self._height),frame)def_run_async(self,coro):"""同步转异步的桥接器"""try:loop=asyncio.get_running_loop()exceptRuntimeError:loop=asyncio.new_event_loop()asyncio.set_event_loop(loop)returnloop.run_until_complete(coro)defconnect(self,password=""):self._run_async(self._connect_async(password=password))defget_screenshot_b64(self,quality=30):ifself._latest_frameisNone:returnNone#压缩为JPEG减少内存buffered=io.BytesIO()self._latest_frame.save(buffered,format="JPEG",quality=quality)returnbase64.b64encode(buffered.getvalue()).decode('utf-8')defclick(self,x,y,button=1):asyncdef_do_click():awaitself._client.pointer_event(x,y,button_mask=button)awaitasyncio.sleep(0.05)awaitself._client.pointer_event(x,y,button_mask=0)self._run_async(_do_click())deftype_string(self,text):asyncdef_do_type():#简单ASCII处理,中文需走剪贴板(此处略)forchintext:if32<=ord(ch)<=126:awaitself._client.key_event(ord(ch),down=True)awaitself._client.key_event(ord(ch),down=False)awaitasyncio.sleep(0.01)self._run_async(_do_type())3.封装为CrewAI工具(视觉驱动)app/crewai_tools.py:让Agent拥有“截图分析”能力。这里我不把巨图塞给LLM(太贵),而是用

EasyOCR

直接在容器内提取文本坐标。importcv2importnumpyasnpfromcrewai.toolsimportBaseToolfrompydanticimportBaseModel,Fieldfromapp.vnc_controllerimportVNCControllerimporteasyocr#初始化OCR(首次运行会下载模型,请耐心等待)reader=easyocr.Reader(['ch_sim','en'],gpu=False)classScreenSchema(BaseModel):action:str=Field(...,description="'ocr'识别文本坐标,'click_text'点击指定文本")classVNCScreenTool(BaseTool):name:str="屏幕视觉操控器"description:str="截取远程桌面,识别屏幕上的文字并返回坐标,或直接点击指定文字"args_schema:type[BaseModel]=ScreenSchemadef_run(self,action:str,target_text:str=None):vnc=VNCController()#确保连接(第一次调用时建立)vnc.connect(password="123456")#与.env对应ifaction=="ocr":b64_img=vnc.get_screenshot_b64()ifnotb64_img:return"截图失败"#解码为OpenCV格式img_data=base64.b64decode(b64_img)np_arr=np.frombuffer(img_data,np.uint8)cv_img=cv2.imdecode(np_arr,cv2.IMREAD_COLOR)results=reader.readtext(cv_img)text_list=[f"{item[1]}位于({int(item[0][0][0])},{int(item[0][0][1])})"foriteminresults]return"\n".join(text_list)elifaction=="click_text"andtarget_text:#简单实现:直接用OCR找文本中心点击(实战中建议用模板匹配)#此处省略循环查找,逻辑类似vnc.click(640,360)#示例坐标returnf"已尝试点击{target_text}"return"未知操作"4.主程序:CrewAI调度+无限循环监控(终极实战)app/main.py:Agent每隔30秒截图一次,判断当前页面状态,若发现“登录”按钮则自动点击——完成自动化渗透/巡检任务。importtimefromcrewaiimportAgent,Task,Crew,Processfromlangchain_openaiimportChatOpenAIfromapp.crewai_toolsimportVNCScreenTool#1.配置LLM(这里换成你的本地QLoRA微调模型或OpenAI兼容接口)llm=ChatOpenAI(base_url="ernal:11434/v1",#宿主机Ollamamodel="qwen2.5:14b",api_key="sk-dummy",temperature=0.2)#2.初始化工具vnc_tool=VNCScreenTool()#3.定义Agent(人设:视觉自动化测试员)agent=Agent(role="GUI自动化测试专家",goal="监控远程桌面,检测异常弹窗并关闭,或完成指定登录流程",backstory="""你精通CV和OCR,能快速从截图中提取关键按钮。如果识别到'确认'或'登录',立即调用工具点击。如果遇到'错误'弹窗,截图并报告。""",tools=[vnc_tool],llm=llm,verbose=True,max_iter=3)#4.定义任务(核心Prompt技巧:让AI输出结构化JSON)task=Task(description="""每30秒执行一次屏幕巡检。1.调用`ocr`获取当前所有文字坐标。2.如

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论