1. 程式人生 > >Python微信庫:itchat ——實現微信自動回覆

Python微信庫:itchat ——實現微信自動回覆

我一個同學向我表示人類的本質是復讀機,就一直重複我的話,然後我就一”怒“之下搜了一下微信自動回覆機器人,然後發現了神奇的itchat庫,利用這個庫可以很簡單實現自動回覆的功能

開始之前,感覺有必要先介紹一下itchat的註冊訊息型別

  • itchat要註冊訊息型別,比如註冊了TEXT(itchat.content.text),就會接收文字訊息,其他訊息不會觸發函式。訊息型別見庫中的content.py檔案
  • 訊息型別判斷,msg[‘Type’]
  • 訊息發起者,msg[‘FromUserName’]
  • 訊息接收者,msg[‘ToUserName’]
  • 文字訊息,msg[‘Content’]
  • 檔名字,msg[‘FileName’],注:如果是自帶的表情就會顯示錶情
  • 傳送檔案時,檔名字應該是unicode編碼(這是python內部預設的編碼風格)

    傳送其他訊息

  • 給自己傳送訊息只需要發出訊息,不指定傳送者,預設發給自己(登陸者) itchat.send_msg(‘nice to meet you’)
  • 傳送圖片,ToUser不指定時發給自己 itchat.send_image(ImageName.decode(‘utf-8’),ToUser) # 傳送圖片
  • 傳送視訊 itchat.send_video(VideoName.decode(‘utf-8’),ToUser) # 傳送圖片
  • 傳送檔案 itchat.send_file(path.decode(‘utf-8’)) # 圖片(檔案)

我先放一下我執行成功的程式碼吧(我隨機生成了三個機器人)

# -*- coding=utf-8 -*-
import requests
import itchat
import random

KEY = '04f44290d4cf462aae8ac563ea7aac16'


def get_response(msg):
    apiUrl = 'http://www.tuling123.com/openapi/api'
    data = {
        'key': KEY,
        'info': msg,
        'userid': 'wechat-robot',
    }
    try:
        r = requests.post(apiUrl, data=data).json()
        return r.get('text')
    except:
        return


@itchat.msg_register(itchat.content.TEXT)
def tuling_reply(msg):
    defaultReply = 'I received: ' + msg['Text']
    robots = ['——By1', '——By2', '——By3']
    reply = get_response(msg['Text'])+random.choice(robots)
    return reply or defaultReply


itchat.auto_login(hotReload=True)
# itchat.auto_login(enableCmdQR=True)這個只能生成一行行二維碼,不能生成圖片
itchat.run()

1、start

最簡單的回覆

通過如下程式碼,可以完成回覆所有文字資訊(包括群聊)。

import itchat
from itchat.content import TEXT

@itchat.msg_register
def simply_reply(msg):
    if msg['Type'] == TEXT:
       return 'I received: %s' % msg['Content']

itchat.auto_login()
itchat.run()

常用訊息的配置

itchat支援所有的訊息型別與群聊,下面的示例中演示了對於這些訊息型別簡單的配置。

import itchat
from itchat.content import *

@itchat.msg_register([TEXT,MAP,CARD,NOTE,SHARING])
def text_reply(msg):
    itchat.send('%s:%s'%(msg['Type'],msg['Text']),msg['FromeUserName'])

# 以下四類的訊息的Text鍵下存放了用於下載訊息內容的方法,傳入檔案地址即可
@itchat.msg_register([PICTURE, RECORDING, ATTACHMENT, VIDEO])
def download_files(msg):
    msg['Text'](msg['FileName'])
    return '@%[email protected]%s' % ({'Picture':'img','Video':'vid'}.get(msg['Type'], 'fil'), msg['FileName'])

# 收到好友邀請自動新增好友
@itchat.msg_register(FRIENDS)
def add_friend(msg):
    itchat.add_friend(**msg['Text']) # 該操作會自動將新好友的訊息錄入,不需要過載通訊錄
    itchat.send_msg('Nice to meet you!', msg['RecommendInfo']['UserName'])

# 在註冊時增加isGroupChat=True將判定為群聊回覆
@itchat.msg_register(TEXT, isGroupChat = True)
def groupchat_reply(msg):
    if msg['isAt']:
        itchat.send(u'@%s\u2005I received: %s' % (msg['ActualNickName'], msg['Content']), msg['FromUserName'])

itchat.auto_login(True)
itchat.run()

當然這裡不需要深究為什麼這些東西可以這麼寫,我在這裡放出了示例程式只是為了給你一個該sdk相關程式碼大概樣子的概念。

