钉钉机器人-scheduler

一、创建钉钉机器人

1、安全设置

  • 自定义关键词
  • 最多可以设置10个关键词,消息中至少包含其中1个关键词才可以发送成功。
  • 加签
  • 把timestamp+"\n"+密钥当做签名字符串,使用HmacSHA256算法计算签名,然后进行Base64 encode,最后再把签名参数再进行urlEncode,得到最终的签名(需要使用UTF-8字符集)

  • 签名计算代码实例
import time
import hmac
import hashlib
import base64
import urllib.parse

timestamp = str(round(time.time() * 1000))
secret = 'this is secret' # 勾选加签的SEC开头的一串字符
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 = urllib.parse.quote_plus(base64.b64encode(hmac_code))
print(timestamp)
print(sign)
  • 把 timestamp和第一步得到的签名值拼接到URL中
https://oapi.dingtalk.com/robot/send?access_token=XXXXXX&timestamp=XXX&sign=XXX

  • IP地址(段):设定后,只有来自IP地址范围内的请求才会被正常处理。支持两种设置方式:IP地址和IP地址段,暂不支持IPv6地址白名单,格式如下

2、设置完成后

  • 复制机器人的Webhook,用于向这个群发送消息
https://oapi.dingtalk.com/robot/send?access_token=XXXXXX

二、机器人支持发送消息的格式

1、text格式

{
    "at": {
        "atMobiles":[
            "180xxxxxx"
        ],
        "atUserIds":[
            "user123"
        ],
        "isAtAll": false
    },
    "text": {
        "content":"我就是我, @XXX 是不一样的烟火"
    },
    "msgtype":"text"
}

实例-关键词

import json

import requests

url = 'https://oapi.dingtalk.com/robot/send?access_token=2f43cdbca48d42b266632aa52aaf2ef10794d5de625f8c2aa0a9b3c3d4eb99b3'
headers = {
    "Content-Type": "application/json;charset=utf-8"
}

json_ = {
    "at": {
        "isAtAll": True
    },
    "text": {
        "content": "打卡"
    },
    "msgtype": "text"
}
# 将dict转为str类型
string_text_msg = json.dumps(json_)
res = requests.post(url, data=string_text_msg, headers=headers, verify=False)
print(res.json())

2、link类型

{
    "msgtype": "link", 
    "link": {
        "text": "这个即将发布的新版本", 
        "title": "时代的火车向前开", 
        "picUrl": "", 
        "messageUrl": "https://www.dingtalk.com/s"
    }
}

实例-关键词

import json

import requests

url = 'https://oapi.dingtalk.com/robot/send?access_token=xx'
headers = {
    "Content-Type": "application/json;charset=utf-8"
}

json_ = {
    "msgtype": "link",
    "link": {
        "text": "这个即将发布的新版本",
        "title": "打卡 时代的火车向前开",
        "picUrl": "",
        "messageUrl": "https://www.dingtalk.com/s"
    }
}
string_text_msg = json.dumps(json_)
res = requests.post(url, data=string_text_msg, headers=headers, verify=False)
print(res.json())

\

3、Markdown格式

{
     "msgtype": "markdown",
     "markdown": {
         "title":"杭州天气",
         "text": "#### 杭州天气 @150XXXXXXXX \n > 9度,西北风1级,空气良89,相对温度73%\n > ![screenshot](https://img.alicdn.com/tfs/TB1NwmBEL9TBuNjy1zbXXXpepXa-2400-1218.png)\n > ###### 10点20分发布 [天气](https://www.dingtalk.com) \n"
     },
      "at": {
          "atMobiles": [
              "150XXXXXXXX"
          ],
          "atUserIds": [
              "user123"
          ],
          "isAtAll": false
      }
 }

实例-关键词

import json

import requests

url = 'https://oapi.dingtalk.com/robot/send?access_token=xx'
headers = {
    "Content-Type": "application/json;charset=utf-8"
}

json_ = {
    "msgtype": "markdown",
    "markdown": {
        "title": "上海天气",
        "text": "打卡 上海天气 @18056540512 \n > 9度,西北风1级,空气良89,相对温度73%\n > ![screenshot](https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fbpic.588ku.com%2Foriginal_pic%2F18%2F10%2F23%2F17e928fa76a63d0908fff97b978d7b27.jpg&refer=http%3A%2F%2Fbpic.588ku.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1629096430&t=eac289fecb0e78922c4e9b33d3d1de7e)\n > ###### 10点20分发布 [天气](http://weathernew.pae.baidu.com/weathernew/pc?query=%E4%B8%8A%E6%B5%B7%E5%A4%A9%E6%B0%94&srcid=4982&city_name=%E4%B8%8A%E6%B5%B7&province_name=%E4%B8%8A%E6%B5%B7) \n"
    },
    "at": {
        "atMobiles": [
            "18056540xxxx"
        ],
        "atUserIds": [
            "user123"
        ],
        "isAtAll": False
    }
}
string_text_msg = json.dumps(json_)
res = requests.post(url, data=string_text_msg, headers=headers, verify=False)
print(res.json())

