影刀RPA新手教程:飞书机器人Webhook完全指南——消息推送格式、卡片消息与群通知自动化

作者:林焱 | 真实案例驱动,每篇覆盖12大核心模块,禁止空话。

案例背景:我把运营群的消息推送搞成了全自动

去年双11,运营团队每天要在3个飞书群里手动推送数据日报,早上9点一次、下午6点一次。

那个人休了三天假,群里连续三天没数据,老板直接在群里问"人呢"。

我接手后用影刀RPA + 飞书机器人Webhook,把这套推送做到了完全无人值守。

今天这篇文章,就是把整套方案拆透,从零到上线,每一步都有代码。


一、安装与准备工作

打开影刀客户端,新建一个应用,取名"飞书消息推送机器人"。

我当时犯的第一个错:直接在本地跑,没考虑服务器环境。

正确做法:先在影刀控制台创建一个应用,发布到云端,再用云调度触发。

安装影刀就不赘述了,官网下载一路下一步。重点说环境配置:

  • 影刀版本:建议 2.6 以上,低版本HTTP指令有bug
  • Python环境:勾选"嵌入Python",后面要用到 requests 库
  • 编码设置:应用设置里把编码改成 UTF-8,否则中文会乱码

我当时踩过这个坑:本地跑得好好的,发到云端就乱码。

原因是本地Windows默认GBK,云端是UTF-8,HTTP请求没指定编码就翻车了。

在这里插入图片描述


二、元素定位:获取飞书Webhook地址

飞书机器人的Webhook地址是固定的,不需要元素定位去抓取。

但很多新手不知道Webhook入口在哪,这里说清楚:

打开飞书群 → 设置 → 群机器人 → 添加机器人 → 自定义机器人。

勾选"自定义消息类型",复制 Webhook URL。

URL格式是这样的:

https://open.feishu.cn/open-apis/bot/v2/hook/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

重要:不要把完整的URL当秘密,飞书机器人的安全机制是靠URL本身,泄露就等于把群权限交出去了。

我当时把URL写进了代码注释里,提交到Git仓库,后来不得不把机器人删了重建。

正确做法:把Webhook URL存到影刀的"应用参数"里,运行时动态读取,代码里永远不硬编码。


三、变量与数据类型:消息体的正确组装方式

飞书消息推送的核心,是往Webhook地址发一个HTTP POST请求,Body是JSON格式。

在影刀里,先创建一个字符串变量 webhook_url,值是你的Webhook地址。

再创建一个字典变量 msg_body,用来组装消息体。

最简单的文本消息格式:

在这里插入图片描述

{
  "msg_type": "text",
  "content": {
    "text": "测试消息"
  }
}

在影刀里用"配置参数"指令来组装这个JSON:

  • 变量名:msg_body
  • 变量类型:字典
  • 键值对:msg_typetextcontent → 另一个字典

这里有个细节:影刀的字典类型,嵌套字典要用"配置参数"里的"添加子项"来操作。

直接写JSON字符串再转字典也行,但我更推荐用影刀原生的字典操作,调试时能在变量面板直接看到结构。

我当时踩过这个坑:用Python的 json.dumps() 转出来的字符串,再传给HTTP指令,Content-Type没设为 application/json,飞书一直返回"invalid body"。


四、流程控制:按条件发送不同消息

真实场景里,消息内容是根据数据动态变化的。

比如销售额达标就发绿色卡片,不达标就发红色告警。

用影刀的"如果…否则"指令来实现:

店群矩阵自动化突破运营极限!

如果 销售额 >= 目标值
  消息类型 = 成功卡片
否则
  消息类型 = 告警文本
结束如果

更复杂一点,可以嵌套判断:

如果 销售额 >= 目标值 * 1.2
  发送"超额完成"卡片
否则如果 销售额 >= 目标值
  发送"达标"卡片
否则
  发送"未达标"告警 + @所有人
结束如果

循环指令用在批量推送场景。

比如要给5个群各发一条消息,把Webhook地址存到列表里,用"遍历循环"逐个发送。

在这里插入图片描述

当时我第一次写循环,把HTTP请求放在循环里没加等待,飞书限频,第3条开始全部失败。

正确做法:每次发送后加 睡眠 指令,等待1-2秒,避开限频。


五、网页自动化:从后台抓取推送数据

消息内容不能写死,要从实际业务系统里抓。

以电商后台为例,用影刀的"启动新浏览器"指令打开后台页面。

元素定位四合一策略

先试XPath,最稳:

//div[@class='sales-number']/span

XPath找不到再试CSS选择器:

div.sales-number > span

动态ID的情况用正则表达式匹配:

id="sales_\d+"

实在定位不到的,用"获取元素XPath"指令先录一遍,再手工优化。

我当时踩过这个坑:页面用了Shadow DOM,影刀直接定位不到。

