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)
https://oapi.dingtalk.com/robot/send?access_token=XXXXXX×tamp=XXX&sign=XXX
https://oapi.dingtalk.com/robot/send?access_token=XXXXXX
{
"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())
{
"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())
{
"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())
{
"actionCard": {
"title": "乔布斯 20 年前想打造一间苹果咖啡厅",
"text": "![screenshot]",
"btnOrientation": "0",
"singleTitle": "打卡 阅读全文",
"singleURL": "http://xxxx"
},
"msgtype": "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())
{
"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"
}
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 "×tamp=" + 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
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)
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.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 表示本月的最后一天执行