加载网页

时间:2014-12-22 15:27:01

标签: python qt pyqt pyside qwebview

我正在尝试使用PySide的QtWebKit模块加载网页。根据文档(Elements of QWebView; QWebFrame::toHtml()),以下脚本应打印Google搜索页面的HTML:

from PySide import QtCore
from PySide import QtGui
from PySide import QtWebKit

# Needed if we want to display the webpage in a widget.
app = QtGui.QApplication([])

view = QtWebKit.QWebView(None)
view.setUrl(QtCore.QUrl("http://www.google.com/"))
frame = view.page().mainFrame()
print(frame.toHtml())

但唉,事实并非如此。所有打印的方法都是等效的null响应:

<html><head></head><body></body></html>

所以我仔细研究了setUrl documentation

  

视图保持不变,直到有足够的数据到达显示新网址。

这让我想到,在从服务器收到响应之前,我可能过早地调用了toHtml()方法。所以我编写了一个覆盖setUrl方法的类,阻塞直到loadFinished信号被触发:

import time

class View(QtWebKit.QWebView):
    def __init__(self, *args, **kwargs):
        super(View, self).__init__(*args, **kwargs)
        self.completed = True
        self.loadFinished.connect(self.setCompleted)

    def setCompleted(self):
        self.completed = True

    def setUrl(self, url):
        self.completed = False
        super(View, self).setUrl(url)
        while not self.completed:
            time.sleep(0.2)

view = View(None)
view.setUrl(QtCore.QUrl("http://www.google.com/"))
frame = view.page().mainFrame()
print(frame.toHtml())

完全没有任何区别。我在这里缺少什么?

编辑:仅仅获取页面的HTML不是我的最终游戏。这是一个代码的简化示例,它没有像我预期的那样工作。感谢Oleh建议用app.processEvents()

替换time.sleep()

1 个答案:

答案 0 :(得分:3)

my other answer复制:

from PySide.QtCore import QObject, QUrl, Slot
from PySide.QtGui import QApplication
from PySide.QtWebKit import QWebPage, QWebSettings

qapp = QApplication([])

def load_source(url):
    page = QWebPage()
    page.settings().setAttribute(QWebSettings.AutoLoadImages, False)
    page.mainFrame().setUrl(QUrl(url))

    class State(QObject):
        src = None
        finished = False

        @Slot()
        def loaded(self, success=True):
            self.finished = True
            if self.src is None:
                self.src = page.mainFrame().toHtml()
    state = State()

    # Optional; reacts to DOM ready, which happens before a full load
    def js():
        page.mainFrame().addToJavaScriptWindowObject('qstate$', state)
        page.mainFrame().evaluateJavaScript('''
            document.addEventListener('DOMContentLoaded', qstate$.loaded);
        ''')
    page.mainFrame().javaScriptWindowObjectCleared.connect(js)

    page.mainFrame().loadFinished.connect(state.loaded)

    while not state.finished:
        qapp.processEvents()

    return state.src

load_source从URL下载数据,并在WebKit修改后返回HTML。它用它的异步事件包装Qt的事件循环,并且是一个阻塞函数。

但你真的应该想想你在做什么。你真的需要调用引擎并获得修改后的HTML吗?如果您只想下载某些网页的HTML,可以采用更简单的方法。

现在,答案中代码的问题是你不要让Qt做任何事情。没有魔法发生,没有代码在后台运行。 Qt基于一个事件循环,你永远不会让它进入那个循环。这通常是通过调用QApplication.exec_或解决方法processEvents来实现的,如我的代码所示。您可以将time.sleep(0.2)替换为app.processEvents(),它可能会起作用。