解决方法是先用"执行JavaScript"指令,在页面里用 ShadowRoot.querySelector() 拿到元素,再把内容通过 return 传出来。


在这里插入图片描述

六、数据处理:把原始数据变成消息内容

从页面抓到的数据,通常是字符串,需要处理成合适的格式。

用影刀的"文本处理"指令做字符串拼接:

"今日销售额:" + 销售额 + "\n目标完成率:" + 完成率 + "%"

多行文本用 \n 换行,飞书的文本消息支持换行显示。

如果是数字,要做格式化:

完成率 =  round(销售额 / 目标值 * 100, 2)

数据里有空值的情况,用"如果…否则"做默认值处理:

如果 销售额 == "" 或 销售额 == null
  销售额 = "0"
结束如果

我当时遇到过一个坑:页面加载不完全,抓到的是空字符串,直接做除法算完成率,流程直接报错停了。

后来在所有数据抓取后面都加了"尝试捕获"指令,抓不到就用上一次缓存的值。


七、鼠标键盘图像:截图插入消息

飞书机器人支持发送图片,先把图表截图,转成Base64,再塞进消息体。

用影刀的"截取网页元素截图"指令,把销售趋势图截下来,保存到本地路径。

然后用Python把图片转成Base64:

import base64

with open("C:/temp/sales_chart.png", "rb") as f:
    img_base64 = base64.b64encode(f.read()).decode('utf-8')
    ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/2cb317897e884b308cf15b1c5f89a387.png#pic_center)


print(img_base64)

把Python的输出存到影刀变量 img_base64 里。

飞书图片消息的格式:

{
  "msg_type": "image",
  "content": {
    "image_key": "img_xxxxxxxx"
  }
}

注意:飞书发送图片不能直接贴Base64,要先用"上传图片"接口拿到 image_key,再用 image_key 发消息。

我当时在这里卡了半天,一直往Webhook直接POST图片数据,返回的都是"unsupported msg type"。


八、进阶技能:卡片消息的高级玩法

文本消息能干的事太有限,真实生产环境都用卡片消息。

飞书卡片消息的JSON结构比较复杂,用影刀的"配置参数"指令一层层组装:

{
  "msg_type": "interactive",
  "card": {
    "config": {
      "wide_screen_mode": true
    },
    "header": {
      "title": {
        "tag": "plain_text",
        "content": "今日数据日报"
      },
      "template": "green"
    },
    "elements": [
      {
        "tag": "div",
        "text": {
          "tag": "lark_md",
          "content": "**销售额**:¥120,000\n**完成率**:120%"
        }
      }
    ]
  }
}

卡片颜色 template 可选值:blue、green、orange、red、purple、grey。

用变量动态控制颜色,让卡片状态一眼可见:

如果 完成率 >= 100
  template = "green"
否则如果 完成率 >= 80
  template = "orange"
否则
  template = "red"
结束如果

卡片里还能加按钮,点击后触发另一个Webhook,实现简单的交互。

我当时做的方案:卡片底部加一个"查看详情"按钮,点击后跳转到数据看板页面。


九、平台实战:在影刀控制台配置定时触发

写完流程,要在影刀控制台配置定时调度,才能做到每天自动推送。

在这里插入图片描述

打开影刀控制台 → 任务中心 → 新建任务。

任务类型选"定时触发",时间设成每天上午9点和下午6点。

Cron表达式写法:

0 9,18 * * *

意思是每天9:00和18:00各触发一次。

触发器配置里,把"飞书Webhook地址"作为参数传入,这样换群只需要改参数,不用改流程。

我当时踩过这个坑:流程里硬编码了Webhook地址,后来运营新建了一个群,要改地址,只能改流程重新发版。

正确做法:所有外部配置(Webhook地址、阈值、收件人列表)全部通过应用参数传入。


十、系统联动:和邮件、短信形成多重告警

飞书消息有可能漏看,关键告警要多重通知。

在影刀流程里,飞书消息发送成功后,再调一个邮件发送指令。

邮件收件人列表存到影刀的列表变量里,遍历发送。

如果飞书消息发送失败(HTTP返回码不是200),立即发邮件告警,内容是错误详情。

用"尝试捕获"指令包住HTTP请求:

尝试
  HTTP请求 POST webhook_url
  如果 返回码 != 200
    发送邮件 "飞书推送失败:" + 返回消息
  结束如果
捕获异常
  发送邮件 "流程异常:" + 异常信息
结束尝试

我当时有一次飞书Webhook被人改了权限,所有推送全部失败,又因为没加异常捕获,失败了也没人知道。

在这里插入图片描述

从那以后,所有对外的HTTP请求,我都会包一层状态检查和异常告警。


十一、工程化规范:让机器人不负责任

上线的机器人,要遵守几个规范,否则跑着跑着就没人维护了。

