在这篇文章中,我将写一个抓取新闻的程序(使用新闻网站reddit.com的api),每隔2秒发出一个关键字,获得与该关键字相关的热度最高的新闻。
我们需要达到以下几个目标:
最终界面如下(设计得很简单,因为界面不是本文的重点):
这部分不是教程的重点,只是从服务器获取并解析数据,所以不做过多讲解。
import json import time import requests agent = ‘Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.8 Safari/537.36‘ headers = { ‘User-Agent‘: agent } def get_top_post(subreddit): #从服务器获取数据 url = "https://www.reddit.com/r/{}.json?limit=1".format(subreddit) try: restext = requests.get(url, headers=headers) data = json.loads(restext.text) top_post = data[‘data‘][‘children‘][0][‘data‘] except Exception as e: print(e) return ‘错误数据‘ return "‘{title}‘ by {author} in {subreddit}".format(**top_post) def get_top_from_subreddits(subreddits): for subreddit in subreddits: yield get_top_post(subreddit) time.sleep(2) if __name__ == ‘__main__‘: for post in get_top_from_subreddits([‘python‘, ‘linux‘, ‘learnpython‘]): print(post)#输出结果
网络请求是使用python的requests库。需要注意上面的 time.sleep(2) ,因为服务器只允许每隔2秒发一次请求,并返回正确的数据。
界面部分,我们可以在代码中写各个控件和布局,也可以用Qt Designer设计好,然后生成相应的代码(可以参考该文:点我)。
def initUI(self): self.setWindowTitle(‘QThread Study‘) keywordLbl = QLabel(‘关键字(以逗号,隔开):‘) self.keywordEdit = QLineEdit() hrLayout = QHBoxLayout() hrLayout.addWidget(keywordLbl) hrLayout.addWidget(self.keywordEdit) resultLbl = QLabel(‘搜索结果:‘) self.resultList = QListWidget() vrLayout = QVBoxLayout() vrLayout.addWidget(resultLbl) vrLayout.addWidget(self.resultList) self.searchProgBar = QProgressBar() self.searchProgBar.setValue(0) self.stopBtn = QPushButton(‘停止‘) self.stopBtn.setEnabled(False) self.startBtn = QPushButton(‘开始‘) hrLayout1 = QHBoxLayout() hrLayout1.addWidget(self.stopBtn) hrLayout1.addWidget(self.startBtn) vrLayout1 = QVBoxLayout(self) vrLayout1.addLayout(hrLayout) vrLayout1.addLayout(vrLayout) vrLayout1.addWidget(self.searchProgBar) vrLayout1.addLayout(hrLayout1)
如果没有使用多线程,你可能会这么做:写好新闻获取部分的代码,再写好界面部分的代码,只是简单地调用函数处理数据。这么做可以,但所有工作都在单独的GUI线程中完成,所以执行函数获取新闻时,你的程序将会被“冻结”住。
就像这样:
下面是主要代码(点击开始按钮,进入槽函数,获取新闻数据):
class ThreadTestUI(QWidget): def __init__(self, parent = None): super().__init__(parent) self.initUI() #建立信号槽连接 self.startBtn.clicked.connect(self.startBtnClicked) def startBtnClicked(self): subreddit_list = str(self.keywordEdit.text()).split(‘,‘) if subreddit_list == [‘‘]: print(‘没有搜索内容‘) return self.resultList.clear() for post in self.get_top_from_subreddits(subreddit_list): self.resultList.addItem(post)
三、使用多线程
我们已经看到没有使用多线程将会发生什么事,下面将使用QThread类重写我们的代码。
我们要做的就是写一个线程,这个线程与之前的 get_top_post 和 get_top_from_subreddits 做相同的工作,当获得新数据时就更新界面,而且允许用户点击“停止”按钮停止获取数据。
1.QThread的基本结构
在这里我们要使用的QThread类很简单,它的整体结构如下:
from PyQt4.QtCore import QThread class YourThreadName(QThread): def __init__(self): QThread.__init__(self) def __del__(self): self.wait() def run(self): # your logic here
你可以通过它的构造方法__init__给线程传参数。不能直接调用run方法,而是通过start间接调用run,否则你的界面仍有可能被“冻结”住。
所以你可以像这样使用上面的自定义线程:
self.myThread = YourThreadName() self.myThread.start()
如此,在run方法中写的代码将被执行,你可以使用像isRunning这样的方法检测线程是否正在运行。
大多数时候你只需使用下面的方法: quit 、 start 、 terminate 、 isFinished 、 isRunning 。QThread的这些信号也很有用: finished 、 started 、 terminated
原文:http://www.cnblogs.com/hellovenus/p/6382991.html