python實現微信自動回覆機器人+查看別人撤回的消息(部署到雲服務器)

python實現微信自動回覆機器人+查看別人撤回的消息(部署到雲服務器)

聲明:僅供技術交流,請勿用於非法用途,如有其它非法用途造成損失,和本博客無關

前言

  • 首先你的微信號能夠登錄網頁版微信,才能打造你的專屬個人微信號機器人,點擊跳轉網頁版微信登錄頁面
  • 類似的文章網上也都有,其實我也是受到別的文章的一些啓發,因爲不是每個人都想實現同樣的功能的,直接套用別人的代碼不嚴謹而且bug太多,於是就想自己動手從零開始實現一個屬於自己的微信機器人,不過呢,也大同小異吧。
  • 算下來前前後後加上寫這篇博客花了大概一週的時間,因爲都是用零零散散的時間進行開發以及測試然後修改bug再加功能再開發,這麼一個循環,從一開始的只能回覆消息、到現在能夠:回覆特定羣聊消息、特殊羣聊特殊處理、回覆表情包、查看所有別人撤回的消息以及操控微信機器人等等等等。

好的,廢話不多說,接下來就開始吧。

一、準備

  1. python3.7(重中之重,後面會解釋)
  2. itchat(直接用pip命令安裝即可)
  3. jupyter notebook(隨意,用你最喜歡的編譯器即可,不過最後還是要把代碼放在一個py文件裏)
  4. NLP實現一個聊天機器人(限於本人沒學過自然語言處理,並且空閒時間也不多,其實就是因爲太難了。。那就只能先調用別人的接口啦)

二、開始

ps:詳情請看代碼註釋,若不想分函數來看也可以直接看完整代碼

  • 定義獲取好友的暱稱和好友的備註函數
def get_friendname():
    friends_name={} #存儲好友的微信暱稱和備註
    friends=itchat.get_friends(update=True) #返回的是一個存儲所有好友信息的列表,每個好友的信息都是用一個字典來存放
    for friend in friends[1:]: #第一個爲自己,所以這裏排除了自己
        friends_name.update({friend['UserName']:{'nickname':friend['NickName'],'remarkname':friend['RemarkName']}})
    return friends_name
  • 定義羣聊信息的函數
    ps:這個獲取羣聊信息的函數只能讀取到你保存到通訊錄中的羣聊,那些沒有保存到通訊錄中的是顯示不出來的,不過不影響獲取羣聊信息,它只是沒有顯示而已,後面添加特定羣聊就算是沒有保存通訊錄的都是可以添加的,一樣可以回覆特定羣聊。
def get_username():
    chatrooms=itchat.get_chatrooms(update=True) #返回的是一個所有羣聊的信息的列表,每個羣聊信息都是用一個字典來存放
    user_name=[] #接收特定羣聊@本人的消息,並回復;存放特定羣聊的username
    all_user_name=[] #存放全部羣聊的username
    vip=[] #存放特定羣聊的名稱
    if os.path.exists('./vip.txt'):
        with open('./vip.txt','r',encoding='utf-8') as f:
            for i in f.read().split('\n')[:-1]:
                vip.append(i)
    for chatroom in chatrooms:
        all_user_name.append(chatroom['UserName'])
        if chatroom['NickName'] in vip:
            user_name.append(chatroom['UserName'])
    return all_user_name,user_name,vip
