Python 中无标题 QtWebKit 浏览器中多个网页的屏幕截图
Posted
技术标签:
【中文标题】Python 中无标题 QtWebKit 浏览器中多个网页的屏幕截图【英文标题】:Screenshot of multiple webpages in a headerless QtWebKit browser in Python 【发布时间】:2012-08-10 14:06:05 【问题描述】:我正在尝试渲染多个网页并截取它们的屏幕截图,但我只能在渲染一个网页时让它工作,因为当我在多个网页上尝试它时,程序要么停在它的轨道上并永远挂起,要么只是不对图像、css 做任何事情,而是会提取站点的文本并将其放入一个长文本块中。通常发生的事情是它会挂起。
我用来在内存中呈现网页的代码是这样的:
class Render(QWebPage):
def __init__(self, url):
self.app = QApplication(sys.argv)
QWebPage.__init__(self)
# Settings
s = self.settings()
#s.setAttribute(QWebSettings.AutoLoadImages, False)
s.setAttribute(QWebSettings.javascriptCanOpenWindows, False)
s.setAttribute(QWebSettings.PluginsEnabled, True)
self.loadFinished.connect(self._loadFinished)
self.mainFrame().load(QUrl(url))
#self.mainFrame().setScrollBarPolicy(Qt.Vertical, Qt.ScrollBarAlwaysOff)
self.mainFrame().setScrollBarPolicy(Qt.Horizontal, Qt.ScrollBarAlwaysOff)
self.app.exec_()
def _loadFinished(self, result):
self.frame = self.mainFrame()
size = self.frame.contentsSize()
size.setWidth(1366)
self.setViewportSize(size)
self.app.quit()
这是我保存图像的方式:
def run(url):
os.chdir("output")
r = Render(url)
image = QImage(r.viewportSize(), QImage.Format_ARGB32)
painter = QPainter(image)
r.frame.render(painter)
painter.end()
fp = "%s.png" % os_safe_name(url)
image.save(fp)
os.chdir("..")
有人知道为什么会这样吗?
【问题讨论】:
【参考方案1】:与 Luke 的回答中描述的差不多,我改变了一些东西以避免为每个 Render
创建一个 QApplication
实例
不是最整洁的,但对我有用:
import re
import sys
import time
# Tested with PySide 1.0.9, changing imports to PyQt should work identically
from PySide.QtCore import Qt, QUrl
from PySide.QtGui import QApplication, QImage, QPainter
from PySide.QtWebKit import QWebPage, QWebSettings
def os_safe_name(url):
url = re.sub("[^a-zA-Z0-9_-]+", "_", url)
url = re.sub("_2,", "_", url)
return url
class Render(QWebPage):
def __init__(self, url):
QWebPage.__init__(self)
self.url = url
self.finished = False
# Settings
s = self.settings()
#s.setAttribute(QWebSettings.AutoLoadImages, False)
s.setAttribute(QWebSettings.JavascriptCanOpenWindows, False)
s.setAttribute(QWebSettings.PluginsEnabled, True)
#self.mainFrame().setScrollBarPolicy(Qt.Vertical, Qt.ScrollBarAlwaysOff)
self.mainFrame().setScrollBarPolicy(Qt.Horizontal, Qt.ScrollBarAlwaysOff)
# When page is loaded, callback saves image to file
self.loadFinished.connect(self._loadFinished)
self.mainFrame().load(QUrl(url))
def _loadFinished(self, result):
frame = self.mainFrame()
size = frame.contentsSize()
size.setWidth(1366)
self.setViewportSize(size)
image = QImage(self.viewportSize(), QImage.Format_ARGB32)
painter = QPainter(image)
frame.render(painter)
painter.end()
self.filepath = "output/%s.png" % os_safe_name(self.url)
image.save(self.filepath)
self.finished = True
def run(url, app = None):
if app is None:
app = QApplication(sys.argv)
r = Render(url)
while not r.finished:
app.processEvents()
time.sleep(0.01)
return r.filepath
if __name__ == '__main__':
app = QApplication(sys.argv)
print run("http://***.com", app=app)
print run("http://google.com", app=app)
【讨论】:
感谢你们俩。这个答案更完整,所以我接受它。 这听起来不适合拍摄快照,因为它不会禁用声音。例如,如果您加载此页面:youtube.com/watch?v=kK42LZqO0wA 并想稍等片刻(例如让 cmets 加载),您将能够听到 html5 视频播放。如何避免这种情况? @user9379 我不认为有一个简单的方法可以做到这一点。插件所做的事情超出了 Qt 的控制 - 插件将直接与操作系统的音频子系统通信 @user9379 将有特定于平台的方法来重定向来自特定进程的音频,例如 OS X 上的 AudioHijack、Linux 和 Windows 上的 Jack 在某处具有用于应用程序音量控制的特定 API跨度> @dbr 我实际上正在尝试为网站快照制作一个高级 Qt 库,这是我唯一的问题...感谢您的回答!【参考方案2】:我假设您正在创建 Render 类的多个实例。如果是这种情况,那么您很可能会遇到问题,因为您创建了多个 QApplication 实例。相反,创建一个 QApplication 并在所有 Render 实例之间共享它。
您可能还需要停止使用 app.quit(),因为您希望 QApplication 继续运行。此外,由于 app.exec_() 在您调用 quit() 之前不会退出,因此您需要创建自己的事件循环。像这样的:
while not self.finished:
self.app.processEvents()
time.sleep(0.01)
【讨论】:
以上是关于Python 中无标题 QtWebKit 浏览器中多个网页的屏幕截图的主要内容,如果未能解决你的问题,请参考以下文章
基于 QtWebKit 的浏览器的虚拟键盘或如何获取当前聚焦的文本字段?
在 QtWebkit 中,如何调用网页的 QNetworkAccessManager::createRequest()?
CentOS 7 Python ImportError:无法导入名称QtWebkit,即使它在我的PyQt4站点包目录中