自动化系列(四)Python实现钉钉机器人

定期数据需求除了以邮件的形式交付外,也可以发送到工作群里通知相关人员及时关注,本文将介绍如何推送数据到钉钉群里并@相关人员及时关注。

添加自定义机器人

  • 创建群聊:右上角+号 -> 选择任意一个场景群 -> 点击创建即可
  • 添加群机器人:点击群设置 -> 群智能助手 -> 添加机器人 -> 选择自定义 -> 添加后安全模式选择加签 -> 完成
  • 查看Webhook和加签密钥:点击群设置 -> 群智能助手 -> 点击刚才创建的自定义机器人。

发送文本类消息

# 导入相关库
import json
import hashlib
import base64
import hmac
import os
import time
import requests
from urllib.parse import quote_plus
# 构造函数生成timestamp和sign
def creat_sign(secret):
    timestamp = str(round(time.time() * 1000))
    se = secret.encode('utf-8')
    tse = '{}\n{}'.format(timestamp, secret)
    tsee = tse.encode('utf-8')
    hmac_code = hmac.new(se, tsee, digestmod=hashlib.sha256).digest()
    sign = quote_plus(base64.b64encode(hmac_code))
    
    return timestamp,sign
# 发送文本消息
def send_text(token, secret, content, Mobiles=None, UserIds=None, isAtAll=False):
    
    # 构造post参数
    url = "https://oapi.dingtalk.com/robot/send"
    headers = {'Content-Type': 'application/json'}
    timestamp,sign = creat_sign(secret)
    params = {
                'access_token': token,
                "sign": sign,
                "timestamp":timestamp
            }
    
    # 构造数据集
    data = {
                "at": {
                    "atMobiles":Mobiles,
                    "atUserIds":UserIds,
                    "isAtAll": isAtAll
                },
                "text": {
                    "content":content
                },
                "msgtype":"text"
            }
    
    # 发送消息
    requests.post(
            url=url,
            data=json.dumps(data),
            params=params,
            headers=headers
        )
# 发送markdown消息
def send_md(token, secret, title, text, Mobiles=None, UserIds=None, isAtAll=False):
    
    # 构造post参数
    url = "https://oapi.dingtalk.com/robot/send"
    headers = {'Content-Type': 'application/json'}
    timestamp,sign = creat_sign(secret)
    params = {
                'access_token': token,
                "sign": sign,
                "timestamp":timestamp
            }
    
    # 构造数据集
    data = {
                "at": {
                    "atMobiles":Mobiles,
                    "atUserIds":UserIds,
                    "isAtAll": isAtAll
                },
                "markdown": {
                    "title":title
                    ,'text':text
                },
                "msgtype":"markdown"
            }
    
    # 发送消息
    requests.post(
            url=url,
            data=json.dumps(data),
            params=params,
            headers=headers
        )
token = '****' # Webhook里的token
secret = '****' # 加签里的密钥
send_text(token, secret, content='HsuHeinrich', Mobiles=[1****])
send_md(token, secret, title="测试md", text="# 一级标题 \n 微信搜索HsuHeinrich,发现更多精彩👍", isAtAll=True)

结果如下图:

java获取企业微信在线文档的数据 python企业微信获取群聊信息_ide

UserIds为钉钉用户的数字ID,非钉钉号,一般只有企业管理员才能看到。所以常用手机号来@相关人员。

发送文件

钉钉正常无法推送文件信息,需要管理员登陆开发者后台创建相关的小程序。感兴趣的同学可以根据钉钉推送文件这个博客自行尝试,这里介绍一种曲线的方式。

我们知道,markdown可以添加图片连接,因此我们只需要将数据表转换成图片,然后将该图片上传至图床并获得链接,最后将图片链接加到markdown消息里就可以了,方法总比困难多~

import pandas as pd
from faker import Faker
from faker.providers import BaseProvider, internet 
from random import randint

# 构造pandas数据
# 自定义fake
fake = Faker('zh_CN')
class MyProvider(BaseProvider):
    def myCityLevel(self):
        cl = ["一线", "二线", "三线", "四线+"]
        return cl[randint(0, len(cl) - 1)]
    def myGender(self):
        g = ['F', 'M']
        return g[randint(0, len(g) - 1)]
    def myDevice(self):
        d = ['Ios', 'Android']
        return d[randint(0, len(d) - 1)]
