RPA自动化进阶我开发了一套店群管理系统彻底解决100店铺并发卡死痛点写在最前面禁止评论区说“这不就是套壳浏览器”。我玻璃心看到恶评就把并发bug写进下一版大家一起卡。本文不定点掉落架构师专属翻车现场点进来的算是捡着了。 3. 店群干久了你会发现最大的敌人不是平台风控而是自己写的代码。去年冬天一个做TikTok店群的老哥请我吃饭。席间他叹气三台电脑两个全职运营每天从早到晚切环境、对订单、上商品。月底一算账利润刚够发工资。买了影刀脚本十几个店铺同时跑就卡成PPT。换了指纹浏览器环境隔离倒是好了但并发一高电脑直接蓝屏。他说林焱你不是写代码的吗能不能搞一套东西让我点一下按钮几十个店铺自己跑我当时喝了口酒说行。然后我就开始了长达半年的“造轮子”之旅。这套系统后来跑在一台64G内存的工作站上同时开着22个浏览器窗口调度着150多个店铺连续运行三个月没重启。客户从“手动切号切到手抽筋”变成了“每天打开看眼报表就关掉”。这篇文章就是这套系统的完整复盘。一、店群“体力活”到底有多苦先还原一个真实的工作室日常上午9点运营到岗。打开电脑登录指纹浏览器平台挨个点开店铺A记录昨日订单。关闭。再点开店铺B记录订单。关闭。一共80个店铺每个操作2分钟光对账就要接近3小时。下午2点开始批量上架商品。先登录店铺A上传图片、填标题、设价格发布。切换到店铺B同样的操作。好不容易上完一半突然收到风控告警——店铺C和店铺D因为环境关联被封了。运营崩溃老板更崩溃。招人贵、管人难、效率低、风险高。通用RPA脚本影刀社区版单窗口跑没问题一开并发就卡死因为脚本根本没有资源调度概念。指纹浏览器环境隔离做得好但按店铺数收费一百个店一个月好几千而且不支持批量流程编排。我当时的判断是必须从底层造一套自己的系统。不用低代码拼凑不用现成的指纹浏览器服务。用Python做内核PyQt6做界面影刀RPA做执行终端。三位一体彻底解决问题。二、核心模块A环境隔离矩阵——每个店铺都是独立“人格”2.1 软件界面长什么样Alien系统的“环境管理中心”界面分成左右两区。左侧是一棵分组树按平台TikTok/拼多多/TEMU展开下面按品类或地区自定义分组。TEMU店群矩阵自动化运营核价报活动右侧是一个数据表格每一行是一个店铺环境列包括店铺ID代理IP带状态灯地理位置经纬度最后活跃时间健康分绿/黄/红操作按钮手动打开、编辑、删除顶部有四个大按钮批量导入、分组管理、导出报表、手动打开选中环境。批量导入支持CSV模板一列店铺ID一列代理IP其他自动生成。运营只需要填这两列一键生成上百个环境。“手动打开选中环境”是运营最爱用的功能。选中一行点一下按钮弹出一个完全隔离的Chrome窗口代理和指纹已经配好。她们可以直接登录后台处理异常订单不用再记任何配置。2.2 技术实现每个店铺一个独立Profile核心思想Chromium的--user-data-dir参数可以指定用户数据目录。只要给每个店铺分配不同的目录Cookies、LocalStorage、缓存就完全隔离。但仅靠目录隔离还不够。还要注入不同的代理、屏幕分辨率、时区、语言、WebGL参数。我写了一个EnvironmentManager类负责为每个店铺创建和管理独立的“环境包”。importosimportjsonimportshutilfrompathlibimportPathfromtypingimportOptionalimporthashlibimportrandomclassEnvironmentManager:DATA_ROOTPath(./AlienEnv)def__init__(self,shop_id:str):self.shop_idshop_id self.env_dirself.DATA_ROOT/shop_id self.profile_dirself.env_dir/browser_profileself.config_fileself.env_dir/env.jsondefcreate(self,proxy:str,group:strdefault)-str:创建新环境返回profile目录路径self.env_dir.mkdir(parentsTrue,exist_okTrue)self.profile_dir.mkdir(exist_okTrue)# 生成一份固定的指纹基于shop_id哈希保证每次相同fingerprintself._generate_fingerprint(proxy,group)withopen(self.config_file,w)asf:json.dump(fingerprint,f,indent2)# 预创建缓存目录(self.profile_dir/Cache).mkdir(exist_okTrue)(self.profile_dir/Local Storage).mkdir(exist_okTrue)returnstr(self.profile_dir)def_generate_fingerprint(self,proxy:str,group:str)-dict:基于shop_id稳定生成指纹不同店铺差异足够大seedhashlib.md5(self.shop_id.encode()).hexdigest()rngrandom.Random(int(seed[:8],16))resolutions[(1920,1080),(1366,768),(1440,900),(1536,864)]timezones[America/New_York,Europe/London,Asia/Tokyo,Australia/Sydney]languages[en-US,en-GB,fr-FR,de-DE]return{proxy:proxy,group:group,screen_width:rng.choice(resolutions)[0],screen_height:rng.choice(resolutions)[1],timezone:rng.choice(timezones),language:rng.choice(languages),platform:rng.choice([Win32,MacIntel]),webgl_vendor:rng.choice([Google Inc.,Intel Inc.,NVIDIA Corporation])}defload(self)-Optional[dict]:ifnotself.config_file.exists():returnNonewithopen(self.config_file,r)asf:returnjson.load(f)defdelete(self):ifself.env_dir.exists():shutil.rmtree(self.env_dir) 关键点指纹生成使用 shop_id 作为随机种子保证同一个店铺每次生成的指纹一致不会因为指纹变化触发登录验证不同店铺之间又天然不同。 启动浏览器时读取 env.json根据里面的配置组装Chrome启动参数。 pythondeflaunch_browser(shop_id:str):env_mgrEnvironmentManager(shop_id)configenv_mgr.load()profile_direnv_mgr.profile_dir cmd[chrome.exe,f--user-data-dir{profile_dir},f--proxy-server{config[proxy]},f--window-size{config[screen_width]},{config[screen_height]},f--lang{config[language]},--disable-blink-featuresAutomationControlled,--remote-debugging-port0# 随机端口]# 启动进程并返回调试端口... 这样每个店铺就拥有了完全独立的“人格”。---## 三、核心模块B自动化流程调度编排环境隔离做好了下一步是让任务跑起来。 店群老板需要的不是单个脚本而是一套可以灵活组合、批量执行的**流程系统**。### 3.1 拖拽式流程编排Alien的“自动化编排流”界面左侧是动作库-登录店铺--浏览商品页--加购--领优惠券--上架商品传商品数据--同步订单--发送客服消息--等待秒--条件判断 右侧是画布运营可以把动作拖到画布上用箭头连接。 比如一个“TikTok日常养号”流程开始 → 打开店铺 → 登录 → 浏览推荐页30秒 → 随机点赞2个视频 → 随机关注1个账号 → 关闭 → 结束 一个“拼多多批量上架”流程开始 → 登录 → 进入商品管理 → 点击新增商品 → 填标题(从csv读取) → 传图片 → 设价格库存 → 发布 → 记录结果 → 结束 这些流程定义保存在JSON文件中可以随时修改、复制、分配给不同店铺。 ### 3.2 并发调度22个窗口不卡不崩 最核心的挑战如何在一台机器上同时运行几十个店铺的任务而不让系统崩溃 我们测试过同时开22个Chrome窗口CPU占用70%内存占用45%还算稳定。开到25个开始卡顿30个以上部分窗口直接白屏。 所以最大并发窗口数设定为22。 调度器需要解决三个问题 1. 控制同时运行的浏览器实例数量不超过22 2. 2. 每个店铺同一时间只能执行一个任务避免冲突 3. 3. 任务结束后及时释放资源并复用窗口 下面是一段简化但真实可跑的调度核心代码 python import threading import queue import time from concurrent.futures import ThreadPoolExecutor class AlienScheduler: def __init__(self, max_concurrent22): self.max_concurrent max_concurrent self.task_queue queue.Queue() self.active_slots 0 self.slot_lock threading.Lock() self.shop_running {} # shop_id - bool self.shop_lock threading.Lock() self.executor ThreadPoolExecutor(max_workersmax_concurrent) def submit(self, task): task: {shop_id, flow_file, params} self.task_queue.put(task) def _worker(self): while True: task self.task_queue.get() shop_id task[shop_id] # 等待该店铺没有正在运行的任务 while True: with self.shop_lock: if not self.shop_running.get(shop_id, False): self.shop_running[shop_id] True break time.sleep(0.5) # 等待有空闲槽位 while True: with self.slot_lock: if self.active_slots self.max_concurrent: self.active_slots 1 break time.sleep(0.5) # 提交到线程池执行 self.executor.submit(self._run_task, task, shop_id) def _run_task(self, task, shop_id): try: # 调用影刀RPA执行流程 self._call_yingdao(task[flow_file], shop_id, task.get(params, {})) finally: with self.slot_lock: self.active_slots - 1 with self.shop_lock: self.shop_running[shop_id] False self.task_queue.task_done() def _call_yingdao(self, flow_file, shop_id, params): # 获取该店铺当前浏览器调试端口如果没启动则先启动 debug_port get_or_launch_browser(shop_id) cmd f影刀RPA.exe -run {flow_file} -param shop_id{shop_id}port{debug_port}params{json.dumps(params)} subprocess.run(cmd, shellTrue, timeout600) def start(self): # 启动多个工作线程 for _ in range(self.max_concurrent): threading.Thread(targetself._worker, daemonTrue).start() 这个调度器保证了 - 并发窗口不超过22 - - 同一店铺的任务串行执行 - - 失败任务不会阻塞队列 踩坑第一次上线后跑了半天发现内存占用从4G涨到了12G。排查发现ThreadPoolExecutor 默认不会自动回收空闲线程而且每个任务结束后浏览器实例没关闭。后来加了空闲超时回收机制浏览器30分钟无任务自动关闭并清理临时文件。 ### 3.3 智能平铺 22个窗口同时打开如果不做排列会全部堆叠在一起影刀脚本点击时容易点错。 Alien的调度器在启动每个浏览器时会根据当前已打开的窗口数量自动计算下一个窗口的坐标。 代码很简单 python grid_cols 5 grid_rows (max_concurrent grid_cols - 1) // grid_cols col window_index % grid_cols row window_index // grid_cols x col * 400 y row * 300 然后把Chrome窗口移动到 (x, y) 位置。运营看着整整齐齐的窗口矩阵直呼舒服。 --- ## 四、底层工程封装让客户觉得“这软件真专业” ### 4.1 抛弃黑框框PyQt6开发精美UI 之前的原型是命令行版本输入指令、看日志。老板说你给我看这个我找小学生也能写。 于是我花了三周用PyQt6重写了整个界面。 主要界面包括 - **仪表盘**实时显示并发窗口数、任务成功率、CPU/内存占用曲线用pyqtgraph画 - - **环境管理**表格树形分组支持批量导入、导出、删除 - - **流程编排**拖拽式画布基于QGraphicsView实现 - - **调度日志**实时滚动的彩色日志支持按店铺ID过滤 暗黑主题圆角卡片微动效客户第一次打开时说这软件得卖一万吧 ### 4.2 双击即用PyInstaller打包成一键exe 客户不愿意装Python环境也不会配ChromeDriver。 我使用PyInstaller把所有依赖打包成一个Alien.exe - Python解释器 - - PyQt6库 - - 所有第三方依赖 - - 一个便携版Chromium约110MB - - 影刀RPA的免安装运行环境 第一次启动时程序会在%APPDATA%\Alien下创建数据目录解压Chromium生成默认配置。 整个安装过程就是下载压缩包 → 解压 → 双击Alien.exe。 不需要任何手动配置。 ### 4.3 安全验证一机一码 为了防止破解我实现了一套简单的授权机制 - 收集机器信息硬盘序列号、MAC地址、主板ID - - 组合后用SHA256生成机器码 - - 客户把机器码发给我我用RSA私钥签名生成license文件 - - 软件启动时验证签名和机器码是否匹配 虽然不能完全防破解但已经足够挡住99%的“复制粘贴即用”行为。 --- ## 五、那些让我失眠的坑 **坑1内存泄漏排查了两周** 当时线上环境跑了几十个号内存从启动时的3GB慢慢涨到15GB然后系统卡死。 查了很久发现是浏览器实例关闭后user-data-dir里的Cache和Code Cache没有清理。日积月累每个店铺的文件夹都到了2GB以上。 解决方法每天凌晨3点对所有空闲超过24小时的店铺删除其缓存目录保留Cookies和LocalStorage。 **坑2影刀超时导致进程残留** 影刀流程有时会卡住超过600秒后我们强制终止进程但Chrome没有被关闭。几天后系统里有上百个chrome.exe僵尸。 解决方案在调度器的任务包装函数里用try/finally确保无论如何都调用浏览器关闭接口。 **坑3拼多多滑块验证** 影刀自带的滑块成功率只有30%。后来接入了超级鹰打码平台截图发送、返回坐标、模拟拖动。成功率提升到80%。剩下的20%触发二次验证我们就把店铺标记为“需人工介入”推送飞书通知运营手动处理。 --- ## 写在最后 一个人从零写一套店群自动化系统听起来很疯狂。 但把问题拆解后每一步都有清晰的路径 - 环境隔离 → Chromium的--user-data-dir - - 指纹伪装 → 启动参数 代理 固定种子随机 - - 任务调度 → 有界队列 店铺级互斥锁 - - 界面封装 → PyQt6 暗黑主题 - - 交付打包 → PyInstaller 便携浏览器 这套系统目前跑着150多个店铺稳定运行了大半年。 客户从“每天切号切到想转行”变成了“每天看一眼报表然后去打麻将”。 技术不能解决所有问题但至少能让重复劳动消失。 如果这篇文章能帮你少踩几个坑或者给你一些架构灵感那就值了。 作者林焱 独立开发者RPA架构师 博客林焱RPA专栏全网同名 原创不易转载需授权 全文约4600字 [video(video-HKFjSmLC-1779866107487)(type-csdn)(url-https://live.csdn.net/v/embed/526818)(image-https://v-blog.csdnimg.cn/asset/582d14c3bd0451c5399cd990b56e2a0d/cover/Cover0.jpg)(title-拼多多店群自动化报活动上架)]