Skip to content

Commit 49b0fb1

Browse files
committedJul 9, 2019
#58 增加QWebEngineView截图支持
1 parent eba99f8 commit 49b0fb1

8 files changed

+236
-1
lines changed
 

‎.settings/org.eclipse.core.resources.prefs

+1
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ encoding//QTreeWidget/ParsingJson.py=utf-8
5858
encoding//QTreeWidget/testTreeWidget.py=utf-8
5959
encoding//QWebEngineView/GetCookie.py=utf-8
6060
encoding//QWebEngineView/JsSignals.py=utf-8
61+
encoding//QWebEngineView/ScreenShotPage.py=utf-8
6162
encoding//QWebView/DreamTree.py=utf-8
6263
encoding//QWebView/GetCookie.py=utf-8
6364
encoding//QWebView/JsSignals.py=utf-8

‎QWebEngineView/Data/html2canvas.min.js

+20
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎QWebEngineView/Data/jquery.js

+4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎QWebEngineView/Data/promise-7.0.4.min.js

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎QWebEngineView/README.md

+10-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
- 目录
44
- [获取Cookie](#1获取Cookie)
55
- [和Js交互操作](#2和Js交互操作)
6+
- [网页整体截图](#3网页整体截图)
67

78
## 1、获取Cookie
89
[运行 GetCookie.py](GetCookie.py)
@@ -18,4 +19,12 @@
1819

1920
具体看代码中的注释
2021

21-
![JsSignals](ScreenShot/JsSignals.gif)
22+
![JsSignals](ScreenShot/JsSignals.gif)
23+
24+
## 3、网页整体截图
25+
[运行 ScreenShotPage.py](ScreenShotPage.py)
26+
27+
1. 方式1:目前通过不完美方法(先调整`QWebEngineView`的大小为`QWebEnginePage`的内容大小,等待一定时间后截图再还原大小)
28+
2. 方式2:通过js库`html2canvas`对指定元素截图,得到`base64`编码的数据并调用接口函数传递到py代码中
29+
30+
![ScreenShotPage](ScreenShot/ScreenShotPage.gif)
359 KB
Loading

‎QWebEngineView/ScreenShotPage.py

+198
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
3+
4+
"""
5+
Created on 2019年7月8日
6+
@author: Irony
7+
@site: https://pyqt5.com https://github.com/PyQt5
8+
@email: 892768447@qq.com
9+
@file: ScreenShotPage
10+
@description: 网页整体截图
11+
"""
12+
import base64
13+
import cgitb
14+
import os
15+
import sys
16+
17+
from PyQt5.QtCore import QUrl, Qt, pyqtSlot, QSize, QTimer
18+
from PyQt5.QtGui import QImage, QPainter, QIcon, QPixmap
19+
from PyQt5.QtWebChannel import QWebChannel
20+
from PyQt5.QtWebEngineWidgets import QWebEngineView, QWebEngineSettings
21+
from PyQt5.QtWidgets import QWidget, QApplication, QVBoxLayout, QPushButton,\
22+
QGroupBox, QLineEdit, QHBoxLayout, QListWidget, QListWidgetItem,\
23+
QProgressDialog
24+
25+
26+
__Author__ = "Irony"
27+
__Copyright__ = "Copyright (c) 2019"
28+
__Version__ = "Version 1.0"
29+
30+
# 对部分内容进行截图
31+
CODE = """
32+
var el = $("%s");
33+
html2canvas(el[0], {
34+
width: el.outerWidth(true),
35+
windowWidth: el.outerWidth(true),
36+
}).then(function(canvas) {
37+
window._self.saveImage(canvas.toDataURL());
38+
});
39+
"""
40+
41+
# 创建交互桥梁脚本
42+
CreateBridge = """
43+
new QWebChannel(qt.webChannelTransport,
44+
function(channel) {
45+
window._self = channel.objects._self;
46+
}
47+
);
48+
"""
49+
50+
51+
class Window(QWidget):
52+
53+
def __init__(self, *args, **kwargs):
54+
super(Window, self).__init__(*args, **kwargs)
55+
self.resize(600, 400)
56+
layout = QHBoxLayout(self)
57+
58+
# 左侧
59+
widgetLeft = QWidget(self)
60+
layoutLeft = QVBoxLayout(widgetLeft)
61+
# 右侧
62+
self.widgetRight = QListWidget(
63+
self, minimumWidth=200, iconSize=QSize(150, 150))
64+
self.widgetRight.setViewMode(QListWidget.IconMode)
65+
layout.addWidget(widgetLeft)
66+
layout.addWidget(self.widgetRight)
67+
68+
self.webView = QWebEngineView()
69+
layoutLeft.addWidget(self.webView)
70+
71+
# 截图方式一
72+
groupBox1 = QGroupBox('截图方式一', self)
73+
layout1 = QVBoxLayout(groupBox1)
74+
layout1.addWidget(QPushButton('截图1', self, clicked=self.onScreenShot1))
75+
layoutLeft.addWidget(groupBox1)
76+
77+
# 截图方式二(采用js)
78+
groupBox2 = QGroupBox('截图方式二', self)
79+
layout2 = QVBoxLayout(groupBox2)
80+
self.codeEdit = QLineEdit(
81+
'body', groupBox2, placeholderText='请输入需要截图的元素、ID或者class:如body、#id .class')
82+
layout2.addWidget(self.codeEdit)
83+
self.btnMethod2 = QPushButton(
84+
'', self, clicked=self.onScreenShot2, enabled=False)
85+
layout2.addWidget(self.btnMethod2)
86+
layoutLeft.addWidget(groupBox2)
87+
88+
# 提供访问接口
89+
self.channel = QWebChannel(self)
90+
# 把自身对象传递进去
91+
self.channel.registerObject('_self', self)
92+
# 设置交互接口
93+
self.webView.page().setWebChannel(self.channel)
94+
# 支持截图
95+
settings = QWebEngineSettings.globalSettings()
96+
settings.setAttribute(QWebEngineSettings.ScreenCaptureEnabled, True)
97+
self.webView.loadStarted.connect(self.onLoadStarted)
98+
self.webView.loadFinished.connect(self.onLoadFinished)
99+
self.webView.load(QUrl("https://pyqt5.com"))
100+
101+
def onLoadStarted(self):
102+
print('load started')
103+
self.btnMethod2.setEnabled(False)
104+
self.btnMethod2.setText('暂时无法使用(等待页面加载完成)')
105+
106+
@pyqtSlot(bool)
107+
def onLoadFinished(self, finished):
108+
if not finished:
109+
return
110+
print('load finished')
111+
# 注入脚本
112+
page = self.webView.page()
113+
# 执行qwebchannel,jquery,promise,html2canvas
114+
page.runJavaScript(
115+
open('Data/qwebchannel.js', 'rb').read().decode())
116+
page.runJavaScript(
117+
open('Data/jquery.js', 'rb').read().decode())
118+
# page.runJavaScript(
119+
# open('Data/promise-7.0.4.min.js', 'rb').read().decode())
120+
page.runJavaScript(
121+
open('Data/html2canvas.min.js', 'rb').read().decode())
122+
page.runJavaScript(CreateBridge)
123+
print('inject js ok')
124+
self.btnMethod2.setText('截图2')
125+
self.btnMethod2.setEnabled(True)
126+
127+
def onScreenShot1(self):
128+
# 截图方式1
129+
page = self.webView.page()
130+
oldSize = self.webView.size()
131+
self.webView.resize(page.contentsSize().toSize())
132+
133+
def doScreenShot():
134+
rect = self.webView.contentsRect()
135+
size = rect.size()
136+
image = QImage(size, QImage.Format_ARGB32_Premultiplied)
137+
image.fill(Qt.transparent)
138+
139+
painter = QPainter()
140+
painter.begin(image)
141+
painter.setRenderHint(QPainter.Antialiasing, True)
142+
painter.setRenderHint(QPainter.TextAntialiasing, True)
143+
painter.setRenderHint(QPainter.SmoothPixmapTransform, True)
144+
145+
self.webView.render(painter)
146+
painter.end()
147+
self.webView.resize(oldSize)
148+
149+
# 添加到左侧list中
150+
item = QListWidgetItem(self.widgetRight)
151+
image = QPixmap.fromImage(image)
152+
item.setIcon(QIcon(image))
153+
item.setData(Qt.UserRole + 1, image)
154+
155+
# 先等一下再截图吧
156+
QTimer.singleShot(2000, doScreenShot)
157+
158+
def onScreenShot2(self):
159+
# 截图方式2
160+
code = self.codeEdit.text().strip()
161+
if not code:
162+
return
163+
self.progressdialog = QProgressDialog(self, windowTitle='正在截图中')
164+
self.progressdialog.setRange(0, 0)
165+
self.webView.page().runJavaScript(CODE % code)
166+
self.progressdialog.exec_()
167+
168+
@pyqtSlot(str)
169+
def saveImage(self, image):
170+
self.progressdialog.close()
171+
# data:image/png;base64,iVBORw0KG....
172+
if not image.startswith('data:image'):
173+
return
174+
data = base64.b64decode(image.split(';base64,')[1])
175+
image = QPixmap()
176+
image.loadFromData(data)
177+
# 添加到左侧list中
178+
item = QListWidgetItem(self.widgetRight)
179+
item.setIcon(QIcon(image))
180+
item.setData(Qt.UserRole + 1, image)
181+
182+
183+
if __name__ == "__main__":
184+
# 开启F12 控制台功能,需要单独通过浏览器打开这个页面
185+
# 这里可以做个保护, 发布软件,启动时把这个环境变量删掉。防止他人通过环境变量开启
186+
os.environ['QTWEBENGINE_REMOTE_DEBUGGING'] = '9966'
187+
sys.excepthook = cgitb.enable(1, None, 5, '')
188+
app = QApplication(sys.argv)
189+
w = Window()
190+
w.show()
191+
192+
# 打开调试页面
193+
dw = QWebEngineView()
194+
dw.setWindowTitle('开发人员工具')
195+
dw.load(QUrl('http://127.0.0.1:9966'))
196+
dw.show()
197+
dw.move(100, 100)
198+
sys.exit(app.exec_())

‎README.md

+1
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ https://pyqt5.com 社区是专门针对PyQt5学习和提升开设的博客网站
132132
- [QWebEngineView](QWebEngineView)
133133
- [获取Cookie](QWebEngineView/GetCookie.py)
134134
- [和Js交互操作](QWebEngineView/JsSignals.py)
135+
- [网页整体截图](QWebEngineView/ScreenShotPage.py)
135136
- [浏览器下载文件](Test/partner_625781186/6.QWebEngineView下载文件)
136137
- [打印网页](Test/partner_625781186/17_打印预览qwebengineview)
137138

0 commit comments

Comments
 (0)