前提
搭建釘釘應(yīng)答機器人,需要先準備或擁有以下權(quán)限:
- 釘釘企業(yè)的管理員或子管理員(如果不是企業(yè)管理員,可以自己創(chuàng)建一個企業(yè),很方便的)
- 有公網(wǎng)通信地址(內(nèi)網(wǎng)穿透也可以);
釘釘群機器人開發(fā)文檔:https://developers.dingtalk.com/document/app/overview-of-group-robots
創(chuàng)建「機器人」應(yīng)用
登錄「釘釘開發(fā)者后臺」,選擇「應(yīng)用開發(fā)」——「企業(yè)內(nèi)部開發(fā)」—— 「機器人」
![](/d/20211017/b50716d5d5b2c39569da67ad60084dd6.gif)
輸入好機器人的基本信息之后,就會生成創(chuàng)建一個「釘釘機器人」
![](/d/20211017/2f5d40e785c5d70ea38b7eb6a01c9eb5.gif)
我們的后端應(yīng)用通過其提供的「AgentId」、「AppKey」、「AppSecret」就能夠與釘釘機器人進行通信。
接收消息
在釘釘機器人的設(shè)定中,當用戶@機器人時,釘釘會通過機器人開發(fā)者的服務(wù)器地址,用 POST 請求方法把消息內(nèi)容發(fā)送出去,其 HTTP header 如下所示:
{
"Content-Type": "application/json; charset=utf-8",
"timestamp": "1577262236757",
"sign":"xxxxxxxxxx"
}
其中,timestamp
是消息發(fā)送時的時間戳,sign
是簽名值,我們需要對這兩個值進行校驗。
如果timestamp
與系統(tǒng)當前時間相差1小時以上,則為非法請求。
如果sign
簽名值與后臺計算的值不一樣,也為非法請求。
其中sign
簽名值的計算方法為:header中的timestamp + “\n” + 機器人的appSecret當做簽名字符串,使用HmacSHA256算法計算簽名,然后進行Base64 encode,得到最終的簽名值。
其 Python 實現(xiàn)代碼如下所示:
import hmac
import hashlib
import base64
timestamp = '1577262236757'
app_secret = 'this is a secret'
app_secret_enc = app_secret.encode('utf-8')
string_to_sign = '{}\n{}'.format(timestamp, app_secret)
string_to_sign_enc = string_to_sign.encode('utf-8')
hmac_code = hmac.new(app_secret_enc, string_to_sign_enc, digestmod=hashlib.sha256).digest()
sign = base64.b64encode(hmac_code).decode('utf-8')
print(sign)
其發(fā)送的消息格如下所示:
{
"conversationId": "xxx",
"atUsers": [
{
"dingtalkId": "xxx",
"staffId":"xxx"
}
],
"chatbotCorpId": "dinge8a565xxxx",
"chatbotUserId": "$:LWCP_v1:$Cxxxxx",
"msgId": "msg0xxxxx",
"senderNick": "楊xx",
"isAdmin": true,
"senderStaffId": "user123",
"sessionWebhookExpiredTime": 1613635652738,
"createAt": 1613630252678,
"senderCorpId": "dinge8a565xxxx",
"conversationType": "2",
"senderId": "$:LWCP_v1:$Ff09GIxxxxx",
"conversationTitle": "機器人測試-TEST",
"isInAtList": true,
"sessionWebhook": "https://oapi.dingtalk.com/robot/sendBySession?session=xxxxx",
"text": {
"content": " 你好"
},
"msgtype": "text"
}
其中,一些參數(shù)的說明如下圖所示:
![](/d/20211017/e1f6741f762cbc41060a5b888a2f737c.gif)
![](/d/20211017/eb291a719ef8961354ec1802f9d586e9.gif)
我們接收到釘釘?shù)南⒑?,可以根?jù)實際的業(yè)務(wù)需求解析出相應(yīng)字段的數(shù)據(jù)來進行處理。
響應(yīng)消息
釘釘機器人支持我們通過「text」、「Markdown」、「整體跳轉(zhuǎn)actionCard」、「獨立跳轉(zhuǎn)actionCard」和「feedCard」這5種消息類型發(fā)送消息到群里。
下面我們通過實際的代碼來展示接收釘釘機器人的消息,以及發(fā)送 5 種消息類型到釘釘群里。
創(chuàng)建一個后端應(yīng)用
接下來,我們通過創(chuàng)建一個 Django 應(yīng)用來接收的處理用戶發(fā)送給釘釘機器人的消息。
首先,創(chuàng)建一個 Django 項目和應(yīng)用:
django-admin startproject DdRobot
python manage.py startapp app_robot
![](/d/20211017/7217720295cdd83ec6f6e413ebdd7c37.gif)
然后打開 “C:\DdRobot\DdRobot\settings.py” 文件,修改 ALLOWED_HOSTS 變量:
將 app_robot 添加到 INSTALLED_APPS 變量列表中:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'app_robot',
]
創(chuàng)建校驗時間戳和簽名函數(shù)
因為釘釘機器人會在請求頭里面?zhèn)魅?code>timestamp時間戳和sign
簽名供我們對請求的合法性進行校驗,所以為了機器人的安全,我們需要編寫 2 個函數(shù)對它們進行校驗(在DdRobot/app_robot/views.py
文件中進行)。
首先,是時間戳的校驗:
def check_timestamp(timestamp):
now_timestamp = int(time.time()*1000)
if now_timestamp - int(timestamp) > 3600000:
return False
else:
return True
然后是簽名值的校驗,簽名值的計算方法和示例代碼釘釘已經(jīng)提供,我們借用即可:
def check_sign(timestamp,sign):
import hmac
import hashlib
import base64
# now_timestamp = str(int(time.time()*1000))
app_secret = 'teTLGS3xZVLp6Z99mXvgVpINOUyJqFsKJ3jLb7crFdjRsJ3_77E-kxhlIbBGbNjX'
app_secret_enc = app_secret.encode('utf-8')
string_to_sign = '{}\n{}'.format(timestamp, app_secret)
string_to_sign_enc = string_to_sign.encode('utf-8')
hmac_code = hmac.new(app_secret_enc, string_to_sign_enc, digestmod=hashlib.sha256).digest()
new_sign = base64.b64encode(hmac_code).decode('utf-8')
# print(sign)
# print(new_sign)
if sign == new_sign:
return True
else:
return False
對于這 2 個值,校驗成功我們都返回 True,校驗失敗我們都返回 False。
創(chuàng)建視圖函數(shù)
接著,我們創(chuàng)建一個視圖函數(shù),用來接收釘釘傳輸過來的消息,以及響應(yīng)給釘釘。
@csrf_exempt
def resp_dd(request):
pass
在 resp_dd() 函數(shù)中,首先從請求頭中讀取釘釘傳輸過來的時間戳和簽名值,然后進行校驗:
@csrf_exempt
def resp_dd(request):
timestamp = request.headers.get('timestamp','')
sign = request.headers.get('sign','')
# 校驗時間戳
if check_timestamp(timestamp) is False:
return JsonResponse({'status':False,'data':'非法請求'})
# 校驗簽名
if check_sign(timestamp,sign) is False:
return JsonResponse({'status':False,'data':'非法請求'})
若是時間戳和簽名值校驗無誤,我們繼續(xù)從請求 body 里面獲取消息信息:
@csrf_exempt
def resp_dd(request):
timestamp = request.headers.get('timestamp','')
sign = request.headers.get('sign','')
# 校驗時間戳
if check_timestamp(timestamp) is False:
return JsonResponse({'status':False,'data':'非法請求'})
# 校驗簽名
if check_sign(timestamp,sign) is False:
return JsonResponse({'status':False,'data':'非法請求'})
body = json.loads(request.body)
# 獲取用戶id
# user_id = body['senderStaffId'] 機器人上線后才會返回
user_id = body['senderId']
# 獲取發(fā)送的消息
msg_type = body['msgtype']
if msg_type == 'text':
content = body['text']['content']
目前釘釘機器人只支持text
文本內(nèi)容的消息接收,所以在此處我們只對消息類型為text
的消息進行處理。
獲取到釘釘機器人發(fā)送過來的信息之后,我們就可以根據(jù)自己的業(yè)務(wù)邏輯進行處理,然后返回特定的消息類型了。
在這里,我們只對消息進行簡單的處理:
- 當發(fā)送來的消息文本為
text
時,機器人回復(fù)文本消息;
- 當發(fā)送來的消息文本為
markdown
時,機器人回復(fù)一個 Markdown 的示例消息;
- 當發(fā)送來的消息文本為
整體跳轉(zhuǎn)
時,機器人回復(fù)一個「整體跳轉(zhuǎn)卡片」的示例消息;
- 當發(fā)送來的消息文本為
獨立跳轉(zhuǎn)
時,機器人回復(fù)一個「獨立跳轉(zhuǎn)卡片」的示例消息;
- 當發(fā)送來的消息文本為
feed
時,機器人回復(fù)一個「feedCard」的示例消息;
先來定義 5 個不同消息類型的響應(yīng)格式。
文本消息類型
# 響應(yīng)文字
resp_text = {
"at": {
"atUserIds": [
user_id
],
"isAtAll": False
},
"text": {
"content": "你剛剛發(fā)的消息是:[{}]".format(content)
},
"msgtype": "text"
}
Markdown消息類型:
# 響應(yīng)Markdown
resp_markdown = {
"msgtype": "markdown",
"markdown": {
"title":"州的先生機器人助理",
"text": "## 這是什么? \n 這是一個釘釘機器人 \n ![](https://zmister.com/wp-content/uploads/2019/06/login_logo.png)"
},
"at": {
"atUserIds": [
user_id
],
"isAtAll": False
}
}
整體跳轉(zhuǎn)卡片消息類型:
# 響應(yīng)整體跳轉(zhuǎn)actionCard
resp_actioncard = {
"msgtype": "actionCard",
"actionCard": {
"title": "州的先生 Python 實戰(zhàn)教程合集",
"text": "![](https://zmister.com/wp-content/uploads/2019/06/login_logo.png) \n #### 州的先生 Python 實戰(zhàn)教程合集 \n\n 學習Python的一個好方法就是用實際的項目來熟練語言",
"singleTitle" : "閱讀全文",
"singleURL" : "http://mrdoc.zmister.com"
}
}
獨立跳轉(zhuǎn)卡片消息類型:
resp_actioncard_2 = {
"msgtype": "actionCard",
"actionCard": {
"title": "州的先生 Python 實戰(zhàn)教程合集",
"text": "![](https://zmister.com/wp-content/uploads/2019/06/login_logo.png) \n #### 州的先生 Python 實戰(zhàn)教程合集 \n\n 學習Python的一個好方法就是用實際的項目來熟練語言",
"hideAvatar": "0",
"btnOrientation": "0",
"btns": [
{
"title": "去看看",
"actionURL": "http://mrdoc.zmister.com"
},
{
"title": "不感興趣",
"actionURL": "https://zmister.com/"
}
]
}
}
Feed卡片消息類型:
# 響應(yīng)feedCard
resp_feedcard = {
"msgtype": "feedCard",
"feedCard": {
"links": [
{
"title": "時代的火車向前開1",
"messageURL": "http://mrdoc.zmister.com",
"picURL": "https://img.alicdn.com/tfs/TB1NwmBEL9TBuNjy1zbXXXpepXa-2400-1218.png"
},
{
"title": "時代的火車向前開2",
"messageURL": "https://zmister.com/",
"picURL": "https://img.alicdn.com/tfs/TB1NwmBEL9TBuNjy1zbXXXpepXa-2400-1218.png"
}
]
}
}
其他的消息響應(yīng)空:
# 響應(yīng)空,不回復(fù)
resp_empty = {
"msgtype": "empty"
}
定義好幾個消息響應(yīng)類型數(shù)據(jù)后,我們對獲取到的 content 變量進行判斷返回響應(yīng)即可:
if content[1:] == 'text':
return JsonResponse(resp_text)
elif content[1:] == 'markdown':
return JsonResponse(resp_markdown)
elif content[1:] == '整體跳轉(zhuǎn)':
return JsonResponse(resp_actioncard)
elif content[1:] == '獨立跳轉(zhuǎn)':
return JsonResponse(resp_actioncard_2)
elif content[1:] == 'feed':
return JsonResponse(resp_feedcard)
else:
return JsonResponse(resp_empty)
這樣,我們這個釘釘機器人的后端處理函數(shù)就寫好了。
配置路由
寫好視圖函數(shù)之后,我們配置一下這個函數(shù)的 URL 路由。
在 “C:\DdRobot\DdRobot\urls.py” 文件中把內(nèi)容修改為如下代碼所示:
from django.contrib import admin
from django.urls import path
from app_robot import views
urlpatterns = [
path('admin/', admin.site.urls),
path('dd_robot/',views.resp_dd, name="resp_dd"),
]
這樣 http://ip地址/dd_robot/ 就是釘釘機器人的消息接收地址。
配置釘釘機器人
回到釘釘開發(fā)者平臺的網(wǎng)頁,在釘釘機器人的「開發(fā)管理」頁面,我們需要把服務(wù)器的出口IP 和釘釘機器人的消息接收地址填寫好:
![](/d/20211017/db527d63a2c021c3222c4965383d3549.gif)
調(diào)試釘釘機器人
在配置好機器人的「服務(wù)器出口IP」與「消息接收地址」之后,我們點擊網(wǎng)頁菜單的「版本管理與發(fā)布」,點擊「調(diào)試按鈕」,進入到釘釘機器人的調(diào)試群:
![](/d/20211017/97978f78275f1e86154c9d67fd222968.gif)
這回在「釘釘機器人名稱-TEST」的群里面添加創(chuàng)建的釘釘機器人:
![](/d/20211017/d4de4d2a0e2c6723f95145708660580a.gif)
我們可以在這個群里面@創(chuàng)建的群機器人進行測試:
![](/d/20211017/114f3655ba37917e0a5c8b0c1f65445c.gif)
在測試沒問題之后,我們就可以點擊「上線」按鈕。釘釘機器人上線之后,就可以在釘釘群內(nèi)添加這個機器人。
![](/d/20211017/06d19c5e62a9b3faab468795a860c102.gif)
這樣,我們就實現(xiàn)了從 0 到 1 使用 Python 開發(fā)釘釘群機器人。
基本的框架和流程大抵如此,具體的業(yè)務(wù)邏輯則需要根據(jù)不同的需求進行額外處理。比如:
查詢天氣,就得解析消息中的城市,然后請求天氣接口獲取天氣數(shù)據(jù),進行消息的響應(yīng);
淘寶客,就得解析消息中的文本,進行分詞或其他處理,再查詢數(shù)據(jù)庫中的商品優(yōu)惠券數(shù)據(jù)或是直接請求淘客接口獲取商品優(yōu)惠券數(shù)據(jù);
員工績效,就得接入釘釘?shù)膽?yīng)用開發(fā),借助釘釘開發(fā)的用戶接口進行數(shù)據(jù)查詢和響應(yīng)。
到此這篇關(guān)于教你如何使用Python開發(fā)一個釘釘群應(yīng)答機器人的文章就介紹到這了,更多相關(guān)Python開發(fā)釘釘群應(yīng)答機器人內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
您可能感興趣的文章:- 用Python selenium實現(xiàn)淘寶搶單機器人
- python通過Seq2Seq實現(xiàn)閑聊機器人
- python操作微信自動發(fā)消息的實現(xiàn)(微信聊天機器人)
- Python實現(xiàn)發(fā)票自動校核微信機器人的方法
- Python實現(xiàn)生活常識解答機器人