RPA自动化进阶自研Alien店群管理系统把200店铺的每日切号5小时变成了0写在最前面禁止评论“这不就是个浏览器农场”。你搭一个不卡死的试试。本文所有坑都是用店铺封号换来的建议逐字阅读。店群老板可以直接拖到最后看“降本增效数据”技术同行建议从头啃。拼多多店群自动化上架方案2022年冬天我蹲在工作室角落啃冷掉的煎饼果子。对面三个运营每人面前两台显示器桌面上贴满了便利贴。她们每天的工作就是登录店铺A、对订单、截图、退出、清缓存、换代理、登录店铺B……循环往复。一个运营一天最多处理60个店铺。200个店铺需要三个人全职还经常因为切错环境被封店。我问老板为什么不搞自动化老板说买了影刀脚本跑十几个号就卡死买了指纹浏览器按环境收费一个月好几千找人定制报价六万八还不保证稳定。他嚼着槟榔问我林焱你不是写代码的吗能不能搞一套我当时煎饼果子咽到一半差点噎死。但我说行。然后我就开始了长达一年的“造轮子”工程。这套系统后来叫Alien。纯Python底层 PyQt6界面 影刀RPA执行。上线后200个店铺的每日切号从5小时压缩到0。运营从三个减到零老板每年省下二十多万工资。今天我把这套系统的核心模块完整拆开。一、店群自动化的谎言与真相市面上的店群自动化90%都在卖一个概念录个脚本循环跑。这个概念的致命缺陷是——它假设所有店铺可以共用一套浏览器环境。实际上平台风控会采集几十个维度的特征Canvas指纹、WebGL、字体列表、时区、语言、屏幕分辨率……两个店铺只要有一半特征相同就有可能被关联。你录了一个“登录-查订单”的脚本套用到200个店铺上。第一个店铺正常登录第二个店铺因为缓存没清干净直接登上了第一个店铺的后台。然后脚本开始对第一个店铺的订单进行批量发货发到了第二个店铺的买家手里。这种事我亲眼见过。所以真正的店群自动化必须解决两个核心问题1. 环境隔离每个店铺拥有完全独立、彼此无关联的“数字身份”。2. 并发调度在不卡死机器的前提下让任务批量、高效地跑起来。下面我分别讲Alien是怎么做的。二、环境隔离矩阵每个店铺都是一台独立“虚拟机”2.1 界面设计让运营告别便利贴TEMU店群如何管理运营Alien的“环境管理中心”长得像Excel和文件管理器的结合体。左侧是分组树。你可以按平台建一级分组拼多多/TEMU/TikTok下面再建二级分组女装/3C/家居。右键分组可以批量分配代理、批量执行流程。右侧是卡片式表格。每一行是一个店铺环境显示店铺ID可改别名代理IP带国家旗子和在线检测健康度基于最近24小时失败率绿/黄/红最后活跃时间操作按钮打开环境、编辑、运行任务、删除顶部四个大按钮导入CSV、新建分组、批量打开选中、导出报表。“导入CSV”是运营最爱。模板只有三列shop_id, platform, proxy。填好点击导入系统自动为每个店铺生成独立Profile和指纹。以前200个店铺要配置一整天现在一分钟。“批量打开选中”更是救命功能。选中十个店铺点一下系统依次弹出十个Chrome窗口每个窗口已经配好对应的代理和登录态。运营可以直接进去手动处理异常订单不用记任何密码。2.2 技术实现user-data-dir 指纹定制隔离的核心是Chromium的--user-data-dir。每个店铺启动时指定一个独立目录。这个目录里装着Cookies、LocalStorage、缓存、插件状态。只要目录不共用店铺之间就不会串数据。但光有目录不够。平台还会采集你的屏幕大小、时区、语言、WebGL厂商。所以Alien给每个店铺生成一套固定的、但彼此不同的指纹。固定是为了避免频繁变化触发风控不同是为了防止平台把你所有店铺关联起来。下面是我的环境管理核心类真实代码脱敏版importhashlibimportrandomimportjsonfrompathlibimportPathclassAlienEnvironment:DATA_ROOTPath(./AlienData)def__init__(self,shop_id:str,platform:str):self.shop_idshop_id self.platformplatform self.env_pathself.DATA_ROOT/platform/shop_id self.profile_pathself.env_path/profileself.fp_pathself.env_path/fingerprint.jsondefcreate(self,proxy:str,group:str)-str:self.env_path.mkdir(parentsTrue,exist_okTrue)self.profile_path.mkdir(exist_okTrue)fpself._generate_fingerprint(proxy,group)withopen(self.fp_path,w)asf:json.dump(fp,f,indent2)# 预建子目录避免首次启动报错(self.profile_path/Cache).mkdir(exist_okTrue)(self.profile_path/Local Storage).mkdir(exist_okTrue)returnstr(self.profile_path)def_generate_fingerprint(self,proxy:str,group:str)-dict:# 用shop_id做种子保证稳定性 差异化seed_strf{self.platform}:{self.shop_id}:{group}seedint(hashlib.md5(seed_str.encode()).hexdigest()[:8],16)rngrandom.Random(seed)resolutions[(1920,1080),(1366,768),(1440,900),(1536,864)]tz_map{pdd:[Asia/Shanghai],temu:[America/New_York,America/Los_Angeles],tiktok:[America/New_York,Europe/London]}lang_map{pdd:[zh-CN],temu:[en-US,en-GB],tiktok:[en-US,en-GB]}return{proxy:proxy,group:group,screen_width:rng.choice(resolutions)[0],screen_height:rng.choice(resolutions)[1],timezone:rng.choice(tz_map.get(self.platform,[UTC])),language:rng.choice(lang_map.get(self.platform,[en-US])),platform_os:rng.choice([Win32,MacIntel]),webgl_vendor:rng.choice([Google Inc.,Intel Inc.]),cpu_cores:rng.choice([2,4,8])}defload_fingerprint(self):withopen(self.fp_path)asf:returnjson.load(f) 启动浏览器时读取指纹拼装命令行并打开远程调试端口供影刀连接。 pythondeflaunch_browser(env:AlienEnvironment):fpenv.load_fingerprint()cmd[chrome.exe,f--user-data-dir{env.profile_path},f--proxy-server{fp[proxy]},f--window-size{fp[screen_width]},{fp[screen_height]},f--lang{fp[language]},--remote-debugging-port0,--disable-blink-featuresAutomationControlled]procsubprocess.Popen(cmd,...)# 从输出中解析调试端口... 这套方案跑了一年多200个店铺从没因为环境关联被封过。---## 三、自动化调度编排22个窗口并发不卡不崩环境建好了下一步是让任务批量跑起来。 Alien的调度器要同时满足四个条件-最多22个浏览器窗口并发实测极限--同一个店铺同一时间只能跑一个任务--不同店铺的任务可以任意并发--任务结束后浏览器复用空闲太久才回收 下面这段代码是调度器的骨架我用信号量控制并发数用字典维护店铺锁 pythonimportthreadingimportqueueimporttimeclassAlienScheduler:def__init__(self,max_concurrent22):self.max_concurrentmax_concurrent self.semaphorethreading.Semaphore(max_concurrent)self.task_queuequeue.Queue()self.shop_locks{}self.lockthreading.Lock()def_get_shop_lock(self,shop_id):withself.lock:ifshop_idnotinself.shop_locks:self.shop_locks[shop_id]threading.Lock()returnself.shop_locks[shop_id]defadd_task(self,shop_id,flow_file,paramsNone):self.task_queue.put((shop_id,flow_file,params))def_worker(self):whileTrue:shop_id,flow_file,paramsself.task_queue.get()shop_lockself._get_shop_lock(shop_id)tthreading.Thread(targetself._run,args(shop_id,flow_file,params,shop_lock))t.start()def_run(self,shop_id,flow_file,params,shop_lock):# 先拿店铺锁保证串行再拿信号量限流withshop_lock:self.semaphore.acquire()try:self._execute(shop_id,flow_file,params)finally:self.semaphore.release()self.task_queue.task_done()def_execute(self,shop_id,flow_file,params):debug_portself._ensure_browser(shop_id)self._call_yingdao(flow_file,shop_id,debug_port,params)def_ensure_browser(self,shop_id):# 检查本地是否有运行中的实例没有则启动passdef_call_yingdao(self,flow_file,shop_id,port,params):importsubprocess,json cmd[影刀RPA.exe,-run,flow_file,-param,fshop_id{shop_id},-param,fdebug_port{port},-param,fparams{json.dumps(params)}]subprocess.run(cmd,timeout600,checkTrue)defstart(self,worker_count22):for_inrange(worker_count):threading.Thread(targetself._worker,daemonTrue).start() 这个调度器上线后22个窗口从早到晚满负荷运行CPU稳定70%内存稳定45%连续跑了三个月没重启过。**智能平铺**每次启动浏览器调度器通过Windows API计算窗口位置自动排列成网格。运营不用在任务栏里大海捞针。**资源回收线程**独立的后台线程每5分钟扫描一次空闲超过30分钟的浏览器自动关闭并删除Cache目录。磁盘占用始终控制在20GB以内。**拖拽式流程编排**我基于PyQt的QGraphicsView写了一个可视化编辑器。左侧是动作库登录、上架、领券、发货右侧是画布。运营把动作拖到画布上用箭头连线就是一个自动化流程。保存后可以分配给单个店铺或整个分组。这个功能让不懂代码的运营也能自己配置业务流程。---## 四、从黑框到商业软件PyQt6 打包 授权如果我把上面这些代码以Python脚本的形式发给客户他们会疯掉。 所以我做了三件事### 4.1 PyQt6 专业界面我花了一个月学PyQt6然后写了完整的GUI。-**仪表盘**用pyqtgraph画实时曲线显示并发数、任务吞吐量、内存占用。--**环境管理**QTreeView分组树QTableView表格支持拖拽分组、右键菜单、批量操作。--**流程编排**基于QGraphicsScene的画布节点可拖拽、连线可编辑。--**日志面板**彩色输出支持按店铺ID筛选。 深色主题圆角卡片按钮有悬停特效。客户第一次打开时说“这软件看着就值钱。”### 4.2 PyInstaller 打包成单exe客户不需要装Python、Chrome、影刀客户端。 我用PyInstaller把所有东西打成一个Alien.exe包含Python解释器、所有依赖库、一个便携版Chromium约120MB。首次启动时解压到%APPDATA%\Alien。 客户只需要下载 → 解压 → 双击exe → 等待10秒 → 看到界面。### 4.3 一机一码安全验证为了防止破解我做了硬件绑定授权。 程序启动时读取硬盘序列号和MAC地址生成机器码。用户把机器码发给我我用RSA私钥签名生成license文件。每次启动验证签名和硬件是否匹配。 虽然不能100%防破解但已经挡住了99%的“复制粘贴即用”。---## 五、那些让我深夜爬起来的真实踩坑**坑1内存泄漏排查了一周。**第一次部署后跑了48小时内存从2GB涨到11GB然后系统卡死。我用tracemalloc逐行定位发现是影刀调用时subprocess.Popen的stdout管道没有被及时读取缓冲区积压。加上stdoutsubprocess.DEVNULL后解决。**坑2同一店铺两个任务同时写同一个文件。**有一个任务会把订单数据导出到orders_{shop_id}.csv。两个任务并行执行时会互相覆盖导致数据不完整。解决方案每个任务生成带时间戳的临时文件orders_{shop_id}_{timestamp}.tmp执行完后再合并到主文件。**坑3代理IP在任务中途失效。**有些廉价代理不稳定跑着跑着就断了。影刀脚本会卡在“加载中”页面直到超时。我在_execute里加了页面加载超时检测30秒超时后重启浏览器并换一个代理然后重试任务。**坑4Windows更新半夜重启。**有一次Windows自动更新半夜重启了机器所有正在执行的任务中断部分店铺的登录态丢失。后来我把调度器改成了“断点续传”模式每个任务开始前在SQLite里记录状态重启后自动恢复未完成的任务。**坑5运营一次全选删除差点把环境全删光。**有一次运营在环境管理界面全选了所有店铺然后点了“删除”。一瞬间100多个环境配置全部消失。我恢复了半天的备份损失了当天的任务记录。从此之后删除操作先移到“回收站”7天后才真正物理删除。同时加了二次确认弹窗。---## 六、降本增效数据老板最关心的Alien上线后我做了前后对比-**人力成本**从3个全职运营 →0个每年省下约24万工资。--**切号时间**每天5小时 →0运营老板自己只需每天花20分钟看报表。--**封店率**每月平均5-8个因环境关联被封 →0个连续10个月无关联封店。--**任务效率**批量上架100个店铺从原来需要一整天 →22个窗口并发跑约1.5小时。 老板后来请我吃了顿饭点了一桌子菜说林焱你这套软件比我前女友还靠谱。 我笑了笑没告诉他——写这套软件我掉了多少头发。---## 写在最后从一个人写Alien到现在已经一年半。 它从几十行脚本变成了上万行代码的完整系统。 有人问我你为什么不直接用现成的指纹浏览器加影刀 我的回答是**自己造轮子不是为了证明自己多厉害而是为了在每一个细节上拥有控制权。**代理池要换改代码。并发数要调整改配置。平台更新了风控策略加一层指纹伪装。 所有事情都在自己手里不用等第三方更新不用看供应商脸色。 如果你也在做店群自动化希望这篇文章能帮你省下几百个小时的踩坑时间。 技术不复杂复杂的是对细节的死磕。作者林焱独立开发者店群自动化架构师博客林焱RPA全网同名转载需授权不接受免费咨询 全文约4600字