Files
apiautotest/common_utils/wechat_handle.py
2023-05-27 14:45:48 +08:00

176 lines
6.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- coding: utf-8 -*-
# @Time : 2023/5/11 15:01
# @Author : chenyinhua
# @File : wechat_handle.py
# @Software: PyCharm
# @Desc: 企业微信机器人
import os
from requests import request
import base64
import hashlib
import re
from loguru import logger
class WechatBot:
"""
企业微信机器人
当前自定义机器人支持文本text、markdownmarkdown、图片image、图文news, 文件file五种消息类型。
机器人的text/markdown类型消息支持在content中使用<@userid>扩展语法来@群成员
"""
def __init__(self, webhook_url):
"""
:param webhook_url: 机器人的WebHook_url
"""
self.webhook_url = webhook_url
self.headers = {
"Content-Type": "application/json",
"Charset": "UTF-8"
}
def send_message(self, payload):
"""
发送微信消息
:payload: 请求json数据
"""
logger.debug("\n======================================================\n" \
"-------------Start发送企业微信消息--------------------\n"
f"Webhook_Url: {self.webhook_url}\n" \
f"内容: {payload}\n" \
"=====================================================")
response = request(
url=self.webhook_url,
json=payload,
headers=self.headers,
method="POST"
)
if response.json().get("errcode") == 0:
logger.debug("\n======================================================\n" \
"-------------End发送企业微信消息--------------------\n"
f"通过企业微信发送{payload.get('msgtype', '')}消息成功:{response.json()}\n" \
"=====================================================")
print(f"通过企业微信发送{payload.get('msgtype', '')}消息成功:{response.json()}")
return True
else:
logger.error(f"通过企业微信发送{payload.get('msgtype', '')}消息失败:{response.text}")
print(f"通过企业微信发送{payload.get('msgtype', '')}消息失败:{response.text}")
return False
def send_text(self, content, mentioned_list=None, mentioned_mobile_list=None):
"""
发送文本消息
:param content: 文本内容最长不超过2048个字节必须是utf8编码
:param mentioned_list: userid的列表提醒群中的指定成员(@某个成员)@all表示提醒所有人如果开发者获取不到userid可以使用mentioned_mobile_list
:param mentioned_mobile_list: 手机号列表,提醒手机号对应的群成员(@某个成员)@all表示提醒所有人
"""
payload = {
"msgtype": "text",
"text": {
"content": content,
"mentioned_list": mentioned_list,
"mentioned_mobile_list": mentioned_mobile_list
}
}
return self.send_message(payload)
def send_markdown(self, content):
"""
发送markdown消息
目前支持的markdown语法是如下的子集
1. 标题 支持1至6级标题注意#与文字中间要有空格)
2. 加粗
3. 链接
4. 行内代码段(暂不支持跨行)
5. 引用
6. 字体颜色(只支持3种内置颜色), 绿色color="info"灰色color="comment"橙红色color="warning"
:param content: markdown内容最长不超过4096个字节必须是utf8编码
"""
payload = {
"msgtype": "markdown",
"markdown": {
"content": content
}
}
return self.send_message(payload)
def send_picture(self, image_path):
"""
发送图片消息
:param image_path: 图片的绝对路径
"""
with open(image_path, "rb") as f:
image_data = f.read()
payload = {
"msgtype": "image",
"image": {
"base64": base64.b64encode(image_data).decode("utf-8"), # # 将图片数据转换成Base64编码格式
"md5": hashlib.md5(image_data).hexdigest() # # 计算图片的MD5值
}
}
return self.send_message(payload)
def send_text_picture(self, articles: list):
"""
发送图文消息
:param articles: 图文消息一个图文消息支持1到8条图文, 包括如下字段
1. title: 标题不超过128个字节超过会自动截断
2. description: 非必填描述不超过512个字节超过会自动截断
3. url: 点击后跳转的链接。
4. picurl: 非必填图文消息的图片链接支持JPG、PNG格式较好的效果为大图 1068*455小图150*150。
"""
payload = {
"msgtype": "news",
"news": {
"articles": [
]
}
}
for article in articles:
payload["news"]["articles"].append(
{
"title": article.get("title"),
"description": article.get("description", ""),
"url": article.get("url"),
"picurl": article.get("picurl", "")
}
)
return self.send_message(payload)
def upload_file(self, file_path):
"""
上传文件到企业微信服务器(要求文件大小在5B~20M之间)
注意素材上传得到media_id该media_id仅三天内有效media_id只能是对应上传文件的机器人可以使用
:param file_path: 文件绝对路径
"""
token_regex = r"key=([\w-]+)"
match = re.search(token_regex, self.webhook_url)
token = match.group(1)
url = f"https://qyapi.weixin.qq.com/cgi-bin/webhook/upload_media?key={token}&type=file"
headers = {
"Content-Type": "multipart/form-data;"
}
with open(file_path, "rb") as f:
files = {"media": (os.path.basename(file_path), f.read())}
response = request(url=url, method="POST", files=files, headers=headers)
if response.json().get("errcode") == 0:
media_id = response.json().get("media_id")
print(f"上传文件成功media_id= {media_id}")
return media_id
else:
print(f"上传文件失败:{response.text}")
return False
def send_file(self, media_id):
"""
发送文件
:param media_id: 文件id通过下文的文件上传接口获取
"""
payload = {
"msgtype": "file",
"file": {
"media_id": media_id,
}
}
return self.send_message(payload)