4、整体跳转ActionCard类型

{
    "actionCard": {
        "title": "乔布斯 20 年前想打造一间苹果咖啡厅",
        "text": "![screenshot]",
        "btnOrientation": "0",
        "singleTitle": "打卡 阅读全文",
        "singleURL": "http://xxxx"
    },
    "msgtype": "actionCard"
}

5、独立跳转ActionCard类型

{
    "msgtype": "actionCard",
    "actionCard": {
        "title": "打卡 我 20 年前想打造一间苹果咖啡厅,而它正是 Apple Store 的前身",
        "text": "![screenshot](https://gimg2.baidu.com/image_search/src=http%3A%2F%2F5b0988e595225.cdn.sohucs.com%2Fimages%2F20200114%2F1d9277a398584cdcb1284f274532c064.jpeg&refer=http%3A%2F%2F5b0988e595225.cdn.sohucs.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1629096721&t=c0fc2015e8963ef750babd9a73522050) \n\n #### 乔布斯 20 年前想打造的苹果咖啡厅 \n\n Apple Store 的设计正从原来满满的科技感走向生活化,而其生活化的走向其实可以追溯到 20 年前苹果一个建立咖啡馆的计划",
        "btnOrientation": "0",
        "btns": [
            {
                "title": "去点饭",
                "actionURL": "http://hefan.youfantech.cn/w/#/login"
            },
            {
                "title": "不感兴趣",
                "actionURL": "http://hefan.youfantech.cn/w/#/login"
            }
        ]
    }
}

实例-关键词

import json

import requests

url = 'https://oapi.dingtalk.com/robot/send?access_token=xxx'
headers = {
    "Content-Type": "application/json;charset=utf-8"
}

json_ = {
    "msgtype": "actionCard",
    "actionCard": {
        "title": "打卡 我 20 年前想打造一间苹果咖啡厅,而它正是 Apple Store 的前身",
        "text": "![screenshot](https://gimg2.baidu.com/image_search/src=http%3A%2F%2F5b0988e595225.cdn.sohucs.com%2Fimages%2F20200114%2F1d9277a398584cdcb1284f274532c064.jpeg&refer=http%3A%2F%2F5b0988e595225.cdn.sohucs.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1629096721&t=c0fc2015e8963ef750babd9a73522050) \n\n #### 乔布斯 20 年前想打造的苹果咖啡厅 \n\n Apple Store 的设计正从原来满满的科技感走向生活化,而其生活化的走向其实可以追溯到 20 年前苹果一个建立咖啡馆的计划",
        "btnOrientation": "0",
        "btns": [
            {
                "title": "去点饭",
                "actionURL": "http://hefan.youfantech.cn/w/#/login"
            },
            {
                "title": "不感兴趣",
                "actionURL": "http://hefan.youfantech.cn/w/#/login"
            }
        ]
    }
}
string_text_msg = json.dumps(json_)
res = requests.post(url, data=string_text_msg, headers=headers, verify=False)
print(res.json())

6、FeedCard类型

{
    "msgtype":"feedCard",
    "feedCard": {
        "links": [
            {
                "title": "悠饭点餐1",
                "messageURL": "https://www.dingtalk.com/",
                "picURL": "https://gimg2.baidu.com/image_search/src=http%3A%2F%2F5b0988e595225.cdn.sohucs.com%2Fimages%2F20200114%2F1d9277a398584cdcb1284f274532c064.jpeg&refer=http%3A%2F%2F5b0988e595225.cdn.sohucs.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1629096721&t=c0fc2015e8963ef750babd9a73522050"
            },
            {
                "title": "打卡 悠饭点餐2",
                "messageURL": "https://www.dingtalk.com/",
                "picURL": "https://gimg2.baidu.com/image_search/src=http%3A%2F%2F5b0988e595225.cdn.sohucs.com%2Fimages%2F20200114%2F1d9277a398584cdcb1284f274532c064.jpeg&refer=http%3A%2F%2F5b0988e595225.cdn.sohucs.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1629096721&t=c0fc2015e8963ef750babd9a73522050"
            }
        ]
    }
}