fake.add_provider(MyProvider)

# 构造假数据
uid=[]
cityLevel=[]
gender=[]
device=[]
age=[]
activeDays=[]
for i in range(10):
    uid.append(i+1)
    cityLevel.append(fake.myCityLevel())
    gender.append(fake.myGender())
    device.append(fake.myDevice())
    age.append(fake.random_int(min=18, max=65))
    activeDays.append(fake.random_int(min=0, max=180))
    
raw_data= pd.DataFrame({'uid':uid,
                        'cityLevel':cityLevel,
                        'gender':gender,
                        'device':device,
                        'age':age,
                        'activeDays':activeDays,
                       })

raw_data.head()

uid

cityLevel

gender

device

age

activeDays

0

1

一线

F

Android

61

151

1

2

一线

F

Ios

32

140

2

3

三线

M

Android

58

122

3

4

三线

M

Ios

41

94

4

5

三线

M

Ios

44

19

# 通过table转图片
from pandas.plotting import  table
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签

# 设置图片参数
fig = plt.figure(dpi=800)
ax = fig.add_subplot(111, frame_on=False)
ax.xaxis.set_visible(False)  # 隐藏x轴
ax.yaxis.set_visible(False)  # 隐藏y轴
# df存为图片
table(ax, raw_data, loc='center')
plt.savefig('df2img.jpg')

java获取企业微信在线文档的数据 python企业微信获取群聊信息_自动化_02

# 默认的表格着实不太好看,通过style美化后,利用dataframe_image转图片
import dataframe_image as dfi

# 通过style美化df
# 增加色阶、标题,隐藏索引、uid列
title = '活跃统计'
df = raw_data.style\
    .background_gradient(cmap='Pastel1',subset=['activeDays'])\
    .set_caption(title)\
    .hide_index()\
    .hide_columns(subset=['uid'])

# 导出图片,留着后用
dfi.export(obj=df, filename='df2img.jpg', fontsize=30, max_cols=-1, max_rows=-1)
# 上传图片至gitee的个人图床,并获取图片链接
import base64,time,hashlib
import requests

def img2Gitee(token, owner, repo, file_path, message='pic'):
    '''上传图片至gitee的个人图床
    token: 图床设置时的token
    owner: 仓库所有者
    repo: 仓库名
    file_path: 文件地址(含文件名)
    message: 不重要,是commit的信息。默认为pic
    
    return: 图片url链接
    '''
    # 读取图片
    with open(file_path, "rb") as pic:
        base64_data = base64.b64encode(pic.read()).decode(encoding = "utf-8")
    # 构造上传文件名
    path = f"{time.strftime('%Y%m%d%H%M%S')}{hashlib.md5(base64_data.encode('utf-8')).hexdigest()}.{file_path.split('.')[1]}"
    # 生成上传url
    upload_url = "https://gitee.com/api/v5/repos/%s/%s/contents/" % (owner, repo)
    url = f"{upload_url}{path}"
    # 上传至gitee
    result = requests.post(url, data = {
            "access_token": token,
            "content": base64_data,
            "message": message
        }).json()
    # 获取图片线上url
    content = result.get("content",None)
    if content:
        pic_url = content.get("download_url", None)
        if pic_url:
            return pic_url
    return pic_url

img_token='****' # 你的gitee图床的token
owner = "HsuHeinrich" # gitee仓库的owner
repo = "images" # gitee仓库的名称
file_path = "df2img.jpg"

pic_url=img2Gitee(img_token, owner, repo, file_path)

# 将图片链接插入markdown
send_md(token, secret, title="数据表转图片", text=f"![img]({pic_url})", isAtAll=True)

最终结果如下:

java获取企业微信在线文档的数据 python企业微信获取群聊信息_ide_03

style可以生成更加美观的数据框,可以参考内置样式或者官方手册

如何创建自己的gitee图床,可以参考开篇中提到的利用Typora+PicGo+Gitee进行Markdown写作

其他类型消息

日常工作最常见的就是文本消息和文件推送,当然,钉钉群机器人还支持其他类型的消息,例如链接、各种卡片。只要按照钉钉开放文档定义数据类型,替换上面函数定义的data即可,喜欢折腾的同学可以自行尝试~

总结

结合上期的定邮,就可以实现定时在工作群里推送消息或数据了,以后再看谁敢说你数据推送不及时。

共勉~