我决定添加一个GUI到我的一个脚本中。该脚本是一个简单的网页刮板。我决定使用工作线程作为下载和解析数据可能需要一段时间。我决定使用PySide,但我对Qt的了解总体上非常有限。PySide等待来自主线程的信号在工作线程中
由于脚本应该在等待用户输入时遇到验证码,我决定应等到QLineEdit
激发returnPressed
,然后将其内容发送到工作线程,以便它可以发送验证。这应该比忙 - 等待按下返回键更好。
似乎等待信号并不像我想的那样直截了当,搜索了一段时间后,我发现了几个类似于this的解决方案。然而,在线程和本地线程中的本地事件循环之间进行信号传递使我的解决方案变得更加复杂。
经过几个小时的修补后,它仍然无法正常工作。
什么是应该发生:
- 下载数据,直到refered来验证码,并进入一个循环
- 下载验证码,并将其显示给用户,开始
QEventLoop
通过调用调用self.loop.exec_()
- 退出
QEventLoop
loop.quit()
在工作线程插槽中通过self.line_edit.returnPressed.connect(self.worker.stop_waiting)
连接main_window
类 - 验证验证码和循环如果validati上失败,否则重试上一个网址现在应该是下载的,然后继续下一个URL
会发生什么:
...见上......
退出
QEventLoop
不起作用。self.loop.isRunning()
在致电exit()
后返回False
。self.isRunning
返回True
,因为在奇怪的情况下线程似乎不会死亡。线程暂停在self.loop.exec_()
行。因此,即使事件循环告诉我它不再运行,线程也会卡住执行事件循环。GUI的响应与工作线程类的插槽一样。我可以看到文本beeing发送给工作线程,事件循环的状态和线程本身,但是上面提到的那一行没有被执行。
的代码是有点令人费解,因为这样我增添几分伪代码蟒蛇混合的离开了不重要的:
class MainWindow(...):
# couldn't find a way to send the text with the returnPressed signal, so I
# added a helper signal, seems to work though. Doesn't work in the
# constructor, might be a PySide bug?
helper_signal = PySide.QtCore.Signal(str)
def __init__(self):
# ...setup...
self.worker = WorkerThread()
self.line_edit.returnPressed.connect(self.helper_slot)
self.helper_signal.connect(self.worker.stop_waiting)
@PySide.QtCore.Slot()
def helper_slot(self):
self.helper_signal.emit(self.line_edit.text())
class WorkerThread(PySide.QtCore.QThread):
wait_for_input = PySide.QtCore.QEventLoop()
def run(self):
# ...download stuff...
for url in list_of_stuff:
self.results.append(get(url))
@PySide.QtCore.Slot(str)
def stop_waiting(self, text):
self.solution = text
# this definitely gets executed upon pressing return
self.wait_for_input.exit()
# a wrapper for requests.get to handle captcha
def get(self, *args, **kwargs):
result = requests.get(*args, **kwargs)
while result.history: # redirect means captcha
# ...parse and extract captcha...
# ...display captcha to user via not shown signals to main thread...
# wait until stop_waiting stops this event loop and as such the user
# has entered something as a solution
self.wait_for_input.exec_()
# ...this part never get's executed, unless I remove the event
# loop...
post = { # ...whatever data necessary plus solution... }
# send the solution
result = requests.post('http://foo.foo/captcha_url'), data=post)
# no captcha was there, return result
return result
frame = MainWindow()
frame.show()
frame.worker.start()
app.exec_()
事实上,这解决了我的问题。谢谢。 – 2012-03-15 13:30:29