有了大概的模式的瞭解之後我們就可以進入下一部分的介紹。

2、login

在上一部分中你看到了基本的註冊與登陸,而顯然登陸使用的是itchat提供了auto_login方法,呼叫即可完成登入。

一般而言,我們都會在完成訊息的註冊後登陸。

當然這裡需要特別強調的是三點,分別是短時間關閉重連、命令列二維碼與自定義登陸內容。 itchat提供了登陸狀態暫存,關閉程式後一定時間內不需要掃碼即可登入。 為了方便在無圖形介面使用itchat,程式內建了命令列二維碼的顯示。 * 如果你需要就登入狀態就一些修改(例如更改提示語、二維碼出現後郵件傳送等)。

**0x01-1 短時間關閉程式後重連**

這樣即使程式關閉,一定時間內重新開啟也可以不用重新掃碼。

最簡單的用法就是給 auto_login 方法傳入值為真的 hotReload 。

該方法會生成一個靜態檔案 itchat.pkl ,用於儲存登陸的狀態。

import itchat
from itchat.content import TEXT

@itchat.msg_register(TEXT)
def simple_reply(msg):
    print(msg['Text'])

itchat.auto_login(hotReload = True)
itchat.run()
itchat.dump_login_status()

通過設定statusStorageDir可以將靜態檔案指定為其他的值。

這一內建選項其實就相當於使用了以下兩個函式的這一段程式:

import itchat
from itchat.content import TEXT

if itchat.load_login_status():
   @itchat.msg_register(TEXT)
   def simple_reply(msg):
       print(msg['Text'])
   itchat.run()
   itchat.dump_login_status()
else:
   itchat.auto_login()
   itchat.dump_login_status()
   print('Config stored, so exit.')

其中load_login_status與dump_login_status分別對應讀取與匯出設定。

通過設定傳入的fileDir的值可以設定匯入匯出的檔案。

**0x01-2 命令列二維碼顯示**

通過以下命令可以在登陸的時候使用命令列顯示二維碼:

itchat.auto_login(enableCmQR=True)

部分系統可能字幅寬度有出入,可以通過將enableCmdQR賦值為特定的倍數進行調整:

# 如部分的linux系統,塊字元的寬度為一個字元(正常應為兩字元),故賦值為2
itchat.auto_login(enableCmdQR=2)

預設控制檯背景色為暗色(黑色),若背景色為淺色(白色),可以將enableCmdQR賦值為負值:

itchat.auto_login(enableCmdQR=-1)

**0x01-2 自定義登入過程**

如果需要控制登入的過程,可以閱讀下面的內容。

同時itchat也提供了登陸所需的每一步的方法,登陸的過程按順序為: 獲取二維碼uuid->獲取二維碼->判斷是否已經登陸成功->獲取初始化資料->更新微信相關資訊(通訊錄、手機登陸狀態)->迴圈掃描新資訊(開啟心跳)

獲取二維碼uuid

獲取生成二維碼所需的uuid,並返回。

  • 方法名稱: get_QRuuid
  • 所需值:無
  • 返回值:成功->uuid,失敗->None

獲取二維碼

根據uuid獲取二維碼並開啟,返回是否成功。

  • 方法名稱: get_QR
  • 所需值:uuid
  • 返回值:成功->True,失敗->False

判斷是否已經登陸成功

判斷是否已經登陸成功,返回掃描的狀態碼。

  • 方法名稱: check_login
  • 所需值:uuid
  • 返回值:登陸成功->'200',已掃描二維碼->'201',二維碼失效->'408',未獲取到資訊->'0'

獲取初始化資料

獲取微信使用者資訊以及心跳所需要的資料。

  • 方法名稱: web_init
  • 所需值:無
  • 返回值:儲存登入微信使用者資訊的字典

獲取微信通訊錄

獲取微信的所有好友資訊並更新。

  • 方法名稱: get_contract
  • 所需值:無
  • 返回值:儲存好友資訊的列表

更新微信手機登陸狀態

在手機上顯示登入狀態。

  • 方法名稱: show_mobile_login
  • 所需值:無
  • 返回值:無

迴圈掃描新資訊(開啟心跳)

迴圈掃描是否有新的訊息,開啟心跳包。

  • 方法名稱: start_receiving
  • 所需值:無
  • 返回值:無

EG

一個登入例子:

import itchat, time, sys

def output_info(msg):
    print('[INFO] %s' % msg)

