微信机器人的做用
- 方便用户上传采购需求文件,用户的采购需求文件通常是在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