引言
企业存在给 特定群组 自动推送消息的需求,比如:监控报警推送、销售线索推送、运营内容推送等。 你可以在群聊中添加一个
自定义机器人
,通过服务端调用webhook
地址,即可将外部系统的通知消息即时推送到群聊中。
飞书自定义机器人使用指南:
钉钉自定义机器人使用指南:
open.dingtalk.com/document/ro…
飞书自定义机器人
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# @Author: Hui
# @Desc: { webhook机器人模块 }
# @Date: 2023/02/19 19:48
import hmac
import base64
import hashlib
import time
from urllib.parse import quote_plus
import requests
from exceptions.base import SendMsgException
class BaseChatBot(object):
"""群聊机器人基类"""
def __init__(self, webhook_url: str, secret: str = None):
"""
初始化机器人
Args:
webhook_url: 机器人webhook地址
secret: 安全密钥
"""
self.webhook_url = webhook_url
self.secret = secret
def _get_sign(self, timestamp: str, secret: str):
"""
获取签名(NotImplemented)
Args:
timestamp: 签名时使用的时间戳
secret: 签名时使用的密钥
Returns:
"""
raise NotImplementedError
def send_msg(self, content: str, timeout=10):
"""
发送消息(NotImplemented)
Args:
content: 消息内容
timeout: 发送消息请求超时时间 默认10秒
Returns:
"""
raise NotImplementedError
class FeiShuChatBot(BaseChatBot):
"""飞书机器人"""
def _get_sign(self, timestamp: str, secret: str) -> str:
"""
获取签名
把 timestamp + "\n" + 密钥 当做签名字符串,使用 HmacSHA256 算法计算签名,再进行 Base64 编码
Args:
timestamp: 签名时使用的时间戳
secret: 签名时使用的密钥
Returns: sign
"""
string_to_sign = '{}\n{}'.format(timestamp, secret)
hmac_code = hmac.new(string_to_sign.encode("utf-8"), digestmod=hashlib.sha256).digest()
# 对结果进行base64处理
sign = base64.b64encode(hmac_code).decode('utf-8')
return sign
def send_msg(self, content: str, timeout=10):
"""
发送消息
Args:
content: 消息内容
timeout: 发送消息请求超时时间 默认10秒
Raises:
SendMsgException
Returns:
"""
msg_data = {
"msg_type": "text",
"content": {
"text": f"{content}"
}
}
if self.secret:
timestamp = str(round(time.time()))
sign = self._get_sign(timestamp=timestamp, secret=self.secret)
msg_data["timestamp"] = timestamp
msg_data["sign"] = sign
try:
resp = requests.post(url=self.webhook_url, json=msg_data, timeout=timeout)
resp_info = resp.json()
if resp_info.get("code") != 0:
raise SendMsgException(f"FeiShuChatBot send msg error, {resp_info}")
except Exception as e:
raise SendMsgException(f"FeiShuChatBot send msg error {e}") from e
钉钉自定义机器人
class DingTalkChatBot(BaseChatBot):
"""钉钉机器人"""
def _get_sign(self, timestamp: str, secret: str):
"""
获取签名
把 timestamp + "\n" + 密钥当做签名字符串,使用 HmacSHA256 算法计算签名,
然后进行 Base64 encode,最后再把签名参数再进行 urlEncode,得到最终的签名(需要使用UTF-8字符集)
Args:
timestamp: 签名时使用的时间戳
secret: 签名时使用的密钥
Returns: sign
"""
secret_enc = secret.encode('utf-8')
string_to_sign = '{}\n{}'.format(timestamp, secret)
string_to_sign_enc = string_to_sign.encode('utf-8')
hmac_code = hmac.new(secret_enc, string_to_sign_enc, digestmod=hashlib.sha256).digest()
sign = quote_plus(base64.b64encode(hmac_code))
return sign
def send_msg(self, content: str, timeout=10):
"""
发送消息
Args:
content: 消息内容
timeout: 发送消息请求超时时间 默认10秒
Raises:
SendMsgException
Returns:
"""
timestamp = str(round(time.time() * 1000))
sign = self._get_sign(timestamp=timestamp, secret=self.secret)
params = {
"timestamp": timestamp,
"sign": sign
}
msg_data = {
"msgtype": "text",
"text": {
"content": content
}
}
try:
resp = requests.post(url=self.webhook_url, json=msg_data, params=params, timeout=timeout)
resp_info = resp.json()
if resp_info.get("errcode") != 0:
raise SendMsgException(f"DingTalkChatBot send msg error, {resp_info}")
except Exception as e:
raise SendMsgException(f"DingTalkChatBot send msg error {e}") from e
使用的时候
feishu = FeiShuChatBot(webhook_url="xxx", secret="xxxx")
feishu.send_msg("test msg")
dingtalk = DingTalkChatBot(webhook_url="xxx", secret="xxxx")
feishu.send_msg("test msg")
但这样使用有点不好的一点就是如果我突然从钉钉换成飞书或者企微,业务中的所有使用的代码就要全部替换。但一般也不会随便换平台,我这里就是想引出工厂模式。
工厂模式封装
工厂模式是一种常见的设计模式,它可以帮助我们创建对象,而无需显式地指定其具体类型。在这种模式下,我们通过使用一个工厂来创建对象,并将对象的创建和使用分离开来,从而提高了代码的可维护性和可扩展性.
对于Webhook群聊机器人,我们可以将其实现为一个工厂类,该工厂类负责创建不同类型的机器人对象。我们可以通过定义一个机器人接口或抽象类,来规范所有机器人的通用方法和属性。然后,我们可以根据需要创建具体的机器人类,并实现其特定的方法和属性。代码如下
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# @Author: Hui
# @Desc: { 机器人工厂模块 }
# @Date: 2023/02/19 20:03
from typing import Dict, Type
from chatbot import DingTalkChatBot, FeiShuChatBot, BaseChatBot
class ChatBotType:
"""群聊机器人类型"""
FEISHU_CHATBOT = "feishu"
DINGTALK_CHATBOT = "dingtalk"
class ChatBotFactory(object):
"""
消息机器人工厂
支持 飞书、钉钉、自定义机器人消息发送
"""
# 群聊机器人处理类映射
CHATBOT_HANDLER_CLS_MAPPING: Dict[str, Type[BaseChatBot]] = {
ChatBotType.FEISHU_CHATBOT: FeiShuChatBot,
ChatBotType.DINGTALK_CHATBOT: DingTalkChatBot,
}
def __init__(self, chatbot_type: str):
if chatbot_type not in self.CHATBOT_HANDLER_CLS_MAPPING:
raise ValueError(f"不支持 {chatbot_type} 类型的机器人")
self.chatbot_type = chatbot_type
def build(self, webhook_url: str, secret: str = None) -> BaseChatBot:
"""
构造具体的机器人处理类
Args:
webhook_url: 机器人webhook地址
secret: 机器人密钥
Returns: 根据 robot_type 返回对应的机器人处理类
"""
chatbot_handle_cls = self.CHATBOT_HANDLER_CLS_MAPPING.get(self.chatbot_type)
return chatbot_handle_cls(webhook_url=webhook_url, secret=secret)
通过字典的方式把机器人类型(平台)与具体处理类关联起来,这样构造的时候就不用写 if else
使用的时候直接用工厂创建具体的实例出来就行
def main():
feishu_webhook = "xxx"
feishu_webhook_secret = "xxx"
dingtalk_webhook = "xxx"
dingtalk_webhook_secret = "xxx"
feishu_chatbot = ChatBotFactory(chatbot_type=ChatBotType.FEISHU_CHATBOT).build(
webhook_url=feishu_webhook,
secret=feishu_webhook_secret
)
content = "飞书自定义机器人使用指南:\n https://open.feishu.cn/document/ukTMukTMukTM/ucTM5YjL3ETO24yNxkjN"
feishu_chatbot.send_msg(content)
dingtalk_chatbot = ChatBotFactory(chatbot_type=ChatBotType.DINGTALK_CHATBOT).build(
webhook_url=dingtalk_webhook,
secret=dingtalk_webhook_secret
)
content = "钉钉自定义机器人使用指南:\n https://open.dingtalk.com/document/robots/custom-robot-access"
dingtalk_chatbot.send_msg(content)
if __name__ == '__main__':
main()
新增企微机器人
需要切换的时候直接替换掉 chatbot_type 就可以。把chatbot_type、webhook_url、secret放到配置文件即可在不改动代码的情况直接切换。工厂模式也方便扩展,例如再新增一个企微等。
class WeComChatbot(BaseChatBot):
"""企业微信机器人"""
def _get_sign(self, timestamp: str, secret: str):
"""企业微信暂不支持签名加密"""
pass
def send_msg(self, content: str, timeout=10):
"""
发送消息
Args:
content: 消息内容
timeout: 发送消息请求超时时间 默认10秒
Raises:
SendMsgException
Returns:
"""
msg_data = {
"msgtype": "text",
"text": {
"content": content
}
}
try:
resp = requests.post(self.webhook_url, json=msg_data)
resp_info = resp.json()
if resp.status_code != 200:
raise ValueError(f"WeComChatbot send message error, {resp_info}")
except Exception as e:
raise SendMsgException(e) from e
工厂类中只要新增一个企微群聊机器人处理类的映射就可以
from typing import Dict, Type
from chatbot import DingTalkChatBot, FeiShuChatBot, WeComChatbot, BaseChatBot
class ChatBotType:
"""群聊机器人类型"""
FEISHU_CHATBOT = "feishu"
DINGTALK_CHATBOT = "dingtalk"
WECOM_CHATBOT = "wecom"
class ChatBotFactory(object):
"""
消息机器人工厂
支持 飞书、钉钉、企微自定义机器人消息发送
"""
# 群聊机器人处理类映射
CHATBOT_HANDLER_CLS_MAPPING: Dict[str, Type[BaseChatBot]] = {
ChatBotType.FEISHU_CHATBOT: FeiShuChatBot,
ChatBotType.DINGTALK_CHATBOT: DingTalkChatBot,
ChatBotType.WECOM_CHATBOT: WeComChatbot
}
def __init__(self, chatbot_type: str):
if chatbot_type not in self.CHATBOT_HANDLER_CLS_MAPPING:
raise ValueError(f"不支持 {chatbot_type} 类型的机器人")
self.chatbot_type = chatbot_type
def build(self, webhook_url: str, secret: str = None) -> BaseChatBot:
"""
构造具体的机器人处理类
Args:
webhook_url: 机器人webhook地址
secret: 机器人密钥
Returns: 根据 robot_type 返回对应的机器人处理类
"""
chatbot_handle_cls = self.CHATBOT_HANDLER_CLS_MAPPING.get(self.chatbot_type)
return chatbot_handle_cls(webhook_url=webhook_url, secret=secret)
看看读取配置文件的话该如何使用
# settings.py
# chatbot_type = "feishu"
# chatbot_type = "dingtalk"
chatbot_type = "wecom"
webhook_url = "xxx"
secret = ""
# xxx_logic.py
import settings
chatbot = ChatBotFactory(chatbot_type=settings.chatbot_type).build(
webhook_url=settings.webhook_url,
secret=settings.secret
)
chatbot.send_msg("test msg")
使用工厂模式封装虽然让代码变的多了一些,但更容易维护与扩展,因此我们还是要结合业务场景选择一些合适的设计模式来编写代码,这样也能提示自己的编码能力。
源代码
HuiDBK/py-tools: 打造 Python 开发常用的工具,让Coding变得更简单 (github.com)
如果你对Python感兴趣,想要学习python,这里给大家分享一份Python全套学习资料,都是我自己学习时整理的,希望可以帮到你,一起加油!
😝有需要的小伙伴,可以点击下方链接免费领取或者V扫描下方二维码免费领取🆓
Python全套学习资料
1️⃣零基础入门
① 学习路线
对于从来没有接触过Python的同学,我们帮你准备了详细的学习成长路线图。可以说是最科学最系统的学习路线,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。
② 路线对应学习视频
还有很多适合0基础入门的学习视频,有了这些视频,轻轻松松上手Python~
③练习题
每节视频课后,都有对应的练习题哦,可以检验学习成果哈哈!
2️⃣国内外Python书籍、文档
① 文档和书籍资料
3️⃣Python工具包+项目源码合集
①Python工具包
学习Python常用的开发软件都在这里了!每个都有详细的安装教程,保证你可以安装成功哦!
②Python实战案例
光学理论是没用的,要学会跟着一起敲代码,动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。100+实战案例源码等你来拿!
③Python小游戏源码
如果觉得上面的实战案例有点枯燥,可以试试自己用Python编写小游戏,让你的学习过程中增添一点趣味!
4️⃣Python面试题
我们学会了Python之后,有了技能就可以出去找工作啦!下面这些面试题是都来自阿里、腾讯、字节等一线互联网大厂,并且有阿里大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。
5️⃣Python兼职渠道
而且学会Python以后,还可以在各大兼职平台接单赚钱,各种兼职渠道+兼职注意事项+如何和客户沟通,我都整理成文档了。
上述所有资料 ⚡️ ,朋友们如果有需要的,可以扫描下方👇👇👇二维码免费领取🆓