def open_QR():
    for get_count in range(10):
        output_info('Getting uuid')
        uuid = itchat.get_QRuuid()
        while uuid is None: uuid = itchat.get_QRuuid();time.sleep(1)
        output_info('Getting QR Code')
        if itchat.get_QR(uuid): break
        elif get_count >= 9:
            output_info('Failed to get QR Code, please restart the program')
            sys.exit()
    output_info('Please scan the QR Code')
    return uuid

uuid = open_QR()
waitForConfirm = False
while 1:
    status = itchat.check_login(uuid)
    if status == '200':
        break
    elif status == '201':
        if waitForConfirm:
            output_info('Please press confirm')
            waitForConfirm = True
    elif status == '408':
        output_info('Reloading QR Code')
        uuid = open_QR()
        waitForConfirm = False
userInfo = itchat.web_init()
itchat.show_mobile_login()
itchat.get_contract()
output_info('Login successfully as %s'%userInfo['NickName'])
itchat.start_receiving()

# Start auto-replying
@itchat.msg_register
def simple_reply(msg):
    if msg['Type'] == 'Text':
        return 'I received: %s' % msg['Content']
itchat.run()

3、register

註冊訊息方法

itchat將根據接收到的訊息型別尋找對應的已經註冊的方法。 如果一個訊息型別沒有對應的註冊方法,該訊息將會被捨棄。 在執行過程中也可以動態註冊方法,註冊方式與結果不同

註冊

你可以通過兩種方式註冊訊息方法

import itchat
from itchat.content import *

#不帶引數註冊,所有訊息型別都將呼叫該方法(包括群訊息)
@itchat.msg_register
def simple_reply(msg):
    if msg['Type'] == 'Text':
        return 'I received: %s' % msg['Text']

#帶引數註冊,該類訊息型別將呼叫該方法
@itchat.msg_register([TEXT, MAP, CARD, NOTE, SHARING])
def text_reply(msg):
    itchat.send('%s: %s' % (msg['Type'], msg['Text']), msg['FromUserName'])

訊息型別:在這裡在敘述一遍,感覺我們處理微信訊息的時候麻煩一點的應該也就是分型別回覆了

向註冊方法傳入的msg包含微信返回的字典的所有內容。

本api增加Text、Type(也就是引數)鍵值,方便操作。

itchat.content中包含所有的訊息型別引數,內容如下表所示:

引數 型別 Text鍵值
TEXT 文字 文字內容
MAP 地圖 位置文字
CARD 名片 推薦人字典
NOTE 通知 通知文字
SHARING 分享 分享名稱
PICTURE 圖片/表情 下載方法
RECODING 語音 下載方法
ATTACHMENT 附件 下載方法
VIDEO 小視訊 下載方法
FRIENDS 好友邀請 新增好友所需引數
Useless 無用資訊 ‘UselessMsg'

比如你需要儲存傳送給你的附件:

@itchat.msg_register(ATTACHMENT)
def download_files(msg):
    msg['Text'](msg['FileName'])

值得注意的是,群訊息增加了三個鍵值: isAt: 判斷是否@本號 ActualNickName: 實際NickName * Content: 實際Content

可以通過本程式測試:

import itchat
from itchat.content import TEXT