命名规范

机器人名字要能看出用途,比如"数据日报推送机器人",不要叫"test"、“机器人1”。

日志规范

每次推送,在影刀流程里写一条日志,记录推送时间、目标群、消息摘要。

日志格式统一:

[飞书推送] 2024-11-11 09:00:02 | 运营群 | 销售额120000 | 成功

异常处理规范

所有HTTP调用都必须有超时设置和重试机制。

飞书Webhook推荐重试3次,每次间隔2秒:

temu店群自动化报活动案例

循环 3次
  尝试
    HTTP请求
    如果 返回码 == 200
      跳出循环
    结束如果
  捕获异常
    睡眠 2秒
    继续
  结束尝试
结束循环

我当时没加热重试,网络抖动导致每天总有那么一两条丢消息,运营来问的时候才发现问题。


在这里插入图片描述

十二、速查表与常见报错

报错1:HTTP 400 invalid body

原因:Content-Type没设为 application/json,或者JSON格式有语法错误。

解决:在HTTP请求指令里,Header手动加一条 Content-Type: application/json

报错2:HTTP 9499 msg timeout

原因:Webhook地址失效,或者机器人被删除了。

解决:去飞书群里重新添加一个机器人,更新Webhook地址。

报错3:卡片消息显示"不支持的消息类型"

原因:卡片JSON结构写错了,或者 msg_type 写成了 text 而不是 interactive

解决:对照飞书开放平台的卡片消息文档,检查JSON结构。

报错4:发送成功但群里看不到消息

原因:机器人被移出了群,或者群设置了"仅群主可@所有人"。

解决:检查机器人在群里的状态,调整群权限设置。

飞书卡片颜色速查

场景 template值
成功/达标 green
进行中/普通 blue
警告/接近阈值 orange
失败/严重告警 red
信息提示 grey

完整案例代码参考

在这里插入图片描述

以下是主流程的核心代码片段,可直接参考使用。

HTTP请求配置(Python实现,在影刀"执行Python代码"指令里调用):

import requests
import json

def send_feishu_message(webhook_url, msg_body):
    headers = {
        "Content-Type": "application/json",
        "charset": "utf-8"
    }
    resp = requests.post(webhook_url, 
                        data=json.dumps(msg_body, ensure_ascii=False).encode('utf-8'),
                        headers=headers,
                        timeout=10)
    return resp.status_code, resp.text

# 卡片消息组装示例
card_msg = {
    "msg_type": "interactive",
    "card": {
        "config": {"wide_screen_mode": True},
        "header": {
            "title": {"tag": "plain_text", "content": "销售日报"},
            "template": "green"
        },
        "elements": [
            {
                "tag": "div",
                "text": {
                    "tag": "lark_md",
                    "content": "**今日销售额**:¥{}\n**完成率**:{}%".format(sales, rate)
                }
            }
        ]
    }
}

status, result = send_feishu_message(webhook_url, card_msg)
print(status, result)

XPath元素定位参考(以电商后台为例):

# 销售额元素
//div[contains(@class,'sales')]//span[@class='value']

# 完成率元素
//div[@id='dashboard']//div[@class='rate']/text()

# 动态ID处理
//div[contains(@id,'sales_')]/span

CSS选择器备选方案:

/* 销售额 */
div.sales span.value

/* 完成率 */
#dashboard div.rate

/* 包含特定文本的元素 */
div:contains("销售额")

我当时踩过这个坑:三个最深刻的教训

教训一:Webhook地址硬编码在代码里。

有次我把包含Webhook地址的代码截图发到技术群里问问题,虽然马赛克了大部分,但有人还是通过上下文猜到了完整地址。

半小时后那个群开始收到垃圾消息。

从那以后,所有密钥、Webhook地址,一律不进代码,全部走参数。

教训二:没做发送频率限制。

早期版本里,数据异常触发告警,1分钟内发了60多条消息到群里。

群成员直接把机器人移出了群。

现在所有推送都加频率限制:同一个内容5分钟内只推一次,告警类消息加@提醒,普通消息不加。

在这里插入图片描述

教训三:卡片消息的JSON手写,没有校验。

有一次手抖少写了一个引号,JSON格式错误,卡片消息一直发不出去。

现在卡片JSON先用在线JSON校验工具检查,再贴到影刀里,或者用Python的 json.dumps() 来生成,避免手写错误。


延伸:home.linyan.cloud 上的更多资源

这篇文章的完整示例代码和飞书卡片消息模板,我都整理到了 home.linyan.cloud,包含10种不同场景的卡片JSON模板,直接复制就能用。

如果你在配置Webhook时遇到这篇文章没覆盖到的问题,也可以去那里留言,我看到会回复。


#影刀RPA #RPA教程 #飞书机器人 #Webhook #消息推送 #自动化 #林焱

作者:林焱

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