image = urlretrieve(url=orderimg, filename=r'%s' % os.path.join(current_path, 'orderimg.jpg'))
itchat.send_image(fileDir=r'%s' % os.path.join(current_path, 'orderimg.jpg'),
toUserName=msg['FromUserName'])
**except** Exception **as** e:
print("发送图片失败,{}\n".format(e))
# 等待3秒继续发送
time.sleep(3)
定时发送消息
def send_order_info():
n = 1
while True:
# 判断当前时间是否大于早上7点且小于晚上十一点
if datetime.today().hour > 8 and datetime.today().hour < 23:
print(‘现在时间:’,datetime.today())
# 获取群聊列表
chatroom = itchat.get_chatrooms()
# 遍历群聊列表
for c in chatroom:
n = datetime.today().hour - 7
print(c[‘UserName’],c[‘NickName’])
# 只选择指定的群聊
if c[‘NickName’] == ‘天猫内部精选优惠券1群’:
try:
# 获取淘宝客商品优惠券信息
response = get_tk_coupon(‘’)
# 遍历商品优惠券信息
for r in response:
# 商品标题
ordername = r[‘title’]
# 商品当前价
orderprice = r[‘zk_final_price’]
coupon_info = r[‘coupon_info’]
coupon_demonination = int(re.findall(r’(\d+)‘, coupon_info)[-1])
# 商品图片
orderimg = r[‘pict_url’]
# 获取淘口令
token = get_token(url=r[‘coupon_click_url’], text=r[‘title’])
# 券后价
couponprice = round(float(orderprice) - int(coupon_demonination), 1)
# 生成短链
link = r[‘item_url’]
link_resp = requests.get(
‘http://api.weibo.com/2/short_url/shorten.json?source=2849184197&url_long=’ + link).text
link_short = json.loads(link_resp, encoding=‘utf-8’)[‘urls’][0][‘url_short’]
msgs = ‘’’【{times}点档特惠精选】\n/:gift{name}\n/:rose【在售价】{orderprice}元\n/:heart【券后价】{conponprice}元\n/:cake 【抢购链接】{link_short}\n-----------------\n复制这条信息\n{token}打开【手机淘宝】,即可查看
‘’‘.format(times=str(datetime.today().hour),
name=ordername,
orderprice=orderprice,
conponprice=couponprice,
token=token,
link_short=link_short)
# 发送文本消息
itchat.send(msg=str(msgs), toUserName=c[‘UserName’])
# 发送商品图片
try:
image = urlretrieve(url=orderimg,
filename=r’%s’ % os.path.join(current_path, ‘orderimg.jpg’))
itchat.send_image(fileDir=r’%s’ % os.path.join(current_path, ‘orderimg.jpg’),
toUserName=c[‘UserName’])
except Exception as e:
print(“发送图片失败,{}\n”.format(e))
time.sleep(3)
except Exception as e:
print(‘发送失败’,e)
n += 1
else:
n = 1
time.sleep(3600)
if name == ‘__main__’:
# 登录
itchat.auto_login(hotReload=True,enableCmdQR=False,picDir=r’%s’%os.path.join(current_path,‘qrcode.jpg’))
# 创建一个线程用于侦听微信的消息
t_reply = threading.Thread(target=itchat.run)
# 创建一个线程用于定时发送消息
t_send = threading.Thread(target=send_order_info)
# 启动线程
t_reply.start()
t_send.start()
t_reply.join()
t_send.join()
最后我们来运行一下这个微信机器人,如果当前时间在早上 9 点到晚上 10 点之间,那么在程序运行之后他会首先主动发送 5 条淘宝客商品优惠券消息,效果如图所示:

如果有人在这个指定的群聊里面 @我们,我们就会调用 gettkcoupon() 方法获取淘宝客商品并回复,效果如下图所示:

只要我们的网络不断、电脑不关、微信不退,那么这个淘宝客微信机器人就会一直运行下去。
#### 4、使用 PyQt5 创建微信机器人的桌面程序
上面创建的淘宝客微信机器人完全通过代码来操作和控制,自己使用倒是没什么问题,如果想给更多的人使用,就很不方便了。其便利性和使用的友好性很是欠缺,如果做成一个桌面应用程序,那么就很方便了。
Python 中提供了多种模块来支持编写桌面应用程序,其中包括内置的 tkinter 模块、第三方的 wxPython、PyQt、Kivy 等。这个模块各有优缺点,在此我们选择 PyQt5 来编写我们的淘宝客微信机器人桌面程序。
在开始使用 PyQt5 编写桌面程序之前,我们先来了解一下桌面应用程序的结构。
有前端开发经验的同学都知道,在最基础的前端架构(HTML、CSS、JS)中,HTML 用来定义网页的结构、CSS 用来定义网页页面的样式和布局,JS 则用来控制页面的行为。
而对于一个桌面应用程序,其势必也是有一个结构的,而且其与前端结构中的 HTML、CSS、JS 也有相似之处,比如:
* 主窗体相当于 HTML 中的 标签;
* 主窗体中的窗口部件相当于 HTML 中的标签;
* 窗体中的 Layout 布局层则相当于 CSS 中的浮动定位、绝对定位、Flex 布局定位等;
* 程序中的一些按钮可能点击后停留在上面会执行一些操作,则相当于 JS 的 click 等事件及其所执行的 javascript 代码。
这样应该就能理解了。那么咱们开始使用 PyQt5 写我们的淘宝客微信群聊机器人桌面程序。
4.1、创建 UI 界面和布局
PyQt5 可以通过 pip 命令直接进行安装:
pip install PyQt5
在安装完成之后,我们在我们的项目目录下再新建一个名为 mainUI.py 的 Python 文件:

我们的桌面程序的代码主要在这个文件中编写。在开始设计 UI 界面之前,我们先来规划一下我们的淘宝客微信群聊机器人的界面(画一个简单的原型图):

可以发现,界面主要由两部分组成:
* 上层的功能按钮和输入框;
* 下层的文本输入控制台;
上层的功能按钮和输入框使用两个 GroupBox 分组:
* 一个为登录和注销按钮的按钮组;
* 一个为功能选项的按钮和输入框组;
下层的文本控制台则就是一个文本标签。
**4.1.1、创建主窗体**
照例我们先引入所需要的所有模块:
coding:utf-8
from PyQt5.QtCore import QThread
from PyQt5.QtWidgets import *
from PyQt5 import QtGui
import sys
import itchat
from itchat.content import *
import datetime
import time
import os
import top.api
import requests
import json
import re
from urllib.request import urlretrieve
然后定义一个全局变量,用于获取当前文件的路径:
current_path = os.path.dirname(os.path.abspath(file))
接着,通过继承 QMainWindow,创建一个主窗口的类:
class MainGUI(QMainWindow):
def __init__(self):
super()._init_()
在 MainGUI 类中,创建一个 iniUI() 方法,用于初始化设置主窗体的信息:
'''
程序默认UI界面信息
‘’’
def iniUI(self):
self.setWindowTitle(“州的先生淘宝客微信机器人v0.1”)
self.resize(1200, 600)
# 设置程序图标
icon = QtGui.QIcon()
icon.addPixmap(QtGui.QPixmap("logo.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.setWindowIcon(icon)
在 iniUI() 方法中,我们通过 setWindowTitle() 设置了主窗体的标题,通过 resize() 设置了主窗体的初始大小,通过 setWindowIcon() 设置了主窗体的 logo 图标。我们将这个 iniUI() 方法添加到 MainGUI() 类的**init**() 方法中,然后运行代码:
class MainGUI(QMainWindow):
def __init__(self):
super().init()
self.iniUI()
‘’’
程序默认UI界面信息
‘’’
def iniUI(self):
self.setWindowTitle(“州的先生淘宝客微信机器人v0.1”)
self.resize(1200, 600)
# 设置程序图标
icon = QtGui.QIcon()
icon.addPixmap(QtGui.QPixmap(“logo.png”), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.setWindowIcon(icon)
if name == ‘__main__’:
app = QApplication(sys.argv)
gui = MainGUI()
gui.show()
sys.exit(app.exec_())
最后出现了如下图这样的一个 GUI 界面:

里面空空如也,只有一个主窗体,没关系接下来我们就在这个主窗体里面添加其他的窗口部件和布局。
**4.1.2、添加窗口部件和布局**
在主窗体创建之后,我们继续在主窗体中添加最基础的窗口部件。在 MainUI() 类中新建一个方法 verticalboxlayout(),在其中创建布局和部件:
# 水平垂直布局
**def** **vertical\_box\_layout**(self):
'''
上层功能盒子
‘’’
# 创建一个用于存放登录相关按钮的窗口部件
login_buttons = QWidget()
login_buttons_box = QVBoxLayout()
# 设置窗口部件的布局为垂直盒子布局
login_buttons.setLayout(login_buttons_box)
# 创建两个登录相关的按钮
self.refresh_button = QPushButton("点击登录")
self.exit_button = QPushButton("退出登陆")
self.exit_button.setEnabled(**False**)
# 将按钮添加到窗口部件中
login_buttons_box.addWidget(self.refresh_button)
login_buttons_box.addWidget(self.exit_button)
# 创建一个登录按钮的组盒子
login_box = QGroupBox()
login_box.setTitle("登陆选项")
# 设置登陆盒子布局为网格布局
login_box_layout = QGridLayout()
login_box.setLayout(login_box_layout)
# 将按钮窗口部件添加到网格布局中
login_box_layout.addWidget(login_buttons,0,1)
# 创建群聊列表子盒子
chatroom_box = QGroupBox()
chatroom_box.setTitle("群聊列表")
# 创建群聊列表的垂直布局层
chatroom_box_layout = QVBoxLayout()
# 设置群聊列表子盒子的布局层
chatroom_box.setLayout(chatroom_box_layout)
# 创建一个群聊部件
scroll_widget = QWidget()
# 创建群聊不见的布局层
self.scroll_widget_layout = QVBoxLayout()
# 设置群聊不见的布局层为self.scroll\_widget\_layout
scroll_widget.setLayout(self.scroll_widget_layout)
# 创建一个可滚动区域
scroll = QScrollArea()
# 在可滚动区域中设置窗口部件为scroll\_widget
scroll.setWidget(scroll_widget)
scroll.setAutoFillBackground(**True**)
scroll.setWidgetResizable(**True**)
# 在群里盒子布局中添加可滚动区域
chatroom_box_layout.addWidget(scroll)
# 创建文件及Token子盒子
settings_box = QGroupBox()
settings_box.setTitle("配置信息")
settings_box_layout = QGridLayout()
settings_box.setLayout(settings_box_layout)
# 创建输入框
key_name = QLabel("AppKey:")
sec_name = QLabel("Secret:")
adzone_name = QLabel("Adzone\_id:")
self.appkey = QLineEdit()
self.secret = QLineEdit()
self.adzone_id = QLineEdit()
file_name = QLabel("优惠券文件路径:")
self.coupon_file = QLineEdit()
choose_file = QPushButton("选择文件")
# 添加输入框到settings\_box\_layout中
settings_box_layout.addWidget(key_name,0,0)
settings_box_layout.addWidget(self.appkey,0,1)
settings_box_layout.addWidget(sec_name,1,0)
settings_box_layout.addWidget(self.secret,1,1)
settings_box_layout.addWidget(adzone_name,2,0)
settings_box_layout.addWidget(self.adzone_id,2,1)
settings_box_layout.addWidget(file_name,3,0)
settings_box_layout.addWidget(self.coupon_file,3,1)
settings_box_layout.addWidget(choose_file,4,0)
# 创建控制按钮盒子
control_box = QGroupBox()
control_box.setTitle("控制开关")
control_box_layout = QVBoxLayout()
control_box.setLayout(control_box_layout)
# 创建控制按钮
self.start_run = QPushButton("开启机器人")
self.end_run = QPushButton("停止机器人")
self.end_run.setEnabled(**False**)
self.check_info = QPushButton("检查配置信息")
# 将控制按钮添加到控制按钮盒子中
control_box_layout.addWidget(self.start_run,0)
control_box_layout.addWidget(self.end_run,1)
control_box_layout.addWidget(self.check_info,2)
# 选项盒子
select_box = QGroupBox()
select_box.setTitle("功能选项")
# 选项盒子布局
select_box_layout = QGridLayout()
select_box.setLayout(select_box_layout)
# 将群聊列表盒子、配置信息盒子和控制按钮盒子添加到选项盒子中
select_box_layout.addWidget(chatroom_box,0,0)
select_box_layout.addWidget(settings_box,0,1)
select_box_layout.addWidget(control_box,0,2)
# 窗口主部件中上层功能按钮的布局
utils_box = QGridLayout()
# 添加登录盒子和选项盒子到上层布局中
utils_box.addWidget(login_box,0,0)
utils_box.addWidget(select_box,0,1)
'''
下层控制台盒子
‘’’
# 创建一个文本框
self.label_1 = QTextEdit()
self.label_1.setReadOnly(True)
# 窗口主部件中下层控制台的布局
console_box = QVBoxLayout()
console_box.addWidget(self.label_1)
'''
主窗体的布局
‘’’
# 窗口主部件
self.Widget = QWidget()
# 设置窗口主部件的布局层
widget_box = QVBoxLayout()
self.Widget.setLayout(widget_box)
# 在窗口主部件的布局层中添加功能按钮层和控制台层
widget_box.addLayout(utils_box)
widget_box.addLayout(console_box)
'''页面初始化层'''
# 设置UI界面的核心窗口为layout\_widget
self.setCentralWidget(