使用 Python 全栈打造淘宝客微信机器人_python top

            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 条淘宝客商品优惠券消息,效果如图所示:


![enter image description here](https://img-blog.csdnimg.cn/img_convert/eecd3b089975ffcfd15028b1145cb561.png)


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


![enter image description here](https://img-blog.csdnimg.cn/img_convert/4eadee48e2309f43571890640e9bac76.png)


只要我们的网络不断、电脑不关、微信不退,那么这个淘宝客微信机器人就会一直运行下去。


#### 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 文件:


![enter image description here](https://img-blog.csdnimg.cn/img_convert/7ada15f2730d92986a40c4dbd9137bcd.png)


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


![enter image description here](https://img-blog.csdnimg.cn/img_convert/313b5b917d059c8f690c4891ba6fdee7.png)


可以发现,界面主要由两部分组成:


* 上层的功能按钮和输入框;
* 下层的文本输入控制台;


上层的功能按钮和输入框使用两个 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 界面:


![enter image description here](https://img-blog.csdnimg.cn/img_convert/4f3a6c18feb9b31a750e56bfd6ea2003.png)


里面空空如也,只有一个主窗体,没关系接下来我们就在这个主窗体里面添加其他的窗口部件和布局。


**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(self.Widget)

之后,我们再将 verticalboxlayout() 方法添加到 iniUI() 方法中:



**def** **iniUI**(**self**):
    **self**.setWindowTitle("州的先生淘宝客微信机器人v0.1")
    **self**.resize(1200, 600)

    **self**.vertical_box_layout()
    # 用于存放群聊列表元素
    **self**.chatroom_list = []
    **self**.current_date = datetime.datetime.strftime(datetime.datetime.today(),'%Y-%m-%d')

    # 设置程序图标
    icon = QtGui.QIcon()
    icon.addPixmap(QtGui.QPixmap("logo.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
    **self**.setWindowIcon(icon)

这样,我们的窗口 UI 界面就已经创建好了,运行代码,会出现如下图所示的界面:


![enter image description here](https://img-blog.csdnimg.cn/img_convert/48fd8580dd412299a055a4e008b0bd46.png)


在这个 UI 界面中,我们:


* 使用 QWidget() 来创建空的窗口部件;
* 使用 QVBoxLayout() 来创建垂直盒子布局层;
* 使用 QGroupBox() 来创建分组盒子;
* 使用 QGridLayout() 来创建网格布局层;
* 使用 QScrollArea() 来创建一个可滚动区域;
* 使用 QPushButton() 来创建按钮;
* 使用 QLabel() 来创建文本标签;
* 使用 QLineEdit() 来创建单行文本输入框;
* 使用 QTextEdit() 创建一个多行文本域;


代码中基本上每一句都有注释,还有不懂的地方可以加我微信 taoist\_ling 咨询。


程序的 UI 界面创建好了,接下来就需要创建界面背后的功能函数了:


* 点击登录按钮:实现弹出微信登录的二维码供我们扫码登录,登录成功之后,按钮变为禁用状态,同时退出登录按钮状态变为激活状态;同时动态获取群聊列表,将其以复选框的形式添加到群聊列表部件中;
* 点击退出按钮:实现微信网页端的注销;
* 点击开启机器人按钮:实现侦听微信消息自动回复群聊的搜索和主动发送消息;
* 点击检查配置信息:在控制台中输出配置信息中填写的信息和选择的群聊;
* 文本控制台中输出每个操作的提示;


这些功能中有一些只是简单的操作,而有一些操作则涉及到了很多耗时的的运算,如果直接写在主类里面,在主线程中运行会直接堵塞 UI 界面导致 UI 界面无响应,所以上述的功能中一部分我们直接写在 MainGUI 主类中,一部分我们使用 QThread 子线程来实现。


4.2、创建功能方法


**4.2.1、创建一个控制台文本输出函数**


因为在我们的 UI 界面中,下次的多行文本框是用作程序的信息输出控制台的,所以我们先来定义一个文本输入函数,在 MainGUI 类中定义一个方法 outputWritten(),详细代码如下所示:



# 在控制台中写入信息
**def** **outputWritten**(**self**, text=None):
    # 获取文本框中文本的游标
    cursor = **self**.label_1.textCursor()
    # 将游标位置移动到当前文本的结束处
    cursor.movePosition(QtGui.QTextCursor.End)
    # 写入文本
    cursor.insertText(text)
    # 设置文本的游标为创建了cursor
    **self**.label_1.setTextCursor(cursor)
    **self**.label_1.ensureCursorVisible()

在这个方法中,我们通过移动文本框的游标来实现不断地在多行文本框中写入文本。


4.2.2、创建微信注销功能函数


在前面介绍 itchat 的时候我们知道,可以直接通过 itchat.logout() 实现微信的注销。现在我们将其加入到一个功能函数中:



# 退出登陆
**def** **logOut**(**self**):
    # 设置登录按钮为激活状态
    **self**.refresh_button.setEnabled(True)
    # 在文本控制台中输入
    **self**.outputWritten("退出微信登录\n")
    # 注销微信登录
    itchat.logout()
    # 设置注销按钮为禁用状态
    **self**.exit_button.setEnabled(False)

在这里,我们首先通过按钮的 setEnabled() 方法设置登录按钮的状态为激活,然后调用刚刚创建的控制台文本输出方法 outputWritten() 在控制台中输入文本,接着调用 itchat.logout() 方法执行注销,最后设置注销按钮的状态为禁用。


**4.2.3、创建一个动态生成群聊选项的方法**


在微信登录成功之后,我们会获取到群聊的对象然后将其添加到可滚动区域部件中,这个操作我们通过新建一个方法来实现:



# 生成群聊列表
def generate_chatroom(**self**,chatrooms):
    # 清空原有群里列表
    **while** **self**.scroll_widget_layout.count():
        item = **self**.scroll_widget_layout.takeAt(0)
        widget = item.widget()
        widget.deleteLater()
    # 获取群里字典
    chatrooms = chatrooms
    **self**.chatroom_dict = dict()
    **try**:
        **for** c,i in zip(chatrooms, range(len(chatrooms))):
            **print**(c['NickName'],c['UserName'])
            checkbox = QCheckBox(c['NickName'])
            checkbox.id_ = i
            **self**.chatroom_dict[c['NickName']] = c['UserName']
            checkbox.stateChanged.connect(**self**.checkChatRoom)  # 1
            **self**.scroll_widget_layout.addWidget(checkbox)
        **self**.outputWritten("生成群聊成功!\n")
    except **Exception** **as** e:
        **print**(e)

**4.2.4、获取群聊的选择状态:**


在动态添加群聊选项到可滚动区域部件中后,我们还需要在选择一个群聊的时候能够在文本控制台中有相应的提示。所以我们再新建一个方法:



# 获取群聊复选框选择状态
**def** **checkChatRoom**(self, state):
    **try**:
        checkBox = self.sender()
        **if** state == Qt.Unchecked:
            self.outputWritten(u'取消选择了{0}: {1}\n'.format(checkBox.id_, checkBox.text()))
            self.chatroom_list.remove(self.chatroom_dict[checkBox.text()])
        **elif** state == Qt.Checked:
            self.outputWritten(u'选择了{0}: {1}\n'.format(checkBox.id_, checkBox.text()))
            self.chatroom_list.append(self.chatroom_dict[checkBox.text()])
    **except** Exception **as** e:
        self.outputWritten("获取群聊选择状态失败:{}\n".format(e))

**4.2.5、创建获取所有输入值和选择值的方法**


在 UI 界面中我们有很多需要填写和选择的选择框、输入框等。我们的 UI 界面也创建了一个 “检查配置信息” 的按钮,我们为其创建一个方法,用于获取所有的输入值和选择值:



# 获取输入及选择的参数
**def** **get\_check\_info**(**self**):
    **try**:
        **self**.outputWritten("选择的群聊为:{}\**n**".format(**self**.chatroom\_list))
        **self**.outputWritten("输入的**AppKey**为:{}\**n**".format(**self**.appkey.text()))
        **self**.outputWritten("输入的**sercet**为:{}\**n**".format(**self**.secret.text()))
        **self**.outputWritten("输入的**adzone\_id**为:{}\**n**".format(**self**.adzone\_id.text()))
        **self**.outputWritten("选择的优惠券文件为:{}\**n**".format(**self**.coupon\_file.text()))
        **self**.outputWritten("++++++++++++++++++++++++++++++++++++++++++++++++++++++\**n**")
    **except** **Exception** **as** **e**:
        **print**(**e**)

**4.2.6、创建微信登录子线程**


为了在程序功能执行的时候不堵塞主线程的 UI 界面,接下来,我们对微信的登录、自动回复消息和定时发送消息都使用 PyQt 提供的线程类 QThread 来实现子线程的调用。


首先,定义一个名为 LoginWechat() 的类,继承 QThread:



登陆微信

class LoginWechat(QThread):


然后,定义一个 PyQt5 中的自定义信号,用于在主线程中能够对其进行调用:



# 自定义一个信号
**finished\_signal** = pyqtSignal(str)

接着,定义初始化方法\*\* init\*\*(),因为在子线程中也要对主线程的 UI 界面中的元素和部件进行操作,所以需要接受那些元素和部件作为参数:



**def** **\_\_init\_\_**(**self**,parent=None,label=None,scroll_widget_layout=None,refresh_button=None,exit_button=None):
    **super**().__init_\_(parent)
    **self**.l = label
    **self**.scroll_widget_layout = scroll_widget_layout
    **self**.refresh_button = refresh_button
    **self**.exit_button = exit_button

同样定义一个控制台的文本输出方法:



# 在控制台中写入信息
**def** **outputWritten**(**self**, text=None):
    cursor = **self**.l.textCursor()
    cursor.movePosition(QtGui.QTextCursor.End)
    cursor.insertText(text)
    **self**.l.setTextCursor(cursor)
    **self**.l.ensureCursorVisible()

接着,我们自定义 itchat 对微信登录的过程,在登录成功之后返回群聊列表:



# 获取uuid
**def** **open\_qr**(self):
    **for** get_count **in** range(1):
        self.outputWritten('获取uuid中……\n')
        uuid = itchat.get_QRuuid()
        **while** uuid **is** **None**:
            uuid = itchat.get_QRuuid()
            time.sleep(1)
        self.outputWritten('成功获取uuid\n')
        **if** itchat.get_QR(uuid,picDir=r'%s'%os.path.join(current_path,'qrcode.jpg')):
            **break**
        **elif** get_count >= 1:
            self.outputWritten("获取二维码出错,请重启程序\n")
            sys.exit()

    **return** uuid

# 二维码登陆
**def** **login\_wechat**(self):
    **try**:
        uuid = self.open_qr()
        self.outputWritten("请扫描二维码\n")
        waitForConfirm = **False**
        **while** 1:
            status = itchat.check_login(uuid)
            **if** status == '200':
                **break**
            **elif** status == '201':
                **if** waitForConfirm:
                    self.outputWritten('请进行确认\n')
                    waitForConfirm = **True**
            **elif** status == '408':
                self.outputWritten('重新加载二维码\n')
                time.sleep(3)
                uuid = self.open_qr()
                waitForConfirm = **False**
        userInfo = itchat.web_init()
        itchat.show_mobile_login()
        itchat.get_friends(**True**)
        self.outputWritten('登陆成功!账号为:%s\n' % userInfo['User']['NickName'])
        itchat.start_receiving()
        self.refresh_button.setText("已登录:{}".format(userInfo['User']['NickName']))
        self.exit_button.setEnabled(**True**)
    **except** Exception **as** e:
        print("登录出错:",e)
        self.outputWritten('登陆出错:{}\n'.format(e))
    **try**:
        # 获取群聊列表
        chatrooms = itchat.get_chatrooms()
        **return** chatrooms
    **except** Exception **as** e:
        self.outputWritten("获取群聊列表出错:{}\n".format(e))

最后,重写 run() 方法,在 run() 方法中设置两个登录按钮的状态,并将 login\_wechat() 方法中返回的群聊数据进行返回:



def run(**self**):
    **try**:
        **self**.refresh_button.setEnabled(**False**)
        **self**.exit_button.setEnabled(**True**)
        **self**.finished_signal.emit(**self**.login_wechat())
    except **Exception** **as** e:
        **self**.outputWritten("运行登录线程出错:{}\n".format(e))

**4.2.7、创建自动回复消息子线程**


继续创建一个继承于 QThread 的类,用于自动回复群聊搜索:



启动自动回复

class StartBot(QThread):
finished_signal = pyqtSignal(str)
# 接受一些按钮和文本信息作为参数
def __init__(self,parent=None,appkey=None,secret=None,adzone_id=None,label=None,start_button=None,end_button=None,chatrooms=None):
super().init(parent)
self.appkey = appkey
self.secret = secret
self.adzone_id = adzone_id
self.l = label
self.start_button = start_button
self.end_button = end_button
self.chatrooms = chatrooms

# 在控制台中写入信息
**def** **outputWritten**(self, text=None):
    cursor = self.l.textCursor()
    cursor.movePosition(QtGui.QTextCursor.End)
    cursor.insertText(text)
    self.l.setTextCursor(cursor)
    self.l.ensureCursorVisible()

# 通过淘宝客API搜索优惠券
**def** **get\_tk\_coupon**(self,kw,size=5):
    req = top.api.TbkDgItemCouponGetRequest()
    req.set_app_info(top.appinfo(self.appkey.text(), self.secret.text()))

    req.adzone_id = int(self.adzone_id.text())
    req.platform = 2
    # req.cat = "16,18"
    req.page_size = size
    req.q = kw
    req.page_no = 1
    **try**:
        resp = req.getResponse()['tbk\_dg\_item\_coupon\_get\_response']['results']['tbk\_coupon']
        **return** resp
    **except** Exception **as** e:
        self.outputWritten(str(e))

# 通过类目返回优惠券
**def** **get\_cat\_coupon**(self,cate_id):
    req = top.api.TbkDgItemCouponGetRequest()
    req.set_app_info(top.appinfo(self.appkey.text(), self.secret.text()))

    req.adzone_id = int(self.adzone_id.text())
    req.platform = 2
    req.cat = cate_id
    req.page_size = 10
    req.page_no = 1
    **try**:
        resp = req.getResponse()['tbk\_dg\_item\_coupon\_get\_response']['results']['tbk\_coupon']
        **return** resp
    **except** Exception **as** e:
        self.outputWritten(str(e))

# 获取淘口令
**def** **get\_token**(self,url, text):
    req = top.api.TbkTpwdCreateRequest()
    req.set_app_info(top.appinfo(self.appkey.text(), self.secret.text()))

    req.text = text
    req.url = url
    **try**:
        resp = req.getResponse()['tbk\_tpwd\_create\_response']['data']['model']
        **return** resp
    **except** Exception **as** e:
        print(e)
        **return** **None**

**def** **run**(self):
    self.start_button.setEnabled(**False**)
    self.end_button.setEnabled(**True**)
    # 回复群聊搜索

@itchat.msg_register(TEXT, isGroupChat=True)
def text_reply(msg):
if msg[‘isAt’] and msg[‘FromUserName’] in self.chatrooms:
searchword = msg[‘Content’][9:]
self.outputWritten(‘消息来自于:{0},内容为:{1}\n’.format(msg[‘ActualNickName’], msg[‘Content’]))
response = self.get_tk_coupon(searchword)
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 = self.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 = ‘’’/:gift{name}\n/:rose【在售价】{orderprice}元\n/:heart【券后价】{conponprice}元\n/:cake 【抢购链接】{link_short}\n-----------------\n复制这条信息\n{token}打开【手机淘宝】,即可查看\n------------------\n
‘’‘.format(name=ordername, orderprice=orderprice, conponprice=couponprice, token=token,
link_short=link_short)
itchat.send(msg=str(msgs), toUserName=msg[‘FromUserName’])
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=msg[‘FromUserName’])
except Exception as e:
self.outputWritten(“发送图片失败,{}\n”.format(e))
time.sleep(3)
itchat.run()


**4.2.8、创建定时发送消息子线程**


在上一节的命令行界面的微信群聊机器人中,我们设置了从早上 9 点到晚上 10 点每一个小时都主动发送商品优惠券信息,后面思考了一下,觉得这样的发送频率太高,容易对用户造成信息骚扰。所以在此将定时发送消息的机制改为两次,早上发上 8 点主动发送一次商品优惠券信息,晚上 8 点主动发送一次搜索的使用方法:



定时自动发送消息

class AutoSend(QThread):
finished_signal = pyqtSignal(str)

**def** **\_\_init\_\_**(self,parent=None,appkey=None,secret=None,adzone_id=None,label=None,start_button=None,end_button=None,chatrooms=None):
    super().__init__(parent)
    self.appkey = appkey
    self.secret = secret
    self.adzone_id = adzone_id
    self.l = label
    self.start_button = start_button
    self.end_button = end_button
    self.chatrooms = chatrooms

# 在控制台中写入信息
**def** **outputWritten**(self, text=None):
    cursor = self.l.textCursor()
    cursor.movePosition(QtGui.QTextCursor.End)
    cursor.insertText(text)
    self.l.setTextCursor(cursor)
    self.l.ensureCursorVisible()

# 通过淘宝客API搜索优惠券
**def** **get\_tk\_coupon**(self,kw,size=5):
    req = top.api.TbkDgItemCouponGetRequest()
    req.set_app_info(top.appinfo(self.appkey.text(), self.secret.text()))

    req.adzone_id = int(self.adzone_id.text())
    req.platform = 2
    # req.cat = "16,18"
    req.page_size = size
    req.q = kw
    req.page_no = 1
    **try**:
        resp = req.getResponse()['tbk\_dg\_item\_coupon\_get\_response']['results']['tbk\_coupon']
        **return** resp
    **except** Exception **as** e:
        self.outputWritten(str(e))

# 获取淘口令
**def** **get\_token**(self,url, text):
    req = top.api.TbkTpwdCreateRequest()
    req.set_app_info(top.appinfo(self.appkey.text(), self.secret.text()))

    req.text = text
    req.url = url
    **try**:
        resp = req.getResponse()['tbk\_tpwd\_create\_response']['data']['model']
        **return** resp
    **except** Exception **as** e:
        print(e)
        **return** **None**

# 定时自动发送优惠券消息
**def** **send\_coupon**(self):
    **while** **True**:
        # 获取选择的群聊列表
        **for** c **in** self.chatrooms:
            # 每天早上8点定时推送商品优惠券
            **if** datetime.datetime.today().hour == 8:
                print('现在时间:', datetime.datetime.today())
                **try**:
                    response = self.get_tk_coupon(kw='精选',size=3)
                    **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 = self.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 = '''【清晨特惠精选】\n/:gift{name}\n/:rose【在售价】{orderprice}元\n/:heart【券后价】{conponprice}元\n/:cake 【抢购链接】{link\_short}\n-----------------\n复制这条信息\n{token}打开【手机淘宝】,即可查看

‘’‘.format(name=ordername,
orderprice=orderprice,
conponprice=couponprice,
token=token,
link_short=link_short)
itchat.send(msg=str(msgs), toUserName=c)
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)
except Exception as e:
self.outputWritten(“发送图片失败,{}\n”.format(e))
time.sleep(3)
except Exception as e:
self.outputWritten(“发送失败:{}\n”.format(e))
# 晚上六点定时发送使用说明消息
elif datetime.datetime.today().hour == 20:
itchat.send(msg=“【优惠券搜索使用说明】\n,@我+搜索名称,即可收到5条精选天猫淘宝商品内部优惠券\n”,
toUserName=c)
time.sleep(3600)

**def** **run**(self):
    **try**:
        self.send_coupon()
    **except** Exception **as** e:
        self.outputWritten("定时发送消息出错:{}\n".format(e))

**4.2.9、在 MainGUI 类中创建调用子线程的方法**


在上面,我们新建了三个继承自 QThread 的类,分别是:


* LoginWechat():用于登录微信,返回群聊对象;
* StartBot():用于恢复群聊中的搜索;
* AutoSend():用于启动定时发送消息;


现在,我们需要在主类 MainGUI 中对其进行调用,所以我们分别在 MainGUI() 中创建三个方法,用于实例化这三个线程并启动它们:


首先是登录微信的线程:



# 登录微信 - 线程
def login_wechat(**self**):
    **try**:
        **self**.login_wechat_thread = LoginWechat(
            label=**self**.label_1,
            scroll_widget_layout=**self**.scroll_widget_layout,
            refresh_button=**self**.refresh_button,
            exit_button=**self**.exit_button,

        )
        **self**.login_wechat_thread.finished_signal.connect(**self**.generate_chatroom)
        **self**.login_wechat_thread.start()
    except **Exception** **as** e:
        **print**("执行登录线程出错:",e)
        **self**.outputWritten("执行登录线程出错:{}\n".format(e))

然后,我们在一个方法中同时启用群聊回复和主动发送消息的线程:



# 启动自动回复和主动发送消息 - 线程
def start_bot(**self**):
    **try**:
        **self**.outputWritten("开始自动回复……\n")
        **self**.start_boot_thread = StartBot(
            appkey=**self**.appkey,
            secret=**self**.secret,
            adzone_id=**self**.adzone_id,
            label=**self**.label_1,
            start_button=**self**.start_run,
            end_button=**self**.end_run,
            chatrooms=**self**.chatroom_list
        )
        **self**.auto_send_coupon_tread = AutoSend(
            appkey=**self**.appkey,
            secret=**self**.secret,
            adzone_id=**self**.adzone_id,
            label=**self**.label_1,
            start_button=**self**.start_run,
            end_button=**self**.end_run,
            chatrooms=**self**.chatroom_list
        )
        **self**.start_boot_thread.finished_signal.connect(**self**._show_message)
        **self**.auto_send_coupon_tread.finished_signal.connect(**self**._show_message)
        **self**.start_boot_thread.start()
        **self**.auto_send_coupon_tread.start()
    except **Exception** **as** e:
        **self**.outputWritten('{}\n'.format(e))

**4.2.10 将按钮与功能函数方法进行绑定**


经过上面的若干步骤,我们创建好了一个 UI 界面,同时也创建了诸多个实际的功能方法。现在问题来了,如何将它们一一对应进行关联呢?我们可以使用 PyQt5 中部件的 clicked 事件 connect 方法来关联对应的方法。先来看一下每个方法所对应的按钮部件:


* “点击登录” 按钮对应于 login\_wechat() 方法;
* “退出登录” 按钮对应于 logOut() 方法;
* “开启机器人” 按钮对应于 start\_bot() 方法;
* “检查配置信息” 按钮对应于 getcheckinfo() 方法;


下面,我们调用这些按钮 clicked 事件将对应的方法绑定在一起,在 MainGUI 类的 verticalboxlayout() 方法中继续添加以下代码:



    **self**.refresh\_button.clicked.connect(**self**.login\_wechat)
    **self**.exit\_button.clicked.connect(**self**.logOut)
    **self**.check\_info.clicked.connect(**self**.get\_check\_info)
    **self**.start\_run.clicked.connect(**self**.start\_bot)

这样,就完成了整个淘宝客微信群聊机器人的编写。我们来运行一下看看效果如何。 登录微信并动态生成群聊列表:


![enter image description here](https://img-blog.csdnimg.cn/img_convert/2d88f161171362b39450a80cd3b9a401.gif)


开启自动回复和主动发送消息:


![enter image description here](https://img-blog.csdnimg.cn/img_convert/485d88a4936607aec2ef3563afd27a20.png)


手机上的效果:


![enter image description here](https://img-blog.csdnimg.cn/img_convert/7d7f3a04e78d5b14e38ab01052e7c888.png)


最后,完整的代码如下所示,对程序和代码有任何不理解的,欢迎添加添加我的私人微信号: taoist\_ling,交流讨论:



coding:utf-8

from PyQt5.QtCore import QThread, pyqtSignal, Qt
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
import traceback

current_path = os.path.dirname(os.path.abspath(file))

global chatrooms

class MainGUI(QMainWindow):
def __init__(self):
super().init()
self.iniUI()

'''

程序默认UI界面信息
‘’’
def iniUI(self):
self.setWindowTitle(“州的先生淘宝客微信机器人v0.1”)
self.resize(1200, 600)

    self.vertical_box_layout()

    self.chatroom_list = []
    self.current_date = datetime.datetime.strftime(datetime.datetime.today(),'%Y-%m-%d')

    # 设置程序图标
    icon = QtGui.QIcon()
    icon.addPixmap(QtGui.QPixmap("logo.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
    self.setWindowIcon(icon)

# 水平垂直布局
**def** **vertical\_box\_layout**(self):

    '''

上层功能盒子
‘’’

    # 创建一个用于存放登录相关按钮的窗口部件
    login_buttons = QWidget()
    login_buttons_box = QVBoxLayout()
    # 设置窗口部件的布局为垂直盒子布局
    login_buttons.setLayout(login_buttons_box)

    # 创建两个登录相关的按钮
    self.refresh_button = QPushButton("点击登录")
    self.refresh_button.clicked.connect(self.login_wechat)
    self.exit_button = QPushButton("退出登陆")
    self.exit_button.clicked.connect(self.logOut)
    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("选择文件")
    choose_file.clicked.connect(self.choose_coupon_file)
    # 添加输入框到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.start_run.clicked.connect(self.start_bot)
    self.end_run = QPushButton("停止机器人")
    self.end_run.setEnabled(**False**)
    self.check_info = QPushButton("检查配置信息")
    self.check_info.clicked.connect(self.get_check_info)
    # 将控制按钮添加到控制按钮盒子中
    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)

    '''页面初始化层'''
    self.setCentralWidget(self.Widget)

'''

功能函数
‘’’
# 退出登陆
def logOut(self):
# 设置登录按钮为激活状态
self.refresh_button.setEnabled(True)
# 在文本控制台中输入
self.outputWritten(“退出微信登录\n”)
# 注销微信登录
itchat.logout()
# 设置注销按钮为禁用状态
self.exit_button.setEnabled(False)

# 选择优惠券文件
**def** **choose\_coupon\_file**(self):
    **try**:
        choose = QFileDialog.getOpenFileName(self,'选择文件','','Excel files(\*.xls)')
        print(choose)
        **if** choose:
            self.coupon_file.setText(choose[0])
    **except** Exception **as** e:
        self.outputWritten('{}\n'.format(e))

# 在控制台中写入信息
**def** **outputWritten**(self, text=None):
    # 获取文本框中文本的游标
    cursor = self.label_1.textCursor()
    # 将游标位置移动到当前文本的结束处
    cursor.movePosition(QtGui.QTextCursor.End)
    # 写入文本
    cursor.insertText(text)
    # 设置文本的游标为创建了cursor
    self.label_1.setTextCursor(cursor)
    self.label_1.ensureCursorVisible()

# 获取输入及选择的参数
**def** **get\_check\_info**(self):
    **try**:
        self.outputWritten("选择的群聊为:{}\n".format(self.chatroom_list))
        self.outputWritten("输入的AppKey为:{}\n".format(self.appkey.text()))
        self.outputWritten("输入的sercet为:{}\n".format(self.secret.text()))
        self.outputWritten("输入的adzone\_id为:{}\n".format(self.adzone_id.text()))
        self.outputWritten("选择的优惠券文件为:{}\n".format(self.coupon_file.text()))
        self.outputWritten("++++++++++++++++++++++++++++++++++++++++++++++++++++++\n")
    **except** Exception **as** e:
        print(e)

'''

ItChat登陆功能
‘’’

@staticmethod
def _show_message(message):
print(‘{}’.format(message))

# 生成群聊列表
**def** **generate\_chatroom**(self,chatrooms):
    # 清空原有群里列表
    **while** self.scroll_widget_layout.count():
        item = self.scroll_widget_layout.takeAt(0)
        widget = item.widget()
        widget.deleteLater()
    # 获取群里字典
    chatrooms = chatrooms
    self.chatroom_dict = dict()
    **try**:
        **for** c,i **in** zip(chatrooms, range(len(chatrooms))):
            print(c['NickName'],c['UserName'])
            checkbox = QCheckBox(c['NickName'])
            checkbox.id_ = i
            self.chatroom_dict[c['NickName']] = c['UserName']
            checkbox.stateChanged.connect(self.checkChatRoom)  # 1
            self.scroll_widget_layout.addWidget(checkbox)
        self.outputWritten("生成群聊成功!\n")
    **except** Exception **as** e:
        print(e)

# 获取群聊复选框选择状态
**def** **checkChatRoom**(self, state):
    **try**:
        checkBox = self.sender()
        **if** state == Qt.Unchecked:
            self.outputWritten(u'取消选择了{0}: {1}\n'.format(checkBox.id_, checkBox.text()))
            self.chatroom_list.remove(self.chatroom_dict[checkBox.text()])
        **elif** state == Qt.Checked:
            self.outputWritten(u'选择了{0}: {1}\n'.format(checkBox.id_, checkBox.text()))
            self.chatroom_list.append(self.chatroom_dict[checkBox.text()])
    **except** Exception **as** e:
        self.outputWritten("获取群聊选择状态失败:{}\n".format(e))

# 登录微信 - 线程
**def** **login\_wechat**(self):
    **try**:
        self.login_wechat_thread = LoginWechat(
            label=self.label_1,
            scroll_widget_layout=self.scroll_widget_layout,
            refresh_button=self.refresh_button,
            exit_button=self.exit_button,
        )
        self.login_wechat_thread.finished_signal.connect(self.generate_chatroom)
        self.login_wechat_thread.start()
    **except** Exception **as** e:
        print("执行登录线程出错:",e)
        self.outputWritten("执行登录线程出错:{}\n".format(e))

# 启动自动回复和主动发送消息 - 线程
**def** **start\_bot**(self):
    **try**:
        self.outputWritten("开始自动回复……\n")
        self.start_boot_thread = StartBot(
            appkey=self.appkey,
            secret=self.secret,
            adzone_id=self.adzone_id,
            label=self.label_1,
            start_button=self.start_run,
            end_button=self.end_run,
            chatrooms=self.chatroom_list
        )
        self.auto_send_coupon_tread = AutoSend(
            appkey=self.appkey,
            secret=self.secret,
            adzone_id=self.adzone_id,
            label=self.label_1,
            start_button=self.start_run,
            end_button=self.end_run,
            chatrooms=self.chatroom_list
        )
        self.start_boot_thread.finished_signal.connect(self._show_message)
        self.auto_send_coupon_tread.finished_signal.connect(self._show_message)
        self.start_boot_thread.start()
        self.auto_send_coupon_tread.start()
    **except** Exception **as** e:
        self.outputWritten('{}\n'.format(e))

启动自动回复

class StartBot(QThread):
finished_signal = pyqtSignal(str)
# 接受一些按钮和文本信息作为参数
def __init__(self,parent=None,appkey=None,secret=None,adzone_id=None,label=None,start_button=None,end_button=None,chatrooms=None):
super().init(parent)
self.appkey = appkey
self.secret = secret
self.adzone_id = adzone_id
self.l = label
self.start_button = start_button
self.end_button = end_button
self.chatrooms = chatrooms

# 在控制台中写入信息
**def** **outputWritten**(self, text=None):
    cursor = self.l.textCursor()
    cursor.movePosition(QtGui.QTextCursor.End)
    cursor.insertText(text)
    self.l.setTextCursor(cursor)
    self.l.ensureCursorVisible()

# 通过淘宝客API搜索优惠券
**def** **get\_tk\_coupon**(self,kw,size=5):
    req = top.api.TbkDgItemCouponGetRequest()
    req.set_app_info(top.appinfo(self.appkey.text(), self.secret.text()))

    req.adzone_id = int(self.adzone_id.text())
    req.platform = 2
    # req.cat = "16,18"
    req.page_size = size
    req.q = kw
    req.page_no = 1
    **try**:
        resp = req.getResponse()['tbk\_dg\_item\_coupon\_get\_response']['results']['tbk\_coupon']
        **return** resp
    **except** Exception **as** e:
        self.outputWritten(str(e))

# 通过类目返回优惠券
**def** **get\_cat\_coupon**(self,cate_id):
    req = top.api.TbkDgItemCouponGetRequest()
    req.set_app_info(top.appinfo(self.appkey.text(), self.secret.text()))

    req.adzone_id = int(self.adzone_id.text())
    req.platform = 2
    req.cat = cate_id
    req.page_size = 10
    req.page_no = 1
    **try**:
        resp = req.getResponse()['tbk\_dg\_item\_coupon\_get\_response']['results']['tbk\_coupon']
        **return** resp
    **except** Exception **as** e:
        self.outputWritten(str(e))

# 获取淘口令
**def** **get\_token**(self,url, text):
    req = top.api.TbkTpwdCreateRequest()
    req.set_app_info(top.appinfo(self.appkey.text(), self.secret.text()))

    req.text = text
    req.url = url
    **try**:
        resp = req.getResponse()['tbk\_tpwd\_create\_response']['data']['model']
        **return** resp
    **except** Exception **as** e:
        print(e)
        **return** **None**

**def** **run**(self):
    self.start_button.setEnabled(**False**)
    self.end_button.setEnabled(**True**)
    # 回复群聊搜索

@itchat.msg_register(TEXT, isGroupChat=True)
def text_reply(msg):
if msg[‘isAt’] and msg[‘FromUserName’] in self.chatrooms:
searchword = msg[‘Content’][9:]
self.outputWritten(‘消息来自于:{0},内容为:{1}\n’.format(msg[‘ActualNickName’], msg[‘Content’]))
response = self.get_tk_coupon(searchword)
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 = self.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 = ‘’’/:gift{name}\n/:rose【在售价】{orderprice}元\n/:heart【券后价】{conponprice}元\n/:cake 【抢购链接】{link_short}\n-----------------\n复制这条信息\n{token}打开【手机淘宝】,即可查看\n------------------\n
‘’‘.format(name=ordername, orderprice=orderprice, conponprice=couponprice, token=token,
link_short=link_short)
itchat.send(msg=str(msgs), toUserName=msg[‘FromUserName’])
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=msg[‘FromUserName’])
except Exception as e:
self.outputWritten(“发送图片失败,{}\n”.format(e))
time.sleep(3)
itchat.run()

定时自动发送消息

class AutoSend(QThread):
finished_signal = pyqtSignal(str)

**def** **\_\_init\_\_**(self,parent=None,appkey=None,secret=None,adzone_id=None,label=None,start_button=None,end_button=None,chatrooms=None):
    super().__init__(parent)
    self.appkey = appkey
    self.secret = secret
    self.adzone_id = adzone_id
    self.l = label
    self.start_button = start_button
    self.end_button = end_button
    self.chatrooms = chatrooms

# 在控制台中写入信息
**def** **outputWritten**(self, text=None):
    cursor = self.l.textCursor()
    cursor.movePosition(QtGui.QTextCursor.End)
    cursor.insertText(text)
    self.l.setTextCursor(cursor)
    self.l.ensureCursorVisible()

# 通过淘宝客API搜索优惠券
**def** **get\_tk\_coupon**(self,kw,size=5):
    req = top.api.TbkDgItemCouponGetRequest()
    req.set_app_info(top.appinfo(self.appkey.text(), self.secret.text()))

    req.adzone_id = int(self.adzone_id.text())
    req.platform = 2
    # req.cat = "16,18"
    req.page_size = size
    req.q = kw
    req.page_no = 1
    **try**:
        resp = req.getResponse()['tbk\_dg\_item\_coupon\_get\_response']['results']['tbk\_coupon']
        **return** resp
    **except** Exception **as** e:
        self.outputWritten(str(e))

# 获取淘口令
**def** **get\_token**(self,url, text):
    req = top.api.TbkTpwdCreateRequest()
    req.set_app_info(top.appinfo(self.appkey.text(), self.secret.text()))

    req.text = text
    req.url = url
    **try**:
        resp = req.getResponse()['tbk\_tpwd\_create\_response']['data']['model']
        **return** resp
    **except** Exception **as** e:
        print(e)
        **return** **None**

# 定时自动发送优惠券消息
**def** **send\_coupon**(self):
    **while** **True**:
        # 获取选择的群聊列表
        **for** c **in** self.chatrooms:
            # 每天早上8点定时推送商品优惠券
            **if** datetime.datetime.today().hour == 8:
                print('现在时间:', datetime.datetime.today())
                **try**:
                    response = self.get_tk_coupon(kw='精选',size=3)
                    **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 = self.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 = '''【清晨特惠精选】\n/:gift{name}\n/:rose【在售价】{orderprice}元\n/:heart【券后价】{conponprice}元\n/:cake 【抢购链接】{link\_short}\n-----------------\n复制这条信息\n{token}打开【手机淘宝】,即可查看

‘’‘.format(name=ordername,
orderprice=orderprice,
conponprice=couponprice,
token=token,
link_short=link_short)
itchat.send(msg=str(msgs), toUserName=c)
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)
except Exception as e:
self.outputWritten(“发送图片失败,{}\n”.format(e))
time.sleep(3)
except Exception as e:
self.outputWritten(“发送失败:{}\n”.format(e))
# 晚上六点定时发送使用说明消息
elif datetime.datetime.today().hour == 20:
itchat.send(msg=“【优惠券搜索使用说明】\n,@我+搜索名称,即可收到5条精选天猫淘宝商品内部优惠券\n”,
toUserName=c)
time.sleep(3600)

**def** **run**(self):
    **try**:
        self.send_coupon()
    **except** Exception **as** e:
        self.outputWritten("定时发送消息出错:{}\n".format(e))
        print(traceback.print_exc())

登陆微信

class LoginWechat(QThread):
# 自定义一个信号
finished_signal = pyqtSignal(object)

**def** **\_\_init\_\_**(self,parent=None,label=None,scroll_widget_layout=None,refresh_button=None,exit_button=None):
    super().__init__(parent)
    self.l = label
    self.scroll_widget_layout = scroll_widget_layout
    self.refresh_button = refresh_button
    self.exit_button = exit_button

# 在控制台中写入信息
**def** **outputWritten**(self, text=None):
    cursor = self.l.textCursor()
    cursor.movePosition(QtGui.QTextCursor.End)
    cursor.insertText(text)
    self.l.setTextCursor(cursor)
    self.l.ensureCursorVisible()

# 获取uuid
**def** **open\_qr**(self):
    **for** get_count **in** range(1):
        self.outputWritten('获取uuid中……\n')
        uuid = itchat.get_QRuuid()
        **while** uuid **is** **None**:
            uuid = itchat.get_QRuuid()
            time.sleep(1)
        self.outputWritten('成功获取uuid\n')
        **if** itchat.get_QR(uuid,picDir=r'%s'%os.path.join(current_path,'qrcode.jpg')):
            **break**
        **elif** get_count >= 1:
            self.outputWritten("获取二维码出错,请重启程序\n")
            sys.exit()

    **return** uuid

# 二维码登陆
**def** **login\_wechat**(self):
    **try**:
        uuid = self.open_qr()
        self.outputWritten("请扫描二维码\n")
        waitForConfirm = **False**
        **while** 1:
            status = itchat.check_login(uuid)
            **if** status == '200':
                **break**
            **elif** status == '201':
                **if** waitForConfirm:
                    self.outputWritten('请进行确认\n')
                    waitForConfirm = **True**
            **elif** status == '408':
                self.outputWritten('重新加载二维码\n')
                time.sleep(3)
                uuid = self.open_qr()
                waitForConfirm = **False**
        userInfo = itchat.web_init()
        itchat.show_mobile_login()
        itchat.get_friends(**True**)
        self.outputWritten('登陆成功!账号为:%s\n' % userInfo['User']['NickName'])
        itchat.start_receiving()
        self.refresh_button.setText("已登录:{}".format(userInfo['User']['NickName']))
        self.exit_button.setEnabled(**True**)
    **except** Exception **as** e:
        print("登录出错:",e)
        self.outputWritten('登陆出错:{}\n'.format(e))
    **try**:
        # 获取群聊列表
        chatrooms = itchat.get_chatrooms()
        print(type(chatrooms))
        **return** chatrooms
    **except** Exception **as** e:
        self.outputWritten("获取群聊列表出错:{}\n".format(e))

**def** **run**(self):
    **try**:
        self.refresh_button.setEnabled(**False**)
        self.exit_button.setEnabled(**True**)
        self.finished_signal.emit(self.login_wechat())
    **except** Exception **as** e:
        self.outputWritten("运行登录线程出错:{}\n".format(e))

if name == ‘__main__’:
app = QApplication(sys.argv)
gui = MainGUI()
gui.show()
sys.exit(app.exec_())


(在 UI 界面中,我们创建了一个选择文件的按钮,但是并没有使用它,大家可以思考一下如何有效地利用这个按钮呢?)


#### 5. 使用 pyinstaller 打包 PyQt5 代码为 exe 可执行程序


虽然程序写好了,但还是通过 IDE 运行代码来实现的,接下来我们通过 Pyinstaller 将程序打包为 exe 可执行文件。


首先使用 pip 命令安装 pyinstaller:



pip install pyinstaller


安装完成之后,我们就可以在命令行界面直接调用



pyinstaller


命令来对 Python 代码程序进行打包。Pyinstaller 中有很多的参数可以供我们使用,但是最常用的还是以下几个:


* -F:生成单个 exe 可执行文件;
* -w:去除控制台窗口;
* -i:指定程序的图标;


接下来,我们对我们的淘宝客微信群聊机器人的代码进行打包,在项目目录下打开命令行窗口:


![enter image description here](https://img-blog.csdnimg.cn/img_convert/8afa9692c0a2bb774dc675867a22999e.png)


然后,输入一下命令:



pyinstaller -F -w mainUI.py


![enter image description here](https://img-blog.csdnimg.cn/img_convert/1763c306c25df0134b920b1c07722a9c.png)


等 pyinstaller 执行完之后,项目目录下会多出两个目录来:


![enter image description here](https://img-blog.csdnimg.cn/img_convert/a5f48c29edf978c7ca3e657fa12afef1.png)


打开 dist 目录,里面会有一个名为 mainUI 的 exe 可执行文件:


![enter image description here](https://img-blog.csdnimg.cn/img_convert/9e0d6b28b0beecfbd168eb63083ec5e8.png)


这个文件就是我们打包之后的程序了,打开正常:


![enter image description here](https://img-blog.csdnimg.cn/img_convert/d11e6eddacff9b213cfc984b8fc7e3e6.png)


登陆功能正常:


![enter image description here](https://img-blog.csdnimg.cn/img_convert/39a29bf7591f3f33f91e3e295f2b46b7.png)


群聊自动回复搜索功能正常:


![enter image description here](https://img-blog.csdnimg.cn/img_convert/4d3cc329afa75c6fdb16154fcfc46d61.png)


手机上的效果:


![enter image description here](https://img-blog.csdnimg.cn/img_convert/d555301822d5b119864263ba47ed98cc.png)


复制一条信息打开淘宝看看(生成淘口令的方法中没有设置头像 logo):


![enter image description here](https://img-blog.csdnimg.cn/img_convert/87153266492905f917d67191665359b1.png)


![enter image description here](https://img-blog.csdnimg.cn/img_convert/23ccc0ef64dba8b2cedb6e5abb776316.png)


这样,就大功告成了。






做了那么多年开发,自学了很多门编程语言,我很明白学习资源对于学一门新语言的重要性,这些年也收藏了不少的Python干货,对我来说这些东西确实已经用不到了,但对于准备自学Python的人来说,或许它就是一个宝藏,可以给你省去很多的时间和精力。



别在网上瞎学了,我最近也做了一些资源的更新,只要你是我的粉丝,这期福利你都可拿走。

我先来介绍一下这些东西怎么用,文末抱走。

* * *



**(1)Python所有方向的学习路线(新版)**

这是我花了几天的时间去把Python所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。



最近我才对这些路线做了一下新的更新,知识体系更全面了。



![在这里插入图片描述](https://img-blog.csdnimg.cn/8fc093dcfa1f476694c574db1242c05b.png)



**(2)Python学习视频**



包含了Python入门、爬虫、数据分析和web开发的学习视频,总共100多个,虽然没有那么全面,但是对于入门来说是没问题的,学完这些之后,你可以按照我上面的学习路线去网上找其他的知识资源进行进阶。



![在这里插入图片描述](https://img-blog.csdnimg.cn/d66e3ad5592f4cdcb197de0dc0438ec5.png#pic_center)



**(3)100多个练手项目**

我们在看视频学习的时候,不能光动眼动脑不动手,比较科学的学习方法是在理解之后运用它们,这时候练手项目就很适合了,只是里面的项目比较多,水平也是参差不齐,大家可以挑自己能做的项目去练练。



![在这里插入图片描述](https://img-blog.csdnimg.cn/f5aeb4050ab547cf90b1a028d1aacb1d.png#pic_center)



**(4)200多本电子书**  

  

这些年我也收藏了很多电子书,大概200多本,有时候带实体书不方便的话,我就会去打开电子书看看,书籍可不一定比视频教程差,尤其是权威的技术书籍。



基本上主流的和经典的都有,这里我就不放图了,版权问题,个人看看是没有问题的。



**(5)Python知识点汇总**

知识点汇总有点像学习路线,但与学习路线不同的点就在于,知识点汇总更为细致,里面包含了对具体知识点的简单说明,而我们的学习路线则更为抽象和简单,只是为了方便大家只是某个领域你应该学习哪些技术栈。



![在这里插入图片描述](https://img-blog.csdnimg.cn/c741a91b05a542ba9dc8abf2f2f4b1af.png)



**(6)其他资料**



还有其他的一些东西,比如说我自己出的Python入门图文类教程,没有电脑的时候用手机也可以学习知识,学会了理论之后再去敲代码实践验证,还有Python中文版的库资料、MySQL和HTML标签大全等等,这些都是可以送给粉丝们的东西。



![在这里插入图片描述](https://img-blog.csdnimg.cn/9fa77af248b84885a6ec779b2ead064d.png)

**这些都不是什么非常值钱的东西,但对于没有资源或者资源不是很好的学习者来说确实很不错,你要是用得到的话都可以直接抱走,关注过我的人都知道,这些都是可以拿到的。**




**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化学习资料的朋友,可以戳这里无偿获取](https://bbs.csdn.net/topics/618317507)**

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值