@itchat.msg_register(TEXT, isGroupChat = True)
def text_reply(msg):
    print(msg['isAt']
    print(msg['ActualNickName'])
    print(msg['Content'])

itchat.auto_login()
itchat.run()

註冊訊息的優先順序

優先順序分別為:後註冊訊息先於先註冊訊息,帶引數訊息先於不帶引數訊息。

以下面的兩個程式為例:

import itchat
from itchat.content import *

itchat.auto_login()

@itchat.msg_register(TEXT)
def text_reply(msg):
    return 'This is the old register'

@itchat.msg_register(TEXT)
def text_reply(msg):
    return 'This is a new one'

itchat.run()

在私聊傳送文字時將會回覆This is a new one。

import itchat
from itchat.content import*

itchat.auto_login()

@itchat.msg_register
def general_reply(msg):
    return 'I received a %s' % msg['Type']

@itchat.msg_register(TEXT)
def text_reply(msg):
    return 'You said to me one to one: %s' % msg['Text']

itchat.run()

僅在私聊傳送文字時將會回覆You said to me one to one,其餘情況將會回覆I received a ...。

動態註冊資訊

動態註冊時可以選擇將 itchat.run() 放入另一執行緒或使用 configured_reply() 方法處理訊息。

兩種方法分別是:

# 使用另一執行緒,但注意不要讓程式執行終止
import thread

thread.start_new_thread(itchat.run, ())

# 使用configured_reply方法
while 1:
    itchat.configured_reply()
    # some other functions
    time.sleep(1)

以下給出一個動態註冊的例子

#coding=utf8
import thread

import itchat
from itchat.content import *

replyToGroupChat = True
functionStatus = False

def change_function():
    if replyToGroupChat != functionStatus:
        if replyToGroupChat:
            @itchat.msg_register(TEXT, isGroupChat = True)
            def group_text_reply(msg):
                if u'關閉' in msg['Text']:
                    replyToGroupChat = False
                    return u'已關閉'
                elif u'開啟' in msg['Text']:
                    return u'已經在執行'
                return u'輸入"關閉"或者"開啟"測試功能'
        else:
            @itchat.msg_register(TEXT, isGroupChat = True)
            def group_text_reply(msg):
                if u'開啟' in msg['Text']:
                    replyToGroupChat = True
                    return u'重新開啟成功'
        functionStatus = replyToGroupChat

thread.start_new_thread(itchat.run, ())

while 1:
    change_function()
    time.sleep(.1)

4、reply

回覆

itchat提供五種回覆方法,建議直接使用send方法。

send方法

  • 方法:

    send(msg='Text Message', toUserName=None)

  • 所需值:
1.msg:訊息內容
2.'@[email protected]檔案地址'將會被識別為傳送檔案,'@[email protected]圖片地址'將會被識別為傳送圖片,'@[email protected]視訊地址'將會被識別為小視訊
3.toUserName:傳送物件,如果留空將會發送給自己
  • 返回值:傳送成功->True, 失敗->False
    import itchat
    
    itchat.aauto_login()
    itchat.send('Hello world!')
    # 請確保該程式目錄下存在:gz.gif以及xlsx.xlsx
    itchat.send('@[email protected]%s' % 'gz.gif')
    itchat.send('@[email protected]%s' % 'xlsx.xlsx')
    itchat.send('@[email protected]%s' % 'demo.mp4')

    send_msg方法

  • 方法:

    send_msg(msg='Text Message', toUserName=None)

  • 所需值:

    msg:訊息內容
     toUserName:傳送物件,如果留空將會發送給自己
  • 返回值:傳送成功->True, 失敗->False

  • 程式示例:

    import itchat
    
    itchat.auto_login()
    itchat.send_msg('Hello world')

    send_file方法

  • 方法:

    send_file(fileDir, toUserName=None)

  • 所需值:

    fileDir:檔案路徑(不存在該檔案時將列印無此檔案的提醒)
     toUserName:傳送物件,如果留空將會發送給自己
  • 返回值:傳送成功->True, 失敗->False

  • 程式示例:

    import itchat
    
    itchat.auto_login()
    #請確保該程式目錄下存在:xlsx.xlsx
    itchat.send_file('xlsx.xlsx')

    send_img方法

  • 方法:

    send_img(fileDir, toUserName=None)

  • 所需值:

    fileDir:檔案路徑(不存在該檔案時將列印無此檔案的提醒)
     toUserName:傳送物件,如果留空將會發送給自己
  • 返回值:傳送成功->True, 失敗->False

  • 程式示例:

    import itchat
    
    itchat.auto_login()
    # 請確保該程式目錄下存在:gz.gif
    itchat.send_img('gz.gif')

    send_video方法

  • 方法:

    send_video(fileDir, toUserName=None)

  • 所需值:
fileDir:檔案路徑(不存在該檔案時將列印無此檔案的提醒)
 toUserName:傳送物件,如果留空將會發送給自己
  • 返回值:傳送成功->True, 失敗->False

需要保證傳送的視訊為一個實質的mp4檔案

import itchat

itchat.auto_login()
#請確保該程式目錄下存在:demo.mp4
itchat.send_file('demo.mp4')

5、Memmber stuff

在使用個人微信的過程當中主要有三種賬號需要獲取,分別為: 好友 公眾號 * 群聊

itchat為這三種賬號都提供了整體獲取方法與搜尋方法。

而群聊多出獲取使用者列表方法以及建立群聊、增加、刪除使用者的方法。

這裡我們分這三種分別介紹如何使用。

好友

好友的獲取方法為 get_friends ,將會返回完整的好友列表。 其中每個好友為一個字典 列表的第一項為本人的賬號資訊 * 傳入update鍵為True將可以更新好友列表並返回

好友的搜尋方法為 search_friends ,有四種搜尋方式: 1. 僅獲取自己的使用者資訊 2. 獲取特定 UserName 的使用者資訊 3. 獲取備註、微訊號、暱稱中的任何一項等於 name 鍵值的使用者 4. 獲取備註、微訊號、暱稱分別等於相應鍵值的使用者

其中三、四項可以一同使用,下面是示例程式:

# 獲取自己的使用者資訊,返回自己的屬性字典
itchat.search_friends()
# 獲取特定UserName的使用者資訊
itchat.search_friends(userName='@abcdefg1234567')
# 獲取任何一項等於name鍵值的使用者
itchat.search_friends(name='littlecodersh')
# 獲取分別對應相應鍵值的使用者
itchat.search_friends(wechatAccount='littlecodersh')
# 三、四項功能可以一同使用
itchat.search_friends(name='LittleCoder機器人', wechatAccount='littlecodersh')

公眾號

公眾號的獲取方法為 get_mps ,將會返回完整的公眾號列表。 其中每個公眾號為一個字典 傳入update鍵為True將可以更新公眾號列表並返回

公眾號的搜尋方法為 search_mps ,有兩種搜尋方法: 1. 獲取特定 UserName 的公眾號 2. 獲取名字中含有特定字元的公眾號

如果兩項都做了特定,將會僅返回特定 UserName 的公眾號,下面是示例程式:

# 獲取特定UserName的公眾號,返回值為一個字典
itchat.search_mps(userName='@abcdefg1234567')
# 獲取名字中含有特定字元的公眾號,返回值為一個字典的列表
itcaht.search_mps(name='LittleCoder')
# 以下方法相當於僅特定了UserName
itchat.search_mps(userName='@abcdefg1234567', name='LittleCoder')

群聊

群聊的獲取方法為 get_chatrooms ,將會返回完整的群聊列表。 其中每個群聊為一個字典 傳入update鍵為True將可以更新群聊列表並返回

群聊的搜尋方法為 search_chatrooms ,有兩種搜尋方法: 1. 獲取特定UserName的群聊 2. 獲取名字中含有特定字元的群聊

如果兩項都做了特定,將會僅返回特定UserName的群聊,下面是示例程式:

# 獲取特定UserName的群聊,返回值為一個字典
itchat.search_chatrooms(userName='@abcdefg1234567')
# 獲取名字中含有特定字元的群聊,返回值為一個字典的列表
itcaht.search_chatrooms(name='LittleCoder')
# 以下方法相當於僅特定了UserName
itchat.search_chatrooms(userName='@abcdefg1234567', name='LittleCoder')

群聊使用者列表的獲取方法為 update_chatroom 。 群聊在首次獲取中不會獲取群聊的使用者列表,所以需要呼叫該命令才能獲取群聊的成員 該方法需要傳入群聊的UserName,返回特定群聊的使用者列表

memberList = itchat.update_chatroom('@abcdefg1234567')

建立群聊、增加、刪除群聊使用者的方法如下所示: 由於之前通過群聊檢測是否被好友拉黑的程式,目前這三個方法都被嚴格限制了使用頻率 刪除群聊需要本賬號為群管理員,否則會失敗

memberList = itchat.get_friends()[1:]
# 建立群聊,topic鍵值為群聊名
chatroomUserName = itchat.create_chatroom(memberList, 'test chatroom')
# 刪除群聊內的使用者
itchat.delete_member_from_chatroom(chatroomUserName, memberList[0])
# 增加使用者進入群聊
itchat.add_member_into_chatroom(chatroomUserName, memberList[0])

6、QAQ

Q: 為什麼我在設定了itchat.auto_login()的enableCmdQR為True後還是沒有辦法在命令列顯示二維碼?

A: 這是由於沒有安裝可選的包 pillow ,可以使用右邊的命令安裝: pip install pillow

7、eg

def signin():
        # 查詢公眾號,進行簽到
        user = itchat.search_mps(name='Nulll.me')
        UserName = user[0]['UserName']
        itchat.send(msg=u'3', toUserName=UserName)
        itchat.dump_login_status()
        pickleDumps('flag', localDay)  # 如果執行成功寫入標緻檔案
        exit()


if __name__ == '__main__':
        # 如果不是在登陸狀態,就迴圈登陸
        while not itchat.load_login_status():
                sendMail()
                itchat.auto_login(hotReload=True)
                itchat.dump_login_status()
                signin()  # 簽到
                time.sleep(3600)
        signin()  # 簽到

好了,大致內容就是這些了,玩得愉快