QiWe开放平台 · 个人名片
API驱动企微自动化,让开发更高效
核心能力:为开发者提供标准化接口、快速集成工具,助力产品高效拓展功能场景
团队定位:专注企微API生态的技术服务团队
对接通道:搜「QiWe 开放平台」联系客服
核心理念:合规赋能,让企微开发更简单、更高效
本文聚焦 Python 语言,极简拆解 RPA 模式下企微第三方 API 外部群主动调用的完整实现流程,从环境搭建、核心代码编写到测试落地,全程实操导向,无冗余理论,适配 Python 技术栈团队快速落地,覆盖文本推送、群聊查询核心场景。
一、前置准备(3 步完成,极简配置)
1. 环境准备
-
服务器:Windows Server 2019/2022(需开启桌面交互、安装基础显卡驱动);
-
软件:企微官方稳定版(关闭自动更新 / 弹窗)、Python 3.9+;
-
核心依赖(终端直接安装):
pip install requests pyautogui pywinauto redis pymysql
2. 基础配置
- 企微:登录专用运营账号,固定窗口位置(建议最大化),锁定群聊列表布局;
- 中间件:部署 Redis(缓存 token、群聊定位参数)、MySQL(存储操作日志),开启本地访问,配置简单密码;
- 权限:服务器创建专用运行账号,赋予程序 / 日志 / 数据盘读写权限,关闭无关权限。
3. 核心前置(规避踩坑)
- 提前获取企微群聊名称(用于定位)、企业 ID + 应用密钥(用于鉴权);
- 禁用企微自动升级、消息弹窗、文件预览,避免干扰 RPA 操作;
- 测试 Python 环境能否正常调用企微客户端(通过 pywinauto 获取窗口句柄验证)。
二、核心代码实现(分模块编写,可直接复用)
整体分为 4 个核心模块,代码极简,注释清晰,可直接复制修改配置后使用,聚焦外部群主动调用核心能力。
1. 基础工具模块(鉴权 + 缓存 + 日志,全局复用)
python
import redis
import pymysql
import requests
import time
# 1. Redis缓存初始化(用于缓存token、群聊定位参数)
redis_client = redis.Redis(host='localhost', port=6379, db=0, password='your_redis_pwd')
# 2. MySQL初始化(用于存储操作日志)
mysql_conn = pymysql.connect(
host='localhost', user='root', password='your_mysql_pwd', db='qw_rpa_api', charset='utf8'
)
cursor = mysql_conn.cursor()
# 3. 鉴权获取access_token(缓存7200s,自动刷新)
def get_access_token():
cache_key = "qw_rpa:access_token"
token = redis_client.get(cache_key)
if token:
return token.decode()
# 调用鉴权接口(复用之前封装的鉴权逻辑)
res = requests.post(
"http://localhost:8080/auth",
json={"corp_id": "your_corp_id", "app_secret": "your_app_secret"}
)
token = res.json()["data"]["access_token"]
redis_client.setex(cache_key, 7200, token)
return token
# 4. 日志记录(简化版,仅记录核心信息)
def record_log(task_id, chat_id, operate_type, result):
sql = """INSERT INTO operate_log (task_id, chat_id, operate_type, result, operate_time)
VALUES (%s, %s, %s, %s, %s)"""
cursor.execute(sql, (task_id, chat_id, operate_type, result, time.strftime("%Y-%m-%d %H:%M:%S")))
mysql_conn.commit()
2. RPA 定位与操作模块(核心,实现群聊定位 + 消息推送)
python
from pywinauto import Application
import pyautogui
# 1. 连接企微客户端(获取窗口句柄)
def connect_qw():
try:
# 通过企微进程名连接(无需坐标,更稳定)
app = Application(backend='uia').connect(process=12345) # 替换为你的企微进程ID
qw_window = app.window(title_re="企业微信") # 匹配企微窗口标题
qw_window.set_focus() # 激活企微窗口
return qw_window
except Exception as e:
print(f"企微连接失败:{str(e)}")
return None
# 2. 群聊定位(文本匹配+控件辅助,适配群聊列表)
def locate_group_chat(qw_window, chat_name):
cache_key = f"qw_rpa:group:{chat_name}"
# 先查缓存,避免重复定位
if redis_client.exists(cache_key):
return True
try:
# 定位群聊列表,点击搜索框
search_box = qw_window.child_window(title="搜索", control_type="Edit").click_input()
pyautogui.typewrite(chat_name, interval=0.05) # 输入群聊名称(模拟人工输入)
time.sleep(1) # 等待搜索结果
# 定位目标群聊并点击进入
group_chat = qw_window.child_window(title=chat_name, control_type="ListItem").click_input()
time.sleep(0.5)
# 缓存定位结果(有效期7天)
redis_client.setex(cache_key, 604800, "success")
return True
except Exception as e:
print(f"群聊定位失败:{str(e)}")
return False
# 3. 文本消息推送(核心操作,标准化执行)
def push_text_message(chat_name, content):
task_id = f"task_{int(time.time())}" # 生成唯一任务ID(幂等性控制)
qw_window = connect_qw()
if not qw_window:
record_log(task_id, chat_name, "push_text", "企微未连接")
return {"code": 500, "msg": "企微未连接", "task_id": task_id}
# 定位群聊
if not locate_group_chat(qw_window, chat_name):
record_log(task_id, chat_name, "push_text", "群聊定位失败")
return {"code": 500, "msg": "群聊定位失败", "task_id": task_id}
try:
# 定位输入框,输入消息
input_box = qw_window.child_window(title="输入框", control_type="Edit").click_input()
pyautogui.typewrite(content, interval=0.05)
time.sleep(0.2)
# 点击发送按钮
qw_window.child_window(title="发送", control_type="Button").click_input()
time.sleep(0.5)
# 记录成功日志
record_log(task_id, chat_name, "push_text", "success")
return {"code": 200, "msg": "推送成功", "task_id": task_id}
except Exception as e:
record_log(task_id, chat_name, "push_text", f"失败:{str(e)}")
return {"code": 500, "msg": f"推送失败:{str(e)}", "task_id": task_id}
3. 群聊查询模块(获取企业外部群列表,简化版)
python
def get_external_group_list():
"""获取企业名下有效外部群列表(RPA模拟查询,简化版)"""
qw_window = connect_qw()
if not qw_window:
return {"code": 500, "msg": "企微未连接", "data": []}
try:
# 定位外部群入口并点击
qw_window.child_window(title="外部群", control_type="ListItem").click_input()
time.sleep(1)
# 遍历群聊列表,获取有效群聊名称(简化版,仅获取可见群聊)
group_list = []
group_items = qw_window.child_window(control_type="List").children()
for item in group_items:
group_name = item.window_text()
if group_name and "已解散" not in group_name: # 剔除已解散群聊
group_list.append(group_name)
return {"code": 200, "msg": "查询成功", "data": group_list[:20]} # 限制返回数量,避免过多
except Exception as e:
return {"code": 500, "msg": f"查询失败:{str(e)}", "data": []}
4. API 封装模块(FastAPI,提供标准化调用入口)
python
from fastapi import FastAPI
app = FastAPI(title="Python+RPA 企微第三方API", version="1.0")
# 1. 消息推送接口(外部调用核心接口)
@app.post("/group/push/text")
def group_push_text(chat_name: str, content: str):
return push_text_message(chat_name, content)
# 2. 群聊查询接口
@app.get("/group/list")
def group_list():
return get_external_group_list()
# 3. 日志查询接口(简化版)
@app.get("/log/query")
def log_query(task_id: str):
sql = "SELECT * FROM operate_log WHERE task_id = %s"
cursor.execute(sql, (task_id,))
log = cursor.fetchone()
return {"code": 200, "data": log if log else None}
# 启动服务(终端执行该脚本即可)
if __name__ == "__main__":
import uvicorn
uvicorn.run(app="__main__:app", host="0.0.0.0", port=8080, reload=False)
三、测试落地(3 步验证,快速上线)
1. 本地测试
- 启动 Redis、MySQL,创建对应的数据库和日志表;
- 运行 API 脚本,启动 FastAPI 服务;
- 用 Apifox 调用
/group/push/text接口,传入群聊名称和文本内容,验证推送是否成功。
2. 核心优化(规避踩坑,提升稳定性)
- 操作速率:所有输入 / 点击添加延时(输入 0.05s / 字符、点击≥200ms),模拟人工;
- 异常兜底:添加企微掉线、定位失败重试逻辑(最多 2 次),失败则记录日志并提醒;
- 缓存优化:群聊定位参数缓存 7 天,token 缓存 7200s,减少重复操作,提升效率。
3. 生产部署
- 用 PyInstaller 将脚本打包为可执行文件,上传至服务器;
- 设置开机自启,配置防火墙开放 8080 端口;
- 启动服务后,调用接口做最终验证,确认功能正常、日志完整。
四、核心总结
Python+RPA 开发企微第三方 API,核心优势是轻量、易上手、成本低,无需复杂协议开发,依托 Python 丰富的 RPA 生态(pyautogui、pywinauto),可快速实现外部群主动调用。
本文实现的核心能力的是文本推送、群聊查询,可基于此扩展图片 / 文件推送、群成员管理等功能,代码模块化设计,复用性强。落地关键是控制操作速率、做好缓存与异常兜底,规避企微风控,确保长期稳定运行,完全适配中小团队 Python 技术栈的落地需求。