实例-关键词

import json

import requests

url = 'https://oapi.dingtalk.com/robot/send?access_token=xx'
headers = {
    "Content-Type": "application/json;charset=utf-8"
}

json_ = {
    "msgtype":"feedCard",
    "feedCard": {
        "links": [
            {
                "title": "悠饭点餐1",
                "messageURL": "https://www.dingtalk.com/",
                "picURL": "https://gimg2.baidu.com/image_search/src=http%3A%2F%2F5b0988e595225.cdn.sohucs.com%2Fimages%2F20200114%2F1d9277a398584cdcb1284f274532c064.jpeg&refer=http%3A%2F%2F5b0988e595225.cdn.sohucs.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1629096721&t=c0fc2015e8963ef750babd9a73522050"
            },
            {
                "title": "打卡 悠饭点餐2",
                "messageURL": "https://www.dingtalk.com/",
                "picURL": "https://gimg2.baidu.com/image_search/src=http%3A%2F%2F5b0988e595225.cdn.sohucs.com%2Fimages%2F20200114%2F1d9277a398584cdcb1284f274532c064.jpeg&refer=http%3A%2F%2F5b0988e595225.cdn.sohucs.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1629096721&t=c0fc2015e8963ef750babd9a73522050"
            }
        ]
    }
}
string_text_msg = json.dumps(json_)
res = requests.post(url, data=string_text_msg, headers=headers, verify=False)
print(res.json())

三、常见问题

// 消息内容中不包含任何关键词
{
  "errcode":310000,
  "errmsg":"keywords not in content"
}

// timestamp 无效
{
  "errcode":310000,
  "errmsg":"invalid timestamp"
}

// 签名不匹配
{
  "errcode":310000,
  "errmsg":"sign not match"
}

// IP地址不在白名单
{
  "errcode":310000,
  "errmsg":"ip X.X.X.X not in whitelist"
}

四、集成

  • PostMan -- Newman、Monitor定时自动监控接口
  • JMeter -- Jenkins、Shell..
  • Python -- sleep、threading模块中的Timer、sched模块

https://www.cnblogs.com/fengff/p/11011000.html

六、实例讲解

  • 钉钉接口

import json
import urllib
import requests
import time
import hmac
import hashlib
import base64
from requests.packages.urllib3.exceptions import InsecureRequestWarning

requests.packages.urllib3.disable_warnings(InsecureRequestWarning)


class Ding:
    """
    钉钉机器人
    """

    def __init__(self):
        # 测试群-钉钉机器人的webhook地址
        self.url = 'https://oapi.dingtalk.com/robot/send?access_token=xxx'
        # secret
        self.secret = 'xxx'

    def check_secret(self, secret):
        """
        生成secret加签
        :param secret:
        :return:
        """
        timestamp = str(round(time.time() * 1000))
        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 = urllib.parse.quote_plus(base64.b64encode(hmac_code))
        return "&timestamp=" + timestamp + "&sign=" + sign

    def send_message(self, message=None):
        """
        发送钉钉消息
        :param message: 发送内容
        :return:
        """
        test_url = self.url + self.check_secret(f"{self.secret}")

        headers = {
            "Content-Type": "application/json;charset=utf-8"
        }

        message = message
        string_text_msg = {
            "msgtype": "text",
            "text": {"content": message},
            "at": {
                "isAtAll": 1  # 如果需要@所有人,这些写1
            }
        }
        string_text_msg = json.dumps(string_text_msg)
        with requests.post(test_url, data=string_text_msg, headers=headers, verify=False) as res:
            return res

    def send_link(self, message_url):
        """
        发送钉钉链接
        :param message_url: 指定的url
        :return:
        """
        test_url = self.url + self.check_secret(f"{self.secret}")

        headers = {
            "Content-Type": "application/json;charset=utf-8"
        }

        string_link_msg = {
            "msgtype": "link",
            "link": {
                "text": "今天吃点啥呢?去悠饭看看吧~",
                "title": "悠饭点饭啦~",
                "picUrl": "https://tvax4.sinaimg.cn/crop.0.0.891.891.180/006Gos8ply8fxgn9viu2fj30ot0orgna.jpg?KID=imgbed,tva&Expires=1626279933&ssig=dsK87pjAuN",
                "messageUrl": message_url
            }
        }
        string_text_msg = json.dumps(string_link_msg)
        with requests.post(test_url, data=string_text_msg, headers=headers, verify=False) as res:
            return res
  • Task任务