def get_response(msg):
    url=''#看到請求url好像涉及到一些sessionid、userid等信息,可能直接複製會用不了什麼的,所以你們直接去分析一下網頁即可拿到啦,把content參數format成msg即可
    headers={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Safari/537.36'}
    r=requests.get(url,headers=headers)
    response=re.findall('"body":{"fontStyle":0,"fontColor":0,"content":"(.*?)","emoticons":{}}}',r.text)[1].replace('\\r\\n','')
    return response
  • 定義獲取聊天機器人詞窮時要回復消息的函數
def get_words():
    words=[]
    if os.path.exists('./words.txt'):
        with open('./words.txt','r',encoding='utf-8') as f:
            for i in f.read().split('\n')[:-1]:
                words.append(i)
    return words
  • 定義註冊消息函數(重頭戲)
# 包括文本(表情符號)、位置、名片、通知、分享、圖片(表情包)、語音、文件、視頻
@itchat.msg_register([TEXT,MAP,CARD,SHARING,PICTURE,RECORDING,ATTACHMENT,VIDEO],isFriendChat=True,isGroupChat=True) #監聽個人消息和羣聊消息
def download_reply_msg(msg):
    global flag,sj,isrun,use_info #flag判斷要不要進入鬥圖模式,sj控制鬥圖的時間長短,isrun判斷是否啓動自動回覆機器人(默認運行中),通過向傳輸助手發指令來控制,use_info說明文檔
    all_user_name,user_name,vip=get_username()#每次接受消息時要拿到當前規定的羣聊和特定羣聊信息,後面用來分別做處理
    words=get_words() #拿到當前自定義回覆消息的信息
    now_time=int(time.time()) #記錄獲取這條消息的時間,後面處理撤回消息的時候用到
    b=[] #用來記錄已經過了可以撤回的時間的消息
    if len(msg_dict) != 0:
        for key,value in msg_dict.items():
            if (now_time - value['time']) >= 125: #經過驗證發現消息2分鐘之內才能撤回,這裏爲了保險起見加多5秒鐘
                b.append(key)
        for eachkey in list(msg_dict.keys()):
            if eachkey in b: #要是過了撤回時間的消息是文件類型的就把它們刪除,避免增加不必要的磁盤空間,盤大的請隨意
                if 'file' in msg_dict[eachkey].keys():
                    os.remove(msg_dict[eachkey]['file'])
                msg_dict.pop(eachkey)
#---------------------------------------------------------
#下面開始存儲各類消息,主要是用來查看別人撤回的消息,後面會用到
    if msg['Type'] in [MAP,SHARING]: #地圖或者分享
        old_id=msg['MsgId']
        link=msg['Url']
        msg_dict.update({old_id:{'type':msg['Type'],'data':link,'time':now_time}})
    elif msg['Type'] in [PICTURE,RECORDING,ATTACHMENT,VIDEO]:
        if msg['ToUserName'] != 'filehelper': # 避免給文件傳輸助手發文件也傳入字典,沒必要而且傳入字典只是爲了防止撤回,況且它是沒有撤回的
            old_id=msg['MsgId']
            file='./保存的文件/'+ msg['MsgId'] + '.' + msg['FileName'].split('.')[-1]
            msg['Text'](file)
            msg_dict.update({old_id:{'type':msg['Type'],'file':file,'time':now_time}})
        else:
            file='./保存的文件/'+ msg['FileName']
            msg['Text'](file)
    elif msg['Type'] == CARD: #名片
        old_id=msg['MsgId']
        link=re.findall('bigheadimgurl="(.*)" smallheadimgurl',str(msg))[0]
        msg_content = '來自' + msg['RecommendInfo']['Province'] +msg['RecommendInfo']['City'] + '的'+ msg['RecommendInfo']['NickName'] + '的名片'    #內容就是推薦人的暱稱和性別
        if msg['RecommendInfo']['Sex'] == 1:
            msg_content += ',男的'
        else:
            msg_content += ',女的'
        msg_dict.update({old_id:{'type':msg['Type'],'head':link,'data':msg_content,'time':now_time}})
    elif msg['Type'] == TEXT: #文本
        old_id=msg['MsgId']
        text=msg['Text']
        msg_dict.update({old_id:{'type':msg['Type'],'data':text,'time':now_time}})
#---------------------------------------------------------
#下面是自動回覆消息的(一切回覆邏輯都在這裏)
    if msg['ToUserName'] != 'filehelper': # 避免給文件傳輸助手發消息也自動回覆
        if isrun == '運行中......': #操控機器人的,想停就停,想啓動就啓動,不用關掉程序,而且不影響查看撤回消息的功能
            if msg['FromUserName'] in all_user_name:
                if msg['FromUserName'] in user_name: #當消息來自特定羣聊時,下面代碼纔會執行
                    if sj is not None:
                        if int(time.time()) - sj >= 900: #鬥圖時間:15分鐘
                            flag=0
                            sj=None
                    if (msg['isAt'] is True)&(msg['Type'] == TEXT):
                        myname='@' + re.findall("'Self'.*?'DisplayName': '(.*?)', 'KeyWord'",str(msg))[0] if re.findall("'Self'.*?'DisplayName': '(.*?)', 'KeyWord'",str(msg))[0] != '' else '這裏填你自己的微信暱稱'
                        if '帥哥來鬥圖' in msg['Text']:
                            flag=1
                            sj=int(time.time())
                            num=random.choice(os.listdir('./表情包'))
                            msg.user.send('@img@./表情包/{}'.format(num))
                            return None
                        reply = get_response(msg['Text'].replace(myname,''))
                        if 'I am' in reply:
                            reply=reply.replace('小i機器人','your father')
                        if '小i' in reply: #這個我是不想讓別人知道是小i機器人,才把它換掉的,你想換成什麼隨你,不換也行,就把這段代碼刪除即可
                            reply=reply.replace('小i','你爸爸')
                        if '機器人' in reply:
                            reply=reply.replace('機器人','')
                        if '輸入' in reply:
                            if flag == 0:
                                reply='有種來鬥圖,輸入“帥哥來鬥圖”即可。'
                            else:
                                reply=random.choice(words)
                        itchat.send('@%s\u2005%s' % (msg['ActualNickName'], reply), msg['FromUserName'])
                    if (msg['Type'] == PICTURE)&(flag == 1):
                        num=random.choice(os.listdir('./表情包'))
                        msg.user.send('@img@./表情包/{}'.format(num))
                else: #這裏是當消息來自不是特定羣聊時,要執行的代碼
                    if msg['Type'] == TEXT:
                        if '收到請回復' in msg['Text']:
                            return '收到'
            else: #下面是處理個人消息的
            	#經過測試發現如果自己手動發消息到新建的羣中,也會觸發下面自動回覆的代碼,於是就要排除這個bug用下面第一個if語句
            	if msg['FromUserName'] == itchat.search_friends(nickName='這裏填你自己的微信暱稱')[0]['UserName']:
                    return None
                if msg['Type'] == TEXT: #下面跟處理羣聊的時候差不多,就不重複了嘻嘻
                    reply = get_response(msg['Text'])
                    if 'I am' in reply:
                        reply=reply.replace('小i機器人','your father')
                    if '小i' in reply:
                        reply=reply.replace('小i','你爸爸')
                    if '機器人' in reply:
                        reply=reply.replace('機器人','')
                    if '輸入' in reply:
                        reply=random.choice(words)
                    msg.user.send(reply+'\n                                    [不是本人]') # 36個空格
                elif msg['Type'] == PICTURE: #表情包回覆
                    num=random.choice(os.listdir('./表情包'))
                    msg.user.send('@img@./表情包/{}'.format(num))
                elif msg['Type'] == RECORDING:
                    msg.user.send('請打字和我交流,謝謝。'+'\n                                    [不是本人]')
#---------------------------------------------------------
#下面是用來控制機器人的(給文件傳輸助手發指令)代碼很簡單,也很清晰
    else:
        if msg['Type'] == TEXT:
            if '添加vip' in msg['Text']:
                with open('./vip.txt','a',encoding='utf-8') as f:
                    f.write(msg['Text'][5:])
                    f.write('\n')
            if '查看vip' in msg['Text']:
                now_vip='\n'.join(vip)
                itchat.send('當前的vip羣有:\n{0}'.format(now_vip), toUserName='filehelper')
            if '刪除vip' in msg['Text']:
                if os.path.exists('./vip.txt'):
                    with open('./vip.txt','r',encoding='utf-8') as f1:
                        lines=f1.readlines()
                        with open('./vip.txt','w',encoding='utf-8') as f2:
                            for line in lines:
                                if msg['Text'][5:] != line.strip():
                                    f2.write(line)
            if '清空vip' in msg['Text']:
                with open('./vip.txt','w',encoding='utf-8') as f:
                    f.flush()
                    
            if '添加words' in msg['Text']:
                with open('./words.txt','a',encoding='utf-8') as f:
                    f.write(msg['Text'][7:])
                    f.write('\n')
            if '查看words' in msg['Text']:
                now_words='\n'.join(words)
                itchat.send('當前的words有:\n{0}'.format(now_words), toUserName='filehelper')
            if '刪除words' in msg['Text']:
                if os.path.exists('./words.txt'):
                    with open('./words.txt','r',encoding='utf-8') as f1:
                        lines=f1.readlines()
                        with open('./words.txt','w',encoding='utf-8') as f2:
                            for line in lines:
                                if msg['Text'][7:] != line.strip():
                                    f2.write(line)
            if '清空words' in msg['Text']:
                with open('./words.txt','w',encoding='utf-8') as f:
                    f.flush()
            if '停止機器人' in msg['Text']:
                isrun='已停止!'
            if '啓動機器人' in msg['Text']:
                isrun='運行中......'
            if '查看機器人' in msg['Text']:
                itchat.send(isrun, toUserName='filehelper')
            if 'robot' in msg['Text']:
                itchat.send(use_info, toUserName='filehelper')
  • 定義監控撤回消息的函數(別人撤回的消息都會發到文件傳輸助手中)
@itchat.msg_register(NOTE,isFriendChat=True,isGroupChat=True)
def get_note(msg):
    if '撤回了一條消息' in msg['Text']:
        if '你撤回了一條消息' in msg['Text']:
            return None
        new_id=re.findall('<msgid>(\d+)</msgid>',str(msg))[0]
        public_time=time.strftime('%Y-%m-%d %H:%M:%S',time.gmtime(msg['CreateTime']+28800))
        data=msg_dict[new_id]
        nickname=re.findall("'UserName': '@[a-zA-Z0-9]+', 'NickName': '(.*?)', 'HeadImgUrl'",str(msg))[0]
        if len(nickname) > 100:
            friends_name=get_friendname()
            #羣名這句我覺得還會有bug,由於測試的時候只在2個人的羣中測試,多個的話可能會出bug,這個後面再說吧,反正我24小時掛着,有bug咱再說哈哈
            qun=re.findall("'NickName': '.*",re.findall("'UserName': '@[a-zA-Z0-9]+', 'NickName': '(.*)', 'HeadImgUrl'",str(msg))[0][-100:])[0].replace("'NickName': '",'')
            an=msg['ActualNickName']
            nickname='{0}在{1}羣中'.format(an,qun)
            if msg['ActualUserName'] in friends_name.keys():
                if friends_name[msg['ActualUserName']]['remarkname'] != '':
                    nickname='{0}({1})在{2}羣中'.format(an,friends_name[msg['ActualUserName']]['remarkname'],qun)
                else:
                    nickname='{0}({1})在{2}羣中'.format(an,friends_name[msg['ActualUserName']]['nickname'],qun)
        if data['type'] == MAP:
            itchat.send('%s在%s撤回了一個位置,其位置:\n%s'%(nickname,public_time,data['data']),toUserName='filehelper')
        elif data['type'] == CARD:
            itchat.send('%s在%s撤回了一個名片,名片信息:\n%s,其頭像:'%(nickname,public_time,data['data']),toUserName='filehelper')
            itchat.send('%s'%(data['head']),toUserName='filehelper')
        elif data['type'] == SHARING:
            itchat.send('%s在%s撤回了一個分享,其鏈接:\n%s'%(nickname,public_time,data['data']),toUserName='filehelper')
        elif data['type'] == TEXT:
            itchat.send('%s在%s撤回了一個信息,其內容:\n%s'%(nickname,public_time,data['data']),toUserName='filehelper')
        elif data['type'] in [PICTURE,RECORDING,ATTACHMENT,VIDEO]:
            itchat.send('%s在%s撤回了一張圖片或者一個表情或者一段語音或者一個視頻又或者一個文件,如下:'%(nickname,public_time),toUserName='filehelper')
            itchat.send('@%s@%s'%({'Picture': 'img', 'Video': 'vid'}.get(data['type'], 'fil'),data['file']),toUserName='filehelper')
  • 到這裏已經定義好了全部所需要的函數了,接下來就是文件的創建和表情包的收集,目前表情包是手動發表情讓程序自動保存下來,其實可以定義一個添加表情的函數的,這個我後面會做出來,所以先這樣吧,收集自定義表情包的函數如下:

ps:這個函數要另外單獨運行(親測商城裏的表情包是保存不了的)

@itchat.msg_register(PICTURE) #只需要註冊圖片消息類型就可以了
def download_msg(msg):
    global q  #給文件傳輸助手發送你想要保存的表情包即可
    if msg['ToUserName'] == 'filehelper':
        msg['Text']('./表情包/' + str(q) + '.' + msg['FileName'].split('.')[-1])
        q+=1
q=1
itchat.auto_login(hotReload=True)
if not os.path.exists('./表情包'):
	os.makedirs('./表情包')
itchat.run()

三、完整代碼

import requests
import itchat
from itchat.content import *
import urllib
import random
import re
import os
import time

def get_response(msg):
    url=''#看到請求url好像涉及到一些sessionid、userid等信息,可能直接複製會用不了什麼的,所以你們直接去分析一下網頁即可拿到啦,把content參數format成msg即可
    headers={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Safari/537.36'}
    r=requests.get(url,headers=headers)
    response=re.findall('"body":{"fontStyle":0,"fontColor":0,"content":"(.*?)","emoticons":{}}}',r.text)[1].replace('\\r\\n','')
    return response

def get_words():
    words=[]
    if os.path.exists('./words.txt'):
        with open('./words.txt','r',encoding='utf-8') as f:
            for i in f.read().split('\n')[:-1]:
                words.append(i)
    return words

def get_friendname():
    friends_name={} #存儲好友的微信暱稱和備註
    friends=itchat.get_friends(update=True) #返回的是一個存儲所有好友信息的列表,每個好友的信息都是用一個字典來存放
    for friend in friends[1:]: #第一個爲自己,所以這裏排除了自己
        friends_name.update({friend['UserName']:{'nickname':friend['NickName'],'remarkname':friend['RemarkName']}})
    return friends_name

def get_username():
    chatrooms=itchat.get_chatrooms(update=True) #返回的是一個所有羣聊的信息的列表,每個羣聊信息都是用一個字典來存放
    user_name=[] #接收特定羣聊@本人的消息,並回復;存放特定羣聊的username
    all_user_name=[] #存放全部羣聊的username
    vip=[] #存放特定羣聊的名稱
    if os.path.exists('./vip.txt'):
        with open('./vip.txt','r',encoding='utf-8') as f:
            for i in f.read().split('\n')[:-1]:
                vip.append(i)
    for chatroom in chatrooms:
        all_user_name.append(chatroom['UserName'])
        if chatroom['NickName'] in vip:
            user_name.append(chatroom['UserName'])
    return all_user_name,user_name,vip

# 包括文本(表情符號)、位置、名片、通知、分享、圖片(表情包)、語音、文件、視頻
@itchat.msg_register([TEXT,MAP,CARD,SHARING,PICTURE,RECORDING,ATTACHMENT,VIDEO],isFriendChat=True,isGroupChat=True) #監聽個人消息和羣聊消息
def download_reply_msg(msg):
    global flag,sj,isrun,use_info #flag判斷要不要進入鬥圖模式,sj控制鬥圖的時間長短,isrun判斷是否啓動自動回覆機器人(默認運行中),通過向傳輸助手發指令來控制,use_info說明文檔
    all_user_name,user_name,vip=get_username()#每次接受消息時要拿到當前規定的羣聊和特定羣聊信息,後面用來分別做處理
    words=get_words() #拿到當前自定義回覆消息的信息
    now_time=int(time.time()) #記錄獲取這條消息的時間,後面處理撤回消息的時候用到
    b=[] #用來記錄已經過了可以撤回的時間的消息
    if len(msg_dict) != 0:
        for key,value in msg_dict.items():
            if (now_time - value['time']) >= 125: #經過驗證發現消息2分鐘之內才能撤回,這裏爲了保險起見加多5秒鐘
                b.append(key)
        for eachkey in list(msg_dict.keys()):
            if eachkey in b: #要是過了撤回時間的消息是文件類型的就把它們刪除,避免增加不必要的磁盤空間,盤大的請隨意
                if 'file' in msg_dict[eachkey].keys():
                    os.remove(msg_dict[eachkey]['file'])
                msg_dict.pop(eachkey)
#---------------------------------------------------------
#下面開始存儲各類消息,主要是用來查看別人撤回的消息,後面會用到
    if msg['Type'] in [MAP,SHARING]: #地圖或者分享
        old_id=msg['MsgId']
        link=msg['Url']
        msg_dict.update({old_id:{'type':msg['Type'],'data':link,'time':now_time}})
    elif msg['Type'] in [PICTURE,RECORDING,ATTACHMENT,VIDEO]:
        if msg['ToUserName'] != 'filehelper': # 避免給文件傳輸助手發文件也傳入字典,沒必要而且傳入字典只是爲了防止撤回,況且它是沒有撤回的
            old_id=msg['MsgId']
            file='./保存的文件/'+ msg['MsgId'] + '.' + msg['FileName'].split('.')[-1]
            msg['Text'](file)
            msg_dict.update({old_id:{'type':msg['Type'],'file':file,'time':now_time}})
        else:
            file='./保存的文件/'+ msg['FileName']
            msg['Text'](file)
    elif msg['Type'] == CARD: #名片
        old_id=msg['MsgId']
        link=re.findall('bigheadimgurl="(.*)" smallheadimgurl',str(msg))[0]
        msg_content = '來自' + msg['RecommendInfo']['Province'] +msg['RecommendInfo']['City'] + '的'+ msg['RecommendInfo']['NickName'] + '的名片'    #內容就是推薦人的暱稱和性別
        if msg['RecommendInfo']['Sex'] == 1:
            msg_content += ',男的'
        else:
            msg_content += ',女的'
        msg_dict.update({old_id:{'type':msg['Type'],'head':link,'data':msg_content,'time':now_time}})
    elif msg['Type'] == TEXT: #文本
        old_id=msg['MsgId']
        text=msg['Text']
        msg_dict.update({old_id:{'type':msg['Type'],'data':text,'time':now_time}})
#---------------------------------------------------------
#下面是自動回覆消息的(一切回覆邏輯都在這裏)
    if msg['ToUserName'] != 'filehelper': # 避免給文件傳輸助手發消息也自動回覆
        if isrun == '運行中......': #操控機器人的,想停就停,想啓動就啓動,不用關掉程序,而且不影響查看撤回消息的功能
            if msg['FromUserName'] in all_user_name:
                if msg['FromUserName'] in user_name: #當消息來自特定羣聊時,下面代碼纔會執行
                    if sj is not None:
                        if int(time.time()) - sj >= 900: #鬥圖時間:15分鐘
                            flag=0
                            sj=None
                    if (msg['isAt'] is True)&(msg['Type'] == TEXT):
                        myname='@' + re.findall("'Self'.*?'DisplayName': '(.*?)', 'KeyWord'",str(msg))[0] if re.findall("'Self'.*?'DisplayName': '(.*?)', 'KeyWord'",str(msg))[0] != '' else '這裏填你自己的微信暱稱'
                        if '帥哥來鬥圖' in msg['Text']:
                            flag=1
                            sj=int(time.time())
                            num=random.choice(os.listdir('./表情包'))
                            msg.user.send('@img@./表情包/{}'.format(num))
                            return None
                        reply = get_response(msg['Text'].replace(myname,''))
                        if 'I am' in reply:
                            reply=reply.replace('小i機器人','your father')
                        if '小i' in reply: #這個我是不想讓別人知道是小i機器人,才把它換掉的,你想換成什麼隨你,不換也行,就把這段代碼刪除即可
                            reply=reply.replace('小i','你爸爸')
                        if '機器人' in reply:
                            reply=reply.replace('機器人','')
                        if '輸入' in reply:
                            if flag == 0:
                                reply='有種來鬥圖,輸入“帥哥來鬥圖”即可。'
                            else:
                                reply=random.choice(words)
                        itchat.send('@%s\u2005%s' % (msg['ActualNickName'], reply), msg['FromUserName'])
                    if (msg['Type'] == PICTURE)&(flag == 1):
                        num=random.choice(os.listdir('./表情包'))
                        msg.user.send('@img@./表情包/{}'.format(num))
                else: #這裏是當消息來自不是特定羣聊時,要執行的代碼
                    if msg['Type'] == TEXT:
                        if '收到請回復' in msg['Text']:
                            return '收到'
            else: #下面是處理個人消息的
            	#經過測試發現如果自己手動發消息到新建的羣中,也會觸發下面自動回覆的代碼,於是就要排除這個bug用下面第一個if語句
            	if msg['FromUserName'] == itchat.search_friends(nickName='這裏填你自己的微信暱稱')[0]['UserName']:
                    return None
                if msg['Type'] == TEXT: #下面跟處理羣聊的時候差不多,就不重複了嘻嘻
                    reply = get_response(msg['Text'])
                    if 'I am' in reply:
                        reply=reply.replace('小i機器人','your father')
                    if '小i' in reply:
                        reply=reply.replace('小i','你爸爸')
                    if '機器人' in reply:
                        reply=reply.replace('機器人','')
                    if '輸入' in reply:
                        reply=random.choice(words)
                    msg.user.send(reply+'\n                                    [不是本人]') # 36個空格
                elif msg['Type'] == PICTURE: #表情包回覆
                    num=random.choice(os.listdir('./表情包'))
                    msg.user.send('@img@./表情包/{}'.format(num))
                elif msg['Type'] == RECORDING:
                    msg.user.send('請打字和我交流,謝謝。'+'\n                                    [不是本人]')
#---------------------------------------------------------
#下面是用來控制機器人的(給文件傳輸助手發指令)代碼很簡單,也很清晰
    else:
        if msg['Type'] == TEXT:
            if '添加vip' in msg['Text']:
                with open('./vip.txt','a',encoding='utf-8') as f:
                    f.write(msg['Text'][5:])
                    f.write('\n')
            if '查看vip' in msg['Text']:
                now_vip='\n'.join(vip)
                itchat.send('當前的vip羣有:\n{0}'.format(now_vip), toUserName='filehelper')
            if '刪除vip' in msg['Text']:
                if os.path.exists('./vip.txt'):
                    with open('./vip.txt','r',encoding='utf-8') as f1:
                        lines=f1.readlines()
                        with open('./vip.txt','w',encoding='utf-8') as f2:
                            for line in lines:
                                if msg['Text'][5:] != line.strip():
                                    f2.write(line)
            if '清空vip' in msg['Text']:
                with open('./vip.txt','w',encoding='utf-8') as f:
                    f.flush()
                    
            if '添加words' in msg['Text']:
                with open('./words.txt','a',encoding='utf-8') as f:
                    f.write(msg['Text'][7:])
                    f.write('\n')
            if '查看words' in msg['Text']:
                now_words='\n'.join(words)
                itchat.send('當前的words有:\n{0}'.format(now_words), toUserName='filehelper')
            if '刪除words' in msg['Text']:
                if os.path.exists('./words.txt'):
                    with open('./words.txt','r',encoding='utf-8') as f1:
                        lines=f1.readlines()
                        with open('./words.txt','w',encoding='utf-8') as f2:
                            for line in lines:
                                if msg['Text'][7:] != line.strip():
                                    f2.write(line)
            if '清空words' in msg['Text']:
                with open('./words.txt','w',encoding='utf-8') as f:
                    f.flush()
            if '停止機器人' in msg['Text']:
                isrun='已停止!'
            if '啓動機器人' in msg['Text']:
                isrun='運行中......'
            if '查看機器人' in msg['Text']:
                itchat.send(isrun, toUserName='filehelper')
            if 'robot' in msg['Text']:
                itchat.send(use_info, toUserName='filehelper')

@itchat.msg_register(NOTE,isFriendChat=True,isGroupChat=True)
def get_note(msg):
    if '撤回了一條消息' in msg['Text']:
        if '你撤回了一條消息' in msg['Text']:
            return None
        new_id=re.findall('<msgid>(\d+)</msgid>',str(msg))[0]
        public_time=time.strftime('%Y-%m-%d %H:%M:%S',time.gmtime(msg['CreateTime']+28800))
        data=msg_dict[new_id]
        nickname=re.findall("'UserName': '@[a-zA-Z0-9]+', 'NickName': '(.*?)', 'HeadImgUrl'",str(msg))[0]
        if len(nickname) > 100:
            friends_name=get_friendname()
            #羣名這句我覺得還會有bug,由於測試的時候只在2個人的羣中測試,多個的話可能會出bug,這個後面再說吧,反正我24小時掛着,有bug咱再說哈哈
            qun=re.findall("'NickName': '.*",re.findall("'UserName': '@[a-zA-Z0-9]+', 'NickName': '(.*)', 'HeadImgUrl'",str(msg))[0][-100:])[0].replace("'NickName': '",'')
            an=msg['ActualNickName']
            nickname='{0}在{1}羣中'.format(an,qun)
            if msg['ActualUserName'] in friends_name.keys():
                if friends_name[msg['ActualUserName']]['remarkname'] != '':
                    nickname='{0}({1})在{2}羣中'.format(an,friends_name[msg['ActualUserName']]['remarkname'],qun)
                else:
                    nickname='{0}({1})在{2}羣中'.format(an,friends_name[msg['ActualUserName']]['nickname'],qun)
        if data['type'] == MAP:
            itchat.send('%s在%s撤回了一個位置,其位置:\n%s'%(nickname,public_time,data['data']),toUserName='filehelper')
        elif data['type'] == CARD:
            itchat.send('%s在%s撤回了一個名片,名片信息:\n%s,其頭像:'%(nickname,public_time,data['data']),toUserName='filehelper')
            itchat.send('%s'%(data['head']),toUserName='filehelper')
        elif data['type'] == SHARING:
            itchat.send('%s在%s撤回了一個分享,其鏈接:\n%s'%(nickname,public_time,data['data']),toUserName='filehelper')
        elif data['type'] == TEXT:
            itchat.send('%s在%s撤回了一個信息,其內容:\n%s'%(nickname,public_time,data['data']),toUserName='filehelper')
        elif data['type'] in [PICTURE,RECORDING,ATTACHMENT,VIDEO]:
            itchat.send('%s在%s撤回了一張圖片或者一個表情或者一段語音或者一個視頻又或者一個文件,如下:'%(nickname,public_time),toUserName='filehelper')
            itchat.send('@%s@%s'%({'Picture': 'img', 'Video': 'vid'}.get(data['type'], 'fil'),data['file']),toUserName='filehelper')

# 下面開始運行機器人和創建所需目錄以及定義默認變量
#itchat.auto_login(hotReload=True) #windows下用這個
itchat.auto_login(hotReload=True,enableCmdQR=2) #linux下用這個
msg_dict={} # 儲存聊天記錄,找到撤回的消息
flag=0 # 判斷vip羣要不要進入鬥圖模式(默認不會,flag爲1時就會)
sj=None # 判斷啥時候flag恢復爲0
use_info='一、特殊羣聊管理\n①增加:添加vip+羣名\n②刪除:刪除vip+羣名\n③查詢:查看vip+羣名\n④清空:清空vip+羣名\n二、默認回覆管理\n①增加:添加words+語句\n②刪除:刪除words+語句\n③查詢:查看words+語句\n④清空:清空words+語句\n三、robot管理\n①啓動:啓動機器人\n②停止:停止機器人\n③狀態:查看機器人\n四、說明文檔:\n①指令:robot\n②注意:如果添加的羣沒有名字,那麼把羣裏每個人的暱稱用英文逗號隔開' #說明文檔
isrun='運行中......' # 是否啓動自動回覆機器人(默認運行中),通過向傳輸助手發指令來控制
if not os.path.exists('./表情包'):
	os.makedirs('./表情包')
if not os.path.exists('./保存的文件'):
	os.makedirs('./保存的文件')
itchat.run()

四、思維導圖(邏輯結構)

ps:單看代碼不過癮的話看下面的圖片吧,機器人處理消息的大致流程如下:

五、部署到雲服務器

前面我有說過就是一定要python3.7版本的原因就在這裏(也不是非要3.7版本,不過我敢肯定的是3.4版本是一定不行。)因爲我本機上的就是3.7,可是服務器上的系統自帶的是python3.4,然後如果你直接用3.4版本來運行,是可以運行的,只是返回來的msg是亂序的,每一次登錄它都不一樣,這樣爲什麼不行呢,因爲代碼裏面用了正則匹配,每次返回來的信息順序都不一樣的話,是沒辦法確定正則表達式的。這個坑坑了我一天好像,因爲當時我就差這一步就完成了!想到會不會是jsonxml版本的原因啊,然後這些又都是標準庫,那麼會不會是python版本原因造成的呢,於是乎,結果真的是這麼回事!!說到雲服務器,我之前的文章就有介紹過了,我用的是三豐雲服務器,土豪請無視。

  • 一樣首先要在linux系統下先將自定義的表情包給上傳了,這裏推薦一個命令:rz ,若還沒有安裝的,可以在終端運行如下代碼,成功之後,進去想要上傳的文件夾路徑輸入rz命令,會彈出選擇文件的框,這時就可以把表情包全部上傳了。
sudo apt-get install lrzsz
  • 要用crontab添加定時任務,就當前時間的下幾分鐘就好了,到點之後找到日誌輸入文件掃碼進行登錄即可,完了之後將定時任務註釋掉即可。
10 12 * * * root cd /home/Juneway/ && python3.7 wechat.py >/home/Juneway/robot.log 2>&1 &

掃碼登錄成功之後,就可以開始屬於你的個人微信機器人啦!!
ps:經過幾天的驗證,可以一直掛着,不會掉線,我懷疑那個心跳機制是假的??這還需要經過時間的驗證才能下定論。

更新如下:

  • 2020-1-7
    到目前爲止,我的個人微信號機器人已經在雲服務器上運行了一週的時間,從未掉過線。網上很多說手機端要保持在線,我不這麼認爲,我晚上睡覺前手機都是開飛行模式的,早上起來也沒有掉線。結論:沒有心跳機制,所以放心掛在服務器上就行。

  • 2020-1-31
    到目前爲止,已經正常連續運行了一個月整,總結:沒有心跳機制

六、運行展示


ps:由於gif有點難弄,就只先展示處理個人消息的吧,還有哪些處理羣聊啊、給文件傳輸助手發指令啊,那些就不一一展示了,有興趣的自己去實踐就行了哈哈


參考鏈接
https://www.php.cn/xiaochengxu-364486.html
https://itchat.readthedocs.io/zh/latest/
https://blog.csdn.net/enweitech/article/details/79585043

寫在最後

沒想到一開始從itchat教程的入門案例中,陷進去了,覺得挺好玩的,可是好景不長,就是他提供的那個圖靈測試的key,竟然調用次數沒有了,於是乎,便開始了屬於自己的個人微信號自動回覆機器人之旅,一開始也只是處理個人消息,後面就不斷地加需求,纔有了現在的robot1.0,其實我想實現的功能遠不止這些:自動回覆+監控撤回消息。其實我想到的還有:

  1. 自動回覆中可以把語音識別給加進去,別人發語音也能跟他們交流;
  2. 不調用別人的接口,自己用NLP來實現一個自己的聊天機器人,讓人工智障更加趨向人工智能;
  3. 退出重登,因爲我看到有個參數是控制退出後會執行的函數,應該可以通過那個來實現,這個我就等看有沒有心跳機制再搞吧;
  4. 實現建羣拉人,找出那些刪除了你的人;
  5. 通過微信機器人控制電腦,通過手機發送指令就可以操作電腦,從而實現更多的功能;
  6. 未完待續……
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章