不止是@所有人:用Python玩转企业微信机器人的Markdown、图文和文件消息
不止是@所有人:用Python玩转企业微信机器人的Markdown、图文和文件消息
企业微信机器人早已超越了简单的文本通知时代。想象一下:凌晨三点服务器崩溃时,自动推送带高亮错误日志的Markdown报告;每日晨会前,系统准时发送整合了KPI图表和数据分析的图文简报;项目结项时,一键生成PDF文档并分发给所有相关成员——这些场景正在通过Python与企业微信机器人的深度结合变为现实。
对于已经掌握基础文本消息推送的开发者而言,解锁富媒体消息能力意味着将团队协作效率提升到全新维度。本文将深入解析企业微信机器人支持的四大高级消息类型,并通过可立即复用的Python代码示例,带您实现从监控报警到自动报告的全场景覆盖。
1. 环境准备与基础配置
在开始发送富媒体消息前,需要完成两个关键步骤:创建企业微信机器人和配置Python环境。不同于简单的文本消息,富媒体消息对数据格式和接口调用有更严格的要求。
首先登录企业微信管理后台,在「应用管理」中创建自定义机器人。获取webhook地址时需注意:
https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
这个包含32位字符的key是后续所有API调用的通行证。为安全起见,建议将其存储在环境变量中:
import os
WEBHOOK_KEY = os.getenv('WECHAT_WORK_BOT_KEY')
WEBHOOK_URL = f"https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key={WEBHOOK_KEY}"
Python环境需要安装requests库处理HTTP请求,推荐使用2.28+版本以获得更稳定的文件上传支持:
pip install requests>=2.28.0
验证基础连接可用性时,可以发送一个简单的文本消息测试通道:
def test_connection():
payload = {
"msgtype": "text",
"text": {"content": "通道测试", "mentioned_list": []}
}
response = requests.post(WEBHOOK_URL, json=payload)
return response.status_code == 200
2. Markdown消息:专业报告的最佳载体
企业微信支持标准的Markdown语法(GFM风格),这让技术报告的呈现变得异常简单。以下是一个包含多级标题、代码块和表格的监控报警示例:
def send_markdown_report():
content = """
# [紧急] 数据库主库CPU告警
> 发生时间: {timestamp}
## 当前指标
| 指标项 | 阈值 | 当前值 | 超出 |
|--------|------|--------|------|
| CPU使用率 | 80% | 92% | ✔ |
| 连接数 | 500 | 623 | ✔ |
## 最近错误日志
```sql
ERROR 1040 (HY000): Too many connections
建议操作:
-
立即检查慢查询
-
考虑增加连接池大小
-
通知DBA团队 """.format(timestamp=datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
payload = { "msgtype": "markdown", "markdown": {"content": content} } requests.post(WEBHOOK_URL, json=payload)
实际效果中,Markdown消息会自动转换为适合移动端阅读的格式,并保留所有关键样式元素。几个实用技巧:
* 使用`<font color="warning">`标签实现彩色文本(支持red/green/blue等颜色值)
* 通过`> `引用块突出关键信息
* 表格列宽会自动调整,建议控制在5列以内
对于需要强调的消息,可以结合@提醒功能:
```python
payload["markdown"]["content"] += "\n<@%s>" % "userid1|userid2"
3. 图文与文件消息:自动化报告解决方案
当简单的Markdown无法满足需求时,图文消息(news)和文件消息(file)提供了更专业的解决方案。以下是发送日报图文卡片的完整实现:
def send_daily_report():
# 先上传本地图片获取media_id
image_url = "https://example.com/report_20230815.png"
image_resp = requests.get(image_url)
upload_url = WEBHOOK_URL.replace("send", "upload_media?type=image")
files = {"media": ("report.png", image_resp.content)}
media_info = requests.post(upload_url, files=files).json()
# 构建图文消息
articles = [{
"title": "8月15日运营日报",
"description": "核心指标趋势与关键事件汇总",
"url": "https://bi.example.com/daily/20230815",
"picurl": media_info['url']
}]
payload = {
"msgtype": "news",
"news": {"articles": articles}
}
requests.post(WEBHOOK_URL, json=payload)
文件消息的发送略有不同,需要先通过API上传文件获取media_id:
def send_excel_report(filepath):
upload_url = WEBHOOK_URL.replace("send", "upload_media?type=file")
with open(filepath, "rb") as f:
files = {"media": (os.path.basename(filepath), f)}
media_info = requests.post(upload_url, files=files).json()
payload = {
"msgtype": "file",
"file": {"media_id": media_info['media_id']}
}
requests.post(WEBHOOK_URL, json=payload)
关键限制说明:
- 图片建议尺寸:1200x720像素,大小不超过2MB
- 文件大小上限:20MB
- media_id有效期:3天
4. 实战组合:构建智能通知系统
将各种消息类型与自动化场景结合,可以创造出强大的工作流。以下是几个典型用例的实现方案:
场景一:服务器监控看板(定时任务)
def server_monitor_dashboard():
# 获取监控数据
cpu_usage = get_cpu_usage()
memory_usage = get_memory_usage()
# 生成Markdown内容
status = "正常" if cpu_usage < 80 else "警告"
content = f"""
## 服务器资源监控 {status}
**更新时间**: {datetime.now().strftime('%H:%M')}
```bash
CPU: {'█' * int(cpu_usage/10)} {cpu_usage}%
内存: {'█' * int(memory_usage/10)} {memory_usage}%
阈值提醒:CPU >80% 或 内存 >90% 时自动通知运维 """
# 添加截图附件
screenshot = generate_screenshot()
send_markdown(content)
send_image(screenshot)
**场景二:自动化测试报告(事件触发)**
```python
def handle_test_result(test_run):
if test_run.failed_count > 0:
content = f"""
# 测试失败告警 ❌
**构建编号**: #{test_run.build_number}
**失败用例**:
{'\n'.join(f'- {case.name}' for case in test_run.failed_cases)}
[查看详细报告]({test_run.report_url})
"""
send_markdown(content)
send_file(test_run.log_file)
else:
send_markdown(f"✅ 所有测试通过 (共{test_run.total_cases}个用例)")
场景三:项目进度日报(定时+人工触发)
def generate_project_report(project_id, manual_trigger=False):
report = generate_project_metrics(project_id)
chart = render_burndown_chart(project_id)
articles = [{
"title": f"{report['name']} 进度日报",
"description": f"完成度: {report['progress']}% | 剩余: {report['remaining']}天",
"url": report['detail_url'],
"picurl": chart
}]
if manual_trigger:
articles[0]["title"] += " (手动生成)"
send_news(articles)
5. 高级技巧与异常处理
在实际企业环境中使用时,有几个关键问题需要注意:
消息频率限制:
- 相同内容每分钟最多发送20次
- 机器人每分钟最多发送30条消息
- 建议实现简单的消息队列控制:
from collections import deque
from time import sleep
message_queue = deque(maxlen=30)
def safe_send(payload):
now = time.time()
if len(message_queue) >= 30 and now - message_queue[0] < 60:
sleep(60 - (now - message_queue[0]))
response = requests.post(WEBHOOK_URL, json=payload)
message_queue.append(time.time())
return response
文件上传优化: 大文件上传时可能超时,建议实现分块上传:
def chunked_upload(filepath, chunk_size=5*1024*1024):
upload_url = WEBHOOK_URL.replace("send", "upload_media?type=file")
file_id = None
with open(filepath, 'rb') as f:
while True:
chunk = f.read(chunk_size)
if not chunk:
break
files = {'media': (os.path.basename(filepath), chunk)}
params = {'file_id': file_id} if file_id else {}
resp = requests.post(upload_url, files=files, params=params)
file_id = resp.json().get('media_id')
return file_id
错误处理最佳实践: 企业微信API可能返回各种错误代码,需要合理处理:
ERROR_CODES = {
40001: "无效的Webhook地址",
40002: "消息内容为空",
40003: "消息内容超过限制",
40004: "无效的媒体文件",
40005: "文件类型不支持"
}
def robust_send(payload):
try:
response = requests.post(WEBHOOK_URL, json=payload, timeout=10)
result = response.json()
if result.get('errcode') != 0:
msg = ERROR_CODES.get(result['errcode'], "未知错误")
raise Exception(f"API错误 {result['errcode']}: {msg}")
return True
except requests.exceptions.RequestException as e:
logging.error(f"网络错误: {str(e)}")
return False
在企业级应用中,建议将消息发送封装为独立服务,并实现以下增强功能:
- 消息模板管理
- 发送频率监控
- 失败自动重试机制
- 消息到达率统计
更多推荐
所有评论(0)