在这篇文章中,我将写一个抓取新闻的程序(使用新闻网站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