微信機器人的做用
- 方便用戶上傳採購需求文件,用戶的採購需求文件通常是在PC端編輯的,若是使用小程序則比較麻煩
- 發揮微信羣的做用,使用微信機器人更方便管理微信羣
- 微信聊天機器人,與用戶智能聊天,解決用戶的部分需求,充當客服的做用(後期實現)
微信機器人技術原理
- 進程間通訊:與微信進程進行通訊,具體的進程間通訊方式有多種。例如:共享內存,管道
- 監聽器與處理器:以守護進程的方式啓動充當服務器,監聽微信發送的消息並作處理
技術框架選擇
- 使用python編程語言,python語言的優勢是用在爬蟲,大數據,人工智能方便,相關加框豐富
- 使用itchat做爲微信機器人技術框架,itchat使用的開發者衆多,文檔豐富,github排名第一
如何在linux服務器控制檯登陸微信機器人
- 下載二維碼至控制檯並使用手機微信掃描登陸二維碼,itchat框架內部已是在在控制檯掃描的功能
如何驗證用戶
- 使用手機號碼做爲藥工匯惟一對應用戶,故在用戶第一次上傳文件時,須要用戶輸入手機號碼
- 使用會話管理判斷上下文的用戶
微信我的號的註冊
- 註冊一個微信我的號做爲機器人微信號,微信名爲藥工匯,將小型加工商加爲機器人微信號的好友;
- 使用機器人微信號創建一個微信羣,羣名爲藥工匯服務羣,將小型加工商拉進此微信羣
- 註冊微信我的號須要手機短信的驗證,全部須要先註冊一個手機號,此手機號只需有短信功能,無需流量,月租越少越好,須要很是清楚的知道協議,發票要有
- 聯通的米粉卡,月租5元,短信0.1元/條, 電話0.1元/分鐘, 流量1元/天天/1G, 3元封頂; 申請發票爲月結髮票,使用聯通APP進行自定義交費,不能選擇固定金額交費; 註冊米粉卡手機號的途徑爲在微信中收縮米粉卡助手,關注公衆號,點擊申請,填寫地址,而後郵寄;
- 聯通人工客服電話爲10010接通後按0進入人工服務
- 可使用QQ號或者郵箱登陸微信
微信機器人應用的特性
- 監聽微信好友及羣好友的發送的文件和圖片並下載
- 自動上傳文件和圖片到阿里雲服務器
- 發送文本消息給微信機器人驗證微信機器人是否正常運行
- 獲取微信好友信息,驗證微信用戶是否爲藥商匯用戶
- 文件上傳相關日誌
運維:將代碼部署到測試環境
- 將代碼上傳到碼雲
git init git add . git commit -m "first commit" git remote add origin https://gitee.com/chggit_liudaoqiang/itchat_app.git git push -u origin master
- 從碼雲克隆代碼到測試或生產服務器
cd /data/chgg git clone https://gitee.com/chggit_liudaoqiang/itchat_app.git
- 進入項目虛擬環境
cd /data/chgg/itchat_app source venv/Scripts/activate
- 在測試環境安裝python3(linux服務器上的python版本爲2.7)
從python官網下載python3.6.6html
cd ~ wget https://www.python.org/ftp/python/3.6.6/Python-3.6.6.tgz
解壓python3.6.6壓縮包python
tar -zxvf Python-3.6.6.tgz
配置源代碼文件mysql
cd ~/Python-3.6.6 ./configure
安裝jquery
vim Makefile # 將 -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes 中的3改成2
make
make install
問題:python3make到unicodeobject.c就再也不繼續運行,linux
gcc -pthread -c -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -I. -I./Include -DPy_BUILD_CORE -o Objects/unicodeobject.o Objects/unicodeobject.cgit
執行到這裏就再也不向下執行github
解決辦法爲執行configure命令後將Makefile文件中的 -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes 中的3改成2web
即-DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypesajax
- 安裝阿里雲OSS存儲對象SDK
cd /data/chgg/itchat_app pip3 install oss2
- 安裝微信機器人itchat包
pip3 install itchat
- 安裝數據庫操做的庫
pip3 install pymysql
- 檢查應用程序相關文件
檢查是否存在文件存放文件夾download算法
# 檢查/data/chgg/itchat_app目錄下是否存在目錄downlaod; 若是沒有則建立該目錄 mkdir -p download
chmod 777 download
檢查是否存在日誌存放文件夾logs
# 檢查/data/chgg/itchat_app目錄下是否存在目錄logs; 若是沒有則建立該目錄 mkdir -p logs chmod 777 logs
將調試狀態改成生產狀態
Debug = True # 改成 Debug = False
修改阿里雲oss的帳號配置
修改數據庫的帳號配置
- 啓動應用程序
nohup python3 server.py
0.業務:
藥工匯的意義:
(1)指抓住小型加工商,拓展業務
(2)之前只作B2B的業務,抓住小型加工商,爲之後的B2C業務打下基礎
(3)收集小型藥工的採購需求,集體採購,造成集採優點
(4)給小型加工商賦能,提供集採,提供採購渠道,提供標準生產加工工藝規範,提供機器設備,提供倉儲養護方案,提供追溯信息
藥工匯的發展:
(1)作小程序平臺,讓小型加工商加盟進來
(2)發展小型加工商,在7月底完成發展100個小型加工商
問題:
(1)如何佈局小型加工點
微信機器人的意義:
(1)有了小型加工商在藥工匯小程序的加盟註冊, 使用微信羣,用智能的方式管理小型加工商
(2)收集小型加工商的採購需求,將採購需求上傳到藥工匯
(3)給小型加工商推送重要的資訊信息
(4)智能聊天,解決小型加工商的疑問,將小型加工商的常見問題疑問收集上來並進行智能回覆
1. 下載安裝Itchat
方法一:
從github上下載Itchat,下載地址爲https://github.com/littlecodersh/ItChat.git, 而後運行setup.py進行安裝;
方法二:
經過pip install itchat進行安裝(具體能夠在項目的virtualenv環境中使用此命令安裝itchat)
2. 爲何使用itchat做爲微信機器人框架:
在github上搜索 「微信機器人」 , itchat排名第一, 遠在其餘框架之上
3. 關於微信機器人itchat的思考:
(1)如何保持itchat的長期登陸狀態
(2)如何讓itchat做爲守護進程運行,處理完用戶消息後關閉該用戶的鏈接可是依然能夠處理下一個用戶的消息, 無需重啓服務進程
(3)itchat如何處理消息撤回,例如:用戶發送了一個文件,itchat調用其餘接口將文件上傳到了第三方服務器,這時應該進行文件在第三方服務器的刪除,即如何監聽文件撤回
(4)itchat進行消息監聽及監聽後處理的原理及實戰
(5)如何實現自動智能回覆,使用圖靈機器人restapi接口實現
(6)如何定時清理緩存
(7)應用程序是部署在linux服務器上的,使得機器人程序完成工做,必需要微信應用程序和微信機器人安裝包及微信機器人應用程序包是在一臺機器上運行。
4. itchat的原理(本質)
(1)itchat做爲守護進程監聽微信消息事件,並進行處理
5. 回調:
(1)服務器A與服務器B之間進行通訊的方式分爲兩種:即同步跨域請求,或異步回調
(2)異步回調不能使用本地開發環境的主機做爲回調地址,由於主動回調的服務器不能識別本地開發環境的域名解析IP
(3)異步回調的調試必須先將回調地址可以直接在瀏覽器訪問通,且能寫入日誌,這樣首先就避免了回調地址權限的問題
6. 跨域:
訪問相同域名,相同端口,相同協議則爲同域,反之,則爲跨域
(1)使用AJAX沒法跨域請求,可是使用jsonp協議的AJAX能夠進行跨域請求,並且必須使用GET請求,不能使用POST請求
(2)能夠跨域請求js文件和json文件,例如引用jquery框架中的js
(3)全部具備src屬性的標籤均可以進行跨域請求,可使用script,img,iframe進行跨域請求
例如:
(1)使用jsonp協議的AJAX進行跨域
$.ajax({ type : 'get', url:'http://192.168.31.137/train/test/testjsonp', data : { name : name, sex : sex, address : address, looks : looks, }, cache :false, jsonp: "callback", jsonpCallback:"success", dataType : 'jsonp', success:function(data){ alert(data); }, error:function(data){ alert('error'); } });
(2)使用script標籤進行跨域
var url = "http://192.168.31.137/train/test/jsonpthree?callback=messagetow"; var script = document.createElement('script'); script.setAttribute('src', url); document.getElementsByTagName('head')[0].appendChild(script);
(3)使用iframe標籤進行跨域
<iframe id='a' src='http://b.study.cn/b.html' onload='test()'>
7. 會話
(1)由於HTTP是無狀態的,第一次使用HTTP協議請求服務器資源,鏈接關閉後;第二次再次發起HTTP請求,服務器不知道是哪一個用戶來請求,只知道是從哪一個客戶端IP發來的請求;因此HTTP協議請求,須要第一次請求時用戶在服務端登陸,記錄用戶身份信息,第二次發起請求時使用請求頭帶入身份信息,服務器將請求帶入的身份信息與服務器記錄的身份信息進行比對,若是能比對上則知道用戶的身份信息,這樣就至關於記錄了狀態
(2)會話管理有3中方式,分別爲Session,Cookie, Token
基於Session管理會話的流程:
基於Session管理會話的優勢:
a. 安全性好,由於在客戶端和服務端認證身份信息的惟一媒介是sessionid, 而sessionid又是隨機的加密字符串, 不太容易冒用別人的sessionid,除非經過CSRF攻擊或者使用HTTP劫持的方法先拿到用戶的sessionid
基於Session管理會話的缺點:
a. 佔用服務器的內存空間,微信每一個用戶都要在服務器註冊session,這些session對象都存儲在服務端,致使服務端佔用太多內存空間
b. 集羣服務器部署困難,由於session是存放在服務端的,而不一樣用戶請求HTTP分配的服務器機器是隨機的,用戶每次請求的都不必定是同一臺建立session的服務器,致使沒法真正認證用戶信息,這樣就須要session對象在全部的服務器都要及時同步才行,或者使用其餘專門的一臺服務器存儲session信息,例如使用Redis服務器做爲中間服務器存儲專門存儲session信息
c, 多應用共享session的跨域問題, 當有多個應用都須要共享session時,不一樣額應用可能部署在不一樣的主機上,而sessionid是依靠cookie來傳遞的
基於Cookie管理會話的流程:
用戶使用用戶名和密碼登陸後,服務器將用戶名和密碼等信息作數字簽名,而後使用對稱加密算法進行加密,將加密後的信息存放在客戶端的Cookie中; 下次請求時傳入此加密信息給服務器,服務器先作解密處理,而後再作數字簽名認證,驗證用戶身份信息
基於Cookie管理會話的優勢:
a. 不佔用服務器的內存空間, 由於Cookie是存放在客戶端的
b. 不影響集羣服務器的部署, 由於每臺服務器的加密和解密算法是同樣的
c. 不影響多應用共享Session,只要保證每一個應用的加密和解密算法是同樣的便可
基於Token管理會話的流程:
原理上和Cookie管理會話的本質是同樣的,只是Cookie是依靠Cookie來傳遞信息的,而Token是依靠HTTP的header或者url參數來傳遞的;
只須要在客戶端將Token存儲起來,其次發起請求時,取出Token並放入url中便可
對於非接口調用直接點擊連接是沒法取出Token的
(3)微信每次的聊天都是不帶狀態的,就像每次HTTP請求都是不帶狀態的,則沒法關聯兩次回次爲同一個用戶,須要關聯先後兩次聊天或HTTP請求,則可使用Cookie或者Session來識別是否爲同一個用戶,微信聊天中監聽的msg中帶有FromUserName字段,爲長串加密字符串,只要服務器沒有從新登陸(即便宕機後重啓無需登陸,使用以前保存的登陸狀態)則同一用戶發送的消息中FromUserName字段是一致的,則此FromUserName字段至關於Cookie或者Session,可使用此字段進行會話管理
8. 微信機器人進程和微信進程是如何通訊的,即進程間有哪些通訊方式?
進程間通訊的方式有5種:
7. 微信機器人採集藥商匯用戶微信好友的採購需求,並在藥商匯微信小程序上展現
(1)監聽微信好友及羣好友的發送的文件和圖片並下載,上傳到阿里雲OSS服務器,生成訪問阿里雲文件的連接
(2)上傳文件和圖片到阿里雲服務器;
提示用戶是否確認上傳到藥工匯,並在一段時間內重複追問;回答是則上傳到阿里雲;(技術上不易實現);可在藥商匯後臺作一個採購需求審覈功能
獲得用戶微信ID和阿里雲返回的文件連接
調用藥工匯投放API在藥商匯小程序展現後給微信用戶發送文本消息,提示已經成功上傳;或生成一個頁面二維碼,經過此二維碼可在藥工匯小程序看到投放的文件
(場景爲用戶和微信機器人一對一對話; 機器人給用戶羣推送消息的場景爲微信羣)
(3)發送文本消息給微信機器人驗證微信機器人是否正常運行
任何微信好友給微信機器人發送帶有「運行狀態「的文本,若是微信機器人進程正在運行,則自動回覆「正在運行」;若是微信機器人已中止運行,則沒有任何回覆;
(4)獲取微信好友信息,驗證微信用戶是否爲藥商匯用戶
(5)日誌功能,記錄用戶的聊天記錄
(6)日誌功能,記錄微信機器人的工做記錄
問題1:爲何使用文件來管理採購需求,而不使用系統錄入來管理採購需求?
(1)由於文件的隨意性很大,採購者沒有被管控的感受,沒有系統的規範,這樣知足了採購者的使用須要又沒有被管控,則容易用起來;反之,則不容易用起來。
(2)另外一方面,使用文件來上傳發布採購需求,對於平臺管理者來講,管理是不可控的,因此最好是開發一個後臺審覈的功能,採購者發佈的需求審覈經過則上傳到藥商匯平臺。
問題2:爲何使用微信機器人來上傳採購需求文件,而不直接在小程序上開發一個上傳採購文件的功能呢?
(1)由於微信機器人可以監聽用戶在PC端使用微信發佈採購需求文件;而小程序只能運行在手機端,沒法運行在PC端;採購文件通常是在PC端編輯的,因此用戶真正的需求是在PC端上傳採購需求文件;微信機器人的產品定位是用接收用戶在PC端發佈的採購文件。
8. 微信機器人程序流程圖
9. 微信機器人itchat_app的代碼以下:
server.py
#!/usr/bin/env python # _*_ coding:UTF-8 _*_ import re import os import time import pickle import json import logging from file_util import FileUtil import itchat import db import str_util import hashlib import sys import json_util file_msg_dict = {} def after_login(): info('login') def after_logout(): info('logout') def info(message): ''' 寫日誌的配置及方法封裝 :param message: :return: ''' LOG_FILE_NAME = 'app' + time.strftime("%Y%m%d", time.gmtime()) + '.log' LOG_FILE_PATH = os.getcwd() + os.path.sep + 'logs' + os.path.sep + LOG_FILE_NAME LOG_FORMAT = '[%(levelname)s]%(asctime)s - %(message)s' DATE_FORMAT = '%Y-%m-%d %H:%M:%S' logger = logging.getLogger() fh = logging.FileHandler(LOG_FILE_PATH) fm = logging.Formatter(LOG_FORMAT) fh.setFormatter(fm) logger.addHandler(fh) logger.setLevel(logging.INFO) logger.info(message) def get_user_msg(user_name): ''' 獲取微信好友的信息 :param user_name: :return: ''' wechat_friend = itchat.search_friends(userName=user_name) return wechat_friend def get_file_name(file_name): ''' 獲取指定文件名的路徑信息 :param file_name: :return: ''' hash = hashlib.md5() hash.update(file_name.encode('utf-8')) file_temp_name = '%s%s%s%s%s' % ( 'itchat', hash.hexdigest(), time.strftime('%Y%m%d', time.gmtime()), '.', file_name.split('.').pop()) file_temp_path = 'download' + os.path.sep + file_temp_name file_oss_url = 'https://chgg-erp-test.oss-cn-beijing.aliyuncs.com/' + 'itchat/' + time.strftime('%Y%m%d', time.gmtime()) + '/' + file_temp_name return file_name, file_temp_name, file_temp_path, file_oss_url def download_file(msg): ''' 下載文件到itchat文件服務器 :param msg: :return: ''' try: msg['Text'](msg['FileName']) except Exception as e: logging.error(e) return False else: file_name, file_temp_name, file_temp_path, file_oss_url = get_file_name(msg['FileName']) os.rename(file_name, file_temp_path) info('download success%s, %s, %s' % (msg['FileName'], msg['Type'], msg['FromUserName'])) return True def handle_download_file(msg): ''' 處理下載文件的全部步驟 :param msg: :return: ''' downlaod_ret = download_file(msg) if not downlaod_ret: return False else: from_user_name = msg['FromUserName'] phone_number = db.db_get_phone_by_from_user_name(from_user_name) file_name = msg['FileName'] file_name, file_temp_name, file_temp_path, file_oss_url = get_file_name(file_name) user_msg = get_user_msg(from_user_name) if not user_msg: user_msg = '' else: _user_msg = { 'UserName': user_msg['UserName'], 'DisplayName': user_msg['DisplayName'], 'RemarkName': user_msg['RemarkName'], 'NickName': user_msg['NickName'], 'City': user_msg['City'], 'HeadImgUrl': user_msg['HeadImgUrl'], 'Sex': user_msg['Sex'], } # user_msg = json_util.class_to_dict(user_msg) user_msg = str(json.dumps(_user_msg)) info(user_msg) row_count = db.db_file_download(from_user_name, phone_number, file_name, file_temp_name, user_msg) return row_count > 0 def handle_upload_file(msg, phone_number): ''' 處理上傳文件到阿里雲的全部步驟 :param msg: :param phone_number: :return: ''' from_user_name = msg['FromUserName'] itchat_file = db.db_get_last_file(from_user_name) file_name = itchat_file['file_name'] file_name, file_temp_name, file_temp_path, file_oss_url = get_file_name(file_name) upload_ret = FileUtil.oss_upload_file(file_temp_path, file_temp_name) if not upload_ret: return False file_msg = file_oss_url db_upload = db.db_file_upload(from_user_name, phone_number, file_name, file_temp_name, file_msg) if not db_upload: return False return True @itchat.msg_register((itchat.content.ATTACHMENT, itchat.content.PICTURE, itchat.content.TEXT), isFriendChat=True, isGroupChat=True) def attachment_handle(msg): ''' 監聽微信的信息並和好友交互 :param msg: :return: ''' Debug = True if Debug: to_user_name = 'filehelper' else: to_user_name = msg['FromUserName'] info(msg) if msg['MsgType'] == 1: if msg['Content'].find('運行狀態', 0, len(msg['Content'])) != -1: itchat.send_msg('正在運行', toUserName=to_user_name) elif msg['Content'] == '是': from_user_name = msg['FromUserName'] itchat_file = db.db_get_last_file(from_user_name) if itchat_file is None: itchat.send_msg('系統異常,請從新發送文件', toUserName=to_user_name) phone_number = db.db_get_phone_by_from_user_name(from_user_name) if not phone_number: itchat.send_msg('請輸入你的手機號碼,必須和藥工匯小程序註冊的手機號碼一致,以識別你在藥工匯的身份信息', toUserName=to_user_name) else: handle_upload = handle_upload_file(msg, phone_number) if not handle_upload: itchat.send_msg('上傳文件%s到藥工匯小程序失敗' % itchat_file['file_name'], toUserName=to_user_name) else: itchat.send_msg('上傳文件%s到藥工匯小程序成功' % itchat_file['file_name'], toUserName=to_user_name) elif str_util.is_phone_number(msg['Content']): phone_number = msg['Content'] from_user_name = msg['FromUserName'] itchat_file = db.db_get_last_file(from_user_name) if not itchat_file: itchat.send_msg('系統異常,請從新發送文件', toUserName=to_user_name) handle_upload = handle_upload_file(msg, phone_number) if not handle_upload: itchat.send_msg('上傳文件%s到藥工匯小程序失敗' % itchat_file['file_name'], toUserName=to_user_name) else: itchat.send_msg('上傳文件%s到藥工匯小程序成功' % itchat_file['file_name'], toUserName=to_user_name) else: pass elif msg['MsgType'] == 3 or msg['MsgType'] == 49: handle_download = handle_download_file(msg) file_name, file_temp_name, file_temp_path, file_oss_url = get_file_name(msg['FileName']) if not handle_download: itchat.send_msg('監聽文件%s失敗' % file_name, to_user_name) else: info('下載文件%s成功, 保存爲%s' % (file_name, file_temp_name)) itchat.send_msg('肯定將%s上傳到藥工匯小程序嗎?肯定上傳請回復是,回覆其餘信息或者不回覆將不會上傳' % file_name, to_user_name) else: pass if __name__ == "__main__": # 自動登陸 itchat.auto_login(hotReload=True, enableCmdQR=True, loginCallback=after_login, exitCallback=after_logout) # 啓動一個工做線程 itchat.run()
db.py
#!/usr/bin/env python # _*_ coding:UTF-8 _*_ import pymysql import time def get_db_and_cursor(): ''' 打開一個數據庫連接 :return: ''' host = 'localhost' username = 'root' password = '123456' database = 'itchat' db = pymysql.connect(host, username, password, database) cursor = db.cursor(cursor=pymysql.cursors.DictCursor) return db, cursor def init_db(): ''' 初始化數據庫 :return: ''' db, cursor = get_db_and_cursor() try: sql = 'DROP TABLE IF EXISTS itchat_file' cursor.execute(sql) sql = 'CREATE TABLE IF NOT EXISTS `itchat_file` (`id` int(8) NOT NULL AUTO_INCREMENT,`from_user_name` varchar(256) NOT NULL,`phone_number` varchar(11) DEFAULT NULL,`file_name` varchar(64) NOT NULL, `file_temp_name` varchar(64) NOT NULL, `is_confirm` int(1) DEFAULT 0,`is_download` int(1) DEFAULT 0,`is_upload_aliyun` int(1) DEFAULT 0,`is_upload_app` int(1) DEFAULT 0, `file_msg` text DEFAULT NULL , `user_msg` text DEFAULT NULL, `created_at` int(10) DEFAULT NULL,`updated_at` int(10) DEFAULT NULL,`is_del` int(1) DEFAULT 0,PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8' cursor.execute(sql) db.commit() print('初始化數據庫itchat_file成功') except: db.rollback() def db_get_phone_by_from_user_name(from_user_name): db, cursor = get_db_and_cursor() phone_number = '' try: sql = "SELECT phone_number FROM itchat_file WHERE from_user_name='%s' AND phone_number IS NOT NULL AND phone_number != ''" % from_user_name cursor.execute(sql) itchat_file = cursor.fetchone() if itchat_file: phone_number = itchat_file['phone_number'] else: phone_number = '' if phone_number is None: phone_number = '' db.commit() except Exception as e: db.rollback() print(e) finally: cursor.close() db.close() return phone_number def db_get_last_file(from_user_name): db, cursor = get_db_and_cursor() itchat_file = None try: sql = "SELECT * FROM itchat_file WHERE from_user_name='%s' ORDER BY created_at DESC" % from_user_name cursor.execute(sql) itchat_file = cursor.fetchone() db.commit() except Exception as e: db.rollback() print(e) finally: cursor.close() db.close() return itchat_file def db_file_download(from_user_name, phone_number, file_name, file_temp_name, user_msg): db, cursor = get_db_and_cursor() row_count = 0 try: # 使用佔位符填充,防止sql注入攻擊 sql = "INSERT INTO itchat_file(from_user_name, phone_number, file_name, file_temp_name, is_download, is_confirm, is_upload_aliyun, is_upload_app, created_at, updated_at, user_msg) VALUES('%s', '%s', '%s', '%s', 1, 0, 0, 0, %d, %d, '%s')" % (from_user_name, phone_number, file_name, file_temp_name, time.mktime(time.localtime()), time.mktime(time.localtime()), user_msg) row_count = cursor.execute(sql) db.commit() except Exception as e: db.rollback() print(e) finally: cursor.close() db.close() return row_count def db_file_upload(from_user_name, phone_number, file_name, file_temp_name, file_msg): db, cursor = get_db_and_cursor() row_count = 0 try: sql = "UPDATE itchat_file SET is_confirm=1, is_upload_aliyun=1, is_upload_app=1, updated_at=%d, phone_number='%s', file_msg='%s' WHERE from_user_name='%s' AND file_name='%s' AND file_temp_name='%s'" % (time.mktime(time.localtime()), phone_number, file_msg, from_user_name, file_name, file_temp_name) row_count = cursor.execute(sql) db.commit() except Exception as e: db.rollback() print(e) finally: cursor.close() db.close() return row_count > 0
file_util.py
#!/usr/bin/env python # _*_ coding:UTF-8 _*_ import os import hashlib import time import oss2 class FileUtil: access_key_id = 'XclfQjpUYBJijjZZ' access_key_secret = '82T3PcaIdLYWHi7gDUscbC8VdDcrb0' end_point = 'http://oss-cn-beijing.aliyuncs.com' bucket = 'chgg-erp-test' @staticmethod def oss_upload_file(file_temp_path, file_temp_name): ''' 上傳文件到阿里雲服務器 :param file_temp_path: :param file_temp_name: :return: ''' serv_file_path = 'itchat/' + time.strftime('%Y%m%d', time.gmtime()) + '/' + file_temp_name auth = oss2.Auth(FileUtil.access_key_id, FileUtil.access_key_secret) bucket = oss2.Bucket(auth, FileUtil.end_point, FileUtil.bucket) try: # with open(local_file_name, 'rb') as fileobj: # # fileobj.seek(1000, os.SEEK_SET) # # current = fileobj.tell() # upload_ret = bucket.put_object(serv_file_path, fileobj) # upload_ret = 'https://chgg-erp-test.oss-cn-beijing.aliyuncs.com/' + serv_file_path # return upload_ret upload_ret = bucket.put_object_from_file(serv_file_path, file_temp_path) upload_ret = 'https://chgg-erp-test.oss-cn-beijing.aliyuncs.com/' + serv_file_path return upload_ret except Exception as e: return False
10. 運維:將代碼部署到測試環境
(1)將代碼上傳到碼雲
git init git add . git commit -m "first commit" git remote add origin https://gitee.com/chggit_liudaoqiang/itchat_app.git git push -u origin master
(2)從碼雲克隆代碼到測試或生產服務器
cd /data/chgg git clone https://gitee.com/chggit_liudaoqiang/itchat_app.git
(3)進入項目虛擬環境
cd /data/chgg/itchat_app source venv/Scripts/activate
(4)在測試環境安裝python3(linux服務器上的python版本爲2.7)
a. 從python官網下載python3.6.6
cd ~ wget https://www.python.org/ftp/python/3.6.6/Python-3.6.6.tgz
b. 解壓python3.6.6壓縮包
tar -zxvf Python-3.6.6.tgz
c. 配置源代碼文件
cd ~/Python-3.6.6 ./configure
d. 安裝
vim Makefile # 將 -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes 中的3改成2
make
make install
問題:python3make到unicodeobject.c就再也不繼續運行,
gcc -pthread -c -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -I. -I./Include -DPy_BUILD_CORE -o Objects/unicodeobject.o Objects/unicodeobject.c
執行到這裏就再也不向下執行
解決辦法爲執行configure命令後將Makefile文件中的 -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes 中的3改成2
即-DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes
(5)安裝阿里雲OSS存儲對象SDK
cd /data/chgg/itchat_app pip3 install oss2
(6)安裝微信機器人itchat包
pip3 install itchat
(7)安裝數據庫操做的庫
pip3 install pymysql
(8)檢查應用程序相關文件
a. 檢查是否存在文件存放文件夾download
# 檢查/data/chgg/itchat_app目錄下是否存在目錄downlaod; 若是沒有則建立該目錄 mkdir -p download
chmod 777 download
b. 檢查是否存在日誌存放文件夾logs
# 檢查/data/chgg/itchat_app目錄下是否存在目錄logs; 若是沒有則建立該目錄 mkdir -p logs chmod 777 logs
c. 將調試狀態改成生產狀態
Debug = True # 改成 Debug = False
d. 修改阿里雲oss的帳號配置
e. 修改數據庫的帳號配置
(9)啓動應用程序
nohup python3 server.py
11,微信我的號的註冊:
(1)註冊一個微信我的號做爲機器人微信號,微信名爲藥工匯,將小型加工商加爲機器人微信號的好友;
(2)使用機器人微信號創建一個微信羣,羣名爲藥工匯服務羣,將小型加工商拉進此微信羣
(3)註冊微信我的號須要手機短信的驗證,全部須要先註冊一個手機號,此手機號只需有短信功能,無需流量,月租越少越好,須要很是清楚的知道協議,發票要有
(4)聯通的米粉卡,月租5元,短信0.1元/條, 電話0.1元/分鐘, 流量1元/天天/1G, 3元封頂; 申請發票爲月結髮票,使用聯通APP進行自定義交費,不能選擇固定金額交費; 註冊米粉卡手機號的途徑爲在微信中收縮米粉卡助手,關注公衆號,點擊申請,填寫地址,而後郵寄;
(5)聯通人工客服電話爲10010接通後按0進入人工服務
(6)可使用QQ號或者郵箱登陸微信
12. 如何使用QQ號註冊新的微信號,並使用新註冊的微信號登錄:
(1)將手機號從原有微信號中解綁
(2)在手機端微信登陸頁面,點擊「更多」,而後點擊「註冊」
(3)填寫註冊相關信息,並使用用戶的手機號進行驗證(此手機號可能已經註冊過微信號)。主要是須要手機號接收的驗證碼
(4)註冊成功後,解綁手機號,並綁定QQ號
(5)使用QQ帳號和密碼登陸微信
注意:新邦的微信沒法解綁手機號; 除非使用選擇忘記密碼找回密碼,這是須要一個沒有綁定綁定微信的手機號以驗證用
12. 微信機器人必須使用手機微信掃碼登陸, 若掃碼手機的微信號推出則微信機器人退出
12. 調試
(1)TypeError: 'NoneType' object is not subscriptable
緣由是列表或字典爲空,沒法使用索引取值(須要對常見的報錯進行總結,知道緣由所在)
(2)TypeError: tuple indices must be integers or slices, not str
緣由是結果爲元組,沒法使用字符串索引從元組中取值
(3)可使用pycharm的debug進行調試,itchat自己的調試可使用filehelper進行調試(須要找一個最有效方便的調試測試方法,若是不用filehelper則必須使用另外一個微信號做爲客戶端進行發送文件測試,頻繁借用同事的手機很難爲情)
(4)使用pycharm的debug工具進行調試,只需點一下按鈕就行看整個過程;反之若是使用命令啓動並使用打印進行調試則費時間
微信好友信息接口結果
{
'MemberList': <ContactList: []>,
'UserName': '@6a3fbfd5f7a22b46842f0af0da0ec7cf00de1618bab9d8e82148b4bcba01a161',
'City': '',
'DisplayName':'',
'PYQuanPin': '',
'RemarkPYInitial': '',
'Province': '',
'KeyWord': '',
'RemarkName': '',
'PYInitial': '',
'EncryChatRoomId': '',
'Alias': '',
'Signature': '',
'NickName': '劉道強',
'RemarkPYQuanPin': '',
'HeadImgUrl': '/cgi-bin/mmwebwx-bin/webwxgeticon?seq=259562817&username=@
6a3fbfd5f7a22b46842f0af0da0ec7cf00de1618bab9d8e82148b4bcba01a161&skey=@crypt_9ecca89f_222960ca1f565099a273b7541c4d26a0',
'UniFriend': 0,
'Sex': 1,
'AppAccountFlag': 0,
'VerifyFlag': 0,
'ChatRoomId': 0,
'HideInputBarFlag': 0,
'AttrStatus': 0,
'SnsFlag': 1,
'MemberCount': 0,
'OwnerUin': 0,
'ContactFlag': 0,
'Uin': 2598508411,
'StarFriend': 0,
'Statues': 0,
'WebWxPluginSwitch': 0,
'HeadImgFlag': 1
}
文件消息結構:
{'MsgId': '1799858425902924703', 'FromUserName': '@3192a354eb69f2ef0fb38798cc99186dbfc5b5a3c952525973f8e6bbb202714d', 'ToUserName': '@3192a354eb69f2ef0fb38798cc99186dbfc5b5a3c952525973f8e6bbb202714d', 'MsgType': 1, 'Content': '消息', 'Status': 3, 'ImgStatus': 1, 'CreateTime': 1552022887, 'VoiceLength': 0, 'PlayLength': 0, 'FileName': '', 'FileSize': '', 'MediaId': '', 'Url': '', 'AppMsgType': 0, 'StatusNotifyCode': 0, 'StatusNotifyUserName': '', 'RecommendInfo': {'UserName': '', 'NickName': '', 'QQNum': 0, 'Province': '', 'City': '', 'Content': '', 'Signature': '', 'Alias': '', 'Scene': 0, 'VerifyFlag': 0, 'AttrStatus': 0, 'Sex': 0, 'Ticket': '', 'OpCode': 0}, 'ForwardFlag': 0, 'AppInfo': {'AppID': '', 'Type': 0}, 'HasProductId': 0, 'Ticket': '', 'ImgHeight': 0, 'ImgWidth': 0, 'SubMsgType': 0, 'NewMsgId': 1799858425902924703, 'OriContent': '', 'EncryFileName': '', 'User': <User: {'MemberList': <ContactList: []>, 'UserName': '@3192a354eb69f2ef0fb38798cc99186dbfc5b5a3c952525973f8e6bbb202714d', 'City': '', 'DisplayName': '', 'PYQuanPin': '', 'RemarkPYInitial': '', 'Province': '', 'KeyWord': '', 'RemarkName': '', 'PYInitial': '', 'EncryChatRoomId': '', 'Alias': '', 'Signature': '', 'NickName': '劉道強', 'RemarkPYQuanPin': '', 'HeadImgUrl': '/cgi-bin/mmwebwx-bin/webwxgeticon?seq=1322683411&username=@3192a354eb69f2ef0fb38798cc99186dbfc5b5a3c952525973f8e6bbb202714d&skey=@crypt_9ecca89f_016f56d6c511a8654127df48176b100d', 'UniFriend': 0, 'Sex': 1, 'AppAccountFlag': 0, 'VerifyFlag': 0, 'ChatRoomId': 0, 'HideInputBarFlag': 0, 'AttrStatus': 0, 'SnsFlag': 1, 'MemberCount': 0, 'OwnerUin': 0, 'ContactFlag': 0, 'Uin': 2598508411, 'StarFriend': 0, 'Statues': 0, 'WebWxPluginSwitch': 0, 'HeadImgFlag': 1}>, 'Type': 'Text', 'Text': '消息'}注意:FromUserName不是固定的,當itchat_app重啓後則每一個用戶的FromUserName則發生改變參考:1,會話管理https://www.cnblogs.com/lyzg/p/6067766.html2. 進程間通訊的5中方式https://www.cnblogs.com/zgq0/p/8780893.html