PySide浏览器在一个单独的过程中

时间:2014-08-30 23:56:52

标签: python qt inheritance processing pyside

我尝试编写一个简单的解析器,检查一些网页,如果这些页面上的内容发生了变化,那么脚本会将url发送到无头webkit浏览器,该浏览器使用PySide绑定到Qt并进行截屏。我希望这个浏览器始终在后台单独的进程中运行,等待url出现在队列中。一旦url到来,它就会截图,保存它然后返回等待。

我尝试使用此代码实现此行为(我剪切了解析器部分):

import multiprocessing
import sys
from datetime import datetime
from PySide import QtGui, QtWebKit, QtCore

class Browser(QtWebKit.QWebPage):
    def __init__(self, queue_in, queue_out):
        self.app = QtGui.QApplication(sys.argv)
        QtWebKit.QWebPage.__init__(self)
        self.queue_out = queue_out
        self.queue_in = queue_in
        self.setViewportSize(QtCore.QSize(900, 900))
        self.mainFrame().setScrollBarPolicy(QtCore.Qt.Horizontal, QtCore.Qt.ScrollBarAlwaysOff)
        self.mainFrame().setScrollBarPolicy(QtCore.Qt.Vertical, QtCore.Qt.ScrollBarAlwaysOff)
        self.mainFrame().loadFinished.connect(self._makeScreenshot)
        self.makeScreenshotOf()

    def makeScreenshotOf(self):
        self.mainFrame().setUrl(QtCore.QUrl.fromEncoded(self.queue_in.get()))

    def _makeScreenshot(self):
        image = QtGui.QImage(self.viewportSize(), QtGui.QImage.Format_ARGB32)
        painter = QtGui.QPainter(image)
        self.mainFrame().render(painter)
        painter.end()
        file_name = datetime.now().strftime("%Y-%m-%d %H-%M-%S-%f") + ".png"
        image.save(file_name)
        self.queue_out.put(file_name)
        self.makeScreenshotOf()

if __name__ == "__main__":
    multiprocessing.set_start_method('spawn')
    queue_in = multiprocessing.Queue()
    queue_out = multiprocessing.Queue()
    t = threading.Thread(target = Browser, args = (queue_in, queue_out))
    t.start()
    queue_in.put(url)

问题是第一次运行时进程成功保持等待,等待url出现在队列中,但一旦获得url,进程就会停止,忽略Qt连接

self.mainFrame().loadFinished.connect(self._makeScreenshot)

问题是如果我直接从Process

继承
class Browser(multiprocessing.Process):
    def __init__(self, queue_in, queue_out):
        multiprocessing.Process.__init__(self)
        self.queue_out = queue_out
        self.queue_in = queue_in
        self.app = QtGui.QApplication(sys.argv)
        self.browser = QtWebKit.QWebPage()
        ...
if __name__ == "__main__":
    queue_in = multiprocessing.Queue()
    queue_out = multiprocessing.Queue()
    b = Browser(queue_in, queue_out)

然后连接不会被忽略,并且一切正常,但是在浏览器进程中调用的副作用self.queue_in.get()也会阻止主进程(如果队列为空)。

问题:

  1. 为什么Qt连接在第一种情况下不起作用而在另一种情况下工作?
  2. 为什么在第二种情况下queue.get()会阻止主进程?如何防止这种情况?

2 个答案:

答案 0 :(得分:2)

如果队列为空,

Queue.get()会阻塞。使用get_nowait(),如果那里没有任何内容,则会引发异常。

答案 1 :(得分:1)

似乎调用app.exec_()是必不可少的。现在一切都有效。除了我得到

warning qapplication was not created in the main()

尽管一切都有效,但我还是决定把它移到主要的

app = QtGui.QApplication(sys.argv)
browser = Browser(queue_in, queue_out)
app.exec_()

并在单独的进程中运行解析器部分。

UPD

了解如何在流程中运行QApplication

class QtApp(QtGui.QApplication):
"""
docstring
"""
def __init__(self, args, url_queue, filename_queue):
    QtGui.QApplication.__init__(self, args)
    browser = Browser(url_queue, filename_queue)
    self.exec_()

browser_process = multiprocessing.Process(target=QtApp, 
                                          args=(sys.argv, url_queue, filename_queue))