python - 加载网页

标签 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())

但可惜事实并非如此。该方法打印的所有内容相当于空响应:

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

所以我仔细查看了 setUrl documentation :

The view remains the same until enough data has arrived to display the new url.

这让我觉得可能是在从服务器收到响应之前我太早调用了 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()

最佳答案

复制自 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(),它可能会起作用。

关于python - 加载网页,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27605555/

相关文章:

python - 如何检查Python中的函数装饰器

python - QtWebPageRenderer SIGILL 问题

python - Django 管理 - 外键 "field object"列表

python - 如何在 python 中一次将多个文件从本地服务器移动到 HDFS?

linux - setObjectName 未在 Qt 中设置线程名称

c++ - 如何在多线程中使用模板类型作为槽和信号参数?

python - QCoreApplication.processEvents 行为

python - QtiPlot 和 Python : global name 'QLocale' is not defined

python - 如何让我的 Spyder 代码在 GPU 而不是 Ubuntu 上的 cpu 上运行?

c++ - 构造函数无法重新声明。为什么?