from common.robot import Ding
import datetime
import pytz

run_time = datetime.datetime.now(pytz.timezone('PRC')).strftime("%Y-%m-%d %H:%M:%S")


def lunch():
    """
    提醒
    :return:
    """
    remind = "朋友们,可以准备准备去吃饭啦~"
    Ding().send_message(f"饭点时间到了  {remind}")
    return remind


def dinner():
    """
    提醒晚上点饭
    :return:
    """
    link = 'http://xxx'
    Ding().send_link(link)
  • 执行方式一:
from task.youfan import lunch, dinner
import datetime
import pytz

from apscheduler.schedulers.blocking import BlockingScheduler

run_time = datetime.datetime.now(pytz.timezone('PRC')).strftime("%Y-%m-%d %H:%M:%S")

scheduler = BlockingScheduler(timezone="Asia/Shanghai")
print("start...")
scheduler.add_job(lunch, 'cron', day_of_week='mon-fri', hour=11, minute=30, second=00)
scheduler.add_job(dinner, 'cron', day_of_week='mon-fri', hour=16, minute=30, second=00)
scheduler.start()
print("end...")
  • 执行方式二:
# 在具体的函数中添加 装饰器
from common.robot import Ding
import datetime
import pytz
from apscheduler.schedulers.blocking import BlockingScheduler

run_time = datetime.datetime.now(pytz.timezone('PRC')).strftime("%Y-%m-%d %H:%M:%S")
scheduler = BlockingScheduler(timezone="Asia/Shanghai")


@scheduler.scheduled_job('cron', day_of_week='mon-fri', hour=11, minute=30, second=00)
def lunch():
    """
    提醒
    :return:
    """
    remind = "朋友们,可以准备准备去吃饭啦~"
    Ding().send_message(f"饭点时间到了  {remind}")
    return remind


@scheduler.scheduled_job('cron', day_of_week='mon-fri', hour=16, minute=30, second=00)
def dinner():
    """
    提醒晚上点饭
    :return:
    """
    link = 'http://hefan.youfantech.cn/w/#/login'
    Ding().send_link(link)

七、scheduler简单使用

import time
from apscheduler.schedulers.blocking import BlockingScheduler
 
def my_job():
    """
    定义一个方法
    """
    print time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))
 
# 创建一个BlockingScheduler(调度器)对象
sched = BlockingScheduler()
# 添加一个作业job_store,第一个参数是可调度的执行,第二个是调用方式(interval,date,cron),第三个是interval中指定的时间
sched.add_job(my_job, 'interval', seconds=5)

try:
    # 启动调度器,注意:启动后就不能修改配置参数了,运行程序需要写在start方法前面。
    sched.start()
except (KeyboardInterrupt, SystemExit):
    sched.shutdown()
  • sched = BlockingScheduler()
sched.add_job(func,'interval','date','cron')
# date

from datetime import datetime
from datetime import date
from apscheduler.schedulers.blocking import BlockingScheduler


def job(text):
    print(text)


scheduler = BlockingScheduler(timezone="Asia/Shanghai")
# 在 2019-8-30 运行一次 job 方法
# args=['这个是方法的一个入参']

scheduler.add_job(job, 'date', run_date=date(2021, 7, 20), args=['text1'])
# 在 2019-8-30 01:00:00 运行一次 job 方法

scheduler.add_job(job, 'date', run_date=datetime(2021, 7, 20, 11, 38, 0), args=['text2'])
# 在 2019-8-30 01:00:01 运行一次 job 方法

scheduler.add_job(job, 'date', run_date='2021-7-20 11:39:00', args=['text3'])

scheduler.start()

sched.add_job(func,'interval','date','cron')
# interval


# 在 2021-07-19 20:15:00至2021-07-20 22:17:00期间,每隔1分30秒 运行一次 job 方法
scheduler.add_job(job, 'interval', minutes=1, seconds = 30, start_date='2019-08-29 22:15:00', end_date='2019-08-29 22:17:00')

sched.add_job(func,'interval','date','cron')
# cron

# 在每天22点,每隔 1分钟 运行一次 job 方法
scheduler.add_job(job, 'cron', hour=22, minute='*/1')
# 在每天22和23点的25分,运行一次 job 方法
scheduler.add_job(job, 'cron', hour='22-23', minute='25')

# 支持表达式的

*					表示任何

*/a				表示每a,执行一次

a-b				表示 a至b的范围内

a-b/c			表示a-b范围内每执行一次

last x		表示本月最后一个工作日执行

last			表示本月的最后一天执行

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值