6

I would like to use PyQt5 to take a screenshot of a webpage. (A full webpage, including the stuff a user wouldn't see unless they scrolled down.)

Supposedly, it is possible to do this in PyQt5 using QtWebEngine. How would you do it though? I specifically don't want the user to see a browser window opening or rendering. I just want a screenshot in a PNG file.

std_answ
  • 1,039
  • 1
  • 11
  • 17
  • I have not tested it. However, my interest is in doing this with PyQt5. – std_answ Mar 19 '19 at 01:27
  • Edited question to remove PyQt4 references – std_answ Mar 19 '19 at 01:46
  • Have you seen [this?](https://stackoverflow.com/questions/10705712/screenshot-of-a-window-using-python). Not sure if it will take a screen shot of the stuff the user wouldn't see though... – Rhdr Mar 19 '19 at 06:21

2 Answers2

7

Here is an example for QtWebEngine (version 5.12):

import sys

from PyQt5.QtWidgets import QApplication
from PyQt5.QtCore import Qt, QUrl, QTimer
from PyQt5.QtWebEngineWidgets import QWebEngineView, QWebEngineSettings


class Screenshot(QWebEngineView):

    def capture(self, url, output_file):
        self.output_file = output_file
        self.load(QUrl(url))
        self.loadFinished.connect(self.on_loaded)
        # Create hidden view without scrollbars
        self.setAttribute(Qt.WA_DontShowOnScreen)
        self.page().settings().setAttribute(
            QWebEngineSettings.ShowScrollBars, False)
        self.show()

    def on_loaded(self):
        size = self.page().contentsSize().toSize()
        self.resize(size)
        # Wait for resize
        QTimer.singleShot(1000, self.take_screenshot)

    def take_screenshot(self):
        self.grab().save(self.output_file, b'PNG')
        self.app.quit()


app = QApplication(sys.argv)
s = Screenshot()
s.app = app
s.capture('https://pypi.org/project/PyQt5/', 'webpage.png')
sys.exit(app.exec_())
xuhcc
  • 2,400
  • 24
  • 23
  • 1
    Is there a better way to wait for resize other than just waiting 1000ms? That seems inefficient and possibly dangerous if the page hasn't resized in that time – reticivis Jan 19 '21 at 18:13
2

-This code was tested in : QT_VERSION_STR = 5.12.1 , PYQT_VERSION_STR = 5.12

NOTE: QtWebKit got deprecated upstream in Qt 5.5 and removed in 5.6.

Instead it is replaced with "QtWebEngineWidgets". So you have to make changes in code.

For more informations: http://doc.qt.io/qt-5/qtwebenginewidgets-qtwebkitportingguide.html

from PyQt5.QtGui import QPainter, QImage
from PyQt5 import QtWebKitWidgets
from functools import partial



class Screenshot(QtWebKitWidgets.QWebView):
    def __init__(self):
        QtWebKitWidgets.QWebView.__init__(self)

    def capture(self, url, output_file):
        self.load(QUrl(url))
        self.loadFinished.connect(partial(self.onDone, output_file))

    def onDone(self,output_file):
        # set to webpage size
        frame = self.page().mainFrame()
        self.page().setViewportSize(frame.contentsSize())
        # render image
        image = QImage(self.page().viewportSize(), QImage.Format_ARGB32)
        painter = QPainter(image)
        frame.render(painter)
        painter.end()
        image.save(output_file)


s = Screenshot()
s.capture('https://pypi.org/project/PyQt5/', 'C:/Users/user/Desktop/web_page.png')

result:

enter image description here

Community
  • 1
  • 1
ncica
  • 7,015
  • 1
  • 15
  • 37
  • This looks like what I want, but some code was lost while pasting into SO. There's no class definition, etc. When run, does this code show a browser window? I would like to keep it hidden from the user. – std_answ Mar 19 '19 at 14:24
  • no,its not showing browser window, its just saving png of gaven url – ncica Mar 19 '19 at 14:30
  • What is the definition of __init__() and the class? – std_answ Mar 19 '19 at 14:34
  • I just edit my post, now you have code with class definition – ncica Mar 19 '19 at 14:41
  • @ncica Qt Webkit is not Qt WebEngine, also Qt Webkit is deprecated from PyQt 5.6. In addition, the rendering in Qt WebEngine is different from Qt WebKit, in the case of the first Qt it does not and in the case of the second if, therefore your method works but as it indicates that class is not available in the last versions – eyllanesc Mar 19 '19 at 20:08
  • 1
    True. I think this is a useful answer to have (so please don't delete it), but it doesn't work in the version of Qt I use. – std_answ Mar 20 '19 at 00:41