Быстрый в изучении - мощный в программировании
>> Telegram ЧАТ для Python Программистов

Свободное общение и помощь советом и решением проблем с кодом! Заходите в наш TELEGRAM ЧАТ!

>> Python Форум Помощи!

Мы создали форум где отвечаем на все вопросы связанные с языком программирования Python. Ждем вас там!

>> Python Канал в Telegram

Обучающие статьи, видео и новости из мира Python. Подпишитесь на наш TELEGRAM КАНАЛ!

Cоздаем скриншот любого сайта на Python с помощью QtWebKit

13 ноября 2015 г. Archy Просмотров: 17152 RSS 3
Cоздаем скриншот любого сайта на Python с помощью QtWebKit

Здравствуй дорогой читатель! Как гласит пословица, одна картинка стоит тысячи слов. В нашем случае, стоимость одной картинке дойдет до несколько десятков строк кода. Встает вопрос, для чего вообще нужно делать скриншоты сайтов?

Тут ответы варьируют от человека к человеку, мне вот нужен был скрипт который раз в неделю сделает скриншот главной странице сайта. Вслед чего, последние две картинки сравнивались побайтно. В случае эквивалентности, скрипт прекратил работу в течение недели после чего снова картинки N и N-1 приступили к сравниванию. В случае когда байты картинок различались, скрипт автоматически запустил другой скрипт, в моем случае был (парсер or граббер or скраппер), тут на ваше усмотрение.

И так, для установки QtWebKit придется немного попотеть. Бывалые программисты/сисадмины сделают это одной левой. Тут pip3 и easy_install не катит, нужно установить бинарные пакеты.

Зайдите на сайт https://www.riverbankcomputing.com/software/sip/download для установки SIP и https://riverbankcomputing.com/software/pyqt/download для установки QtWebKit. Для пользователей Windows данный процесс пройдет легко так как нужно всего скачать и запускать нужные .exe файлы.

Если вы пользователь Linux, то, скачав архивы под нужную вам версию, разархивируйте архивы в любую папку затем с помощью команды cd через терминал зайдите в нее и выполните команду python configure.py. Важно! Сначала установите SIP и только потом PyQt. В противном случае выдаст ошибку наподобие "Error: This version of PyQt requires SIP v4.16.4 or later".

В сегодняшнем примере мы будем использовать Python 2.7. Если вы дошли до этого момента, значит у вас все получилось и вы готовы увидеть работающий скрипт.

import sys
import time
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from PyQt4.QtWebKit import *
class MakeScreenshot(QWebView):
    def __init__(self):
        self.app = QApplication(sys.argv)
        QWebView.__init__(self)
        self._loaded = False
        self.loadFinished.connect(self._loadFinished)
    
    def wait_load(self, delay = 0):
        while not self._loaded:
            self.app.processEvents()
            time.sleep(delay)
        self.loaded = False
        
    def _loadFinished(self, result):
        self._loaded = True
        
    def get_image(self, url):
        self.load(QUrl(url))
        self.wait_load()
        
        frame = self.page().mainFrame()
        self.page().setViewportSize(frame.contentsSize())
        
        image = QImage(self.page().viewportSize(),
                        QImage.Format_ARGB32)
        painter = QPainter(image)
        frame.render(painter)
        painter.end()
        return image

Красивый получился код, согласитесь. Чистый ООП, вот к чему вам нужно стремиться.

Копируйте скрипт и сохраните его под любым именем с окончанием .py. Теперь дело осталось за малым, нужно создать экземпляр класса то есть инициализировать объект. Делается это легко, дополните код следующими строками:

s = MakeScreenshot()
image = s.get_image('http://www.python-3.ru')
image.save('website-screen.png')

Вам осталось только запустить программу из терминал с помощью "python myCode.py" или выполнив его в ваш IDE нажатием на стрелочку, зеленую такую.

Как все здесь работает?

Наш скрипт использует QWebView для загрузки URL сайта и после этого создает скриншот с помощью QPainter.

Метод get_image() принимает только один параметр - нашу цель, то есть ссылку на желаемый сайт. Зная параметр, можно легко импортировать его в другие методы и расширить функционал класса.

Для начало мы импортировали все модули:

import sys
import time
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from PyQt4.QtWebKit import *

Затем мы создали название класса и указали классу что нужно наследовать все от QWebView.

class Screenshot(QWebView):

Заметьте пожалуйста что наш конструктор инициализирует новое свойство self._loaded которая вместе с _loadFinished и wait_load проверяет состояние программы во время ее работы. Данные свойства и функции нужны для того чтобы не сделать скриншот сайта преждевременно, они проверяют если наша цель(сайт) загрузилась полностью.

Самая важная функция в нашем коде является get_image() так как именно она делает скриншот сайта. Именно get_image() задает размеры окна сайта. В функции мы также задавали формат картинки ARGB32 и присваивали картинку объекту QPainter вслед чего закрыли объект с помощью метода end(). В самом конце мы возвращаем скриншот.

Комментариев: 3
  1. Владимир | 2016-04-13 в 10:01:56

    Делает скриншоты любого сайта - это перебор. Попробуй-ка этот https://geekbrains.ru/posts/top_april_jokes (в разделе посты, любой пост). Да и много кода, как для скриншота.

    Вот этот код любой сайт сделает и кода меньше:

    from selenium import webdriver

    driver = webdriver.Firefox()

    driver.get("https://geekbrains.ru/posts/top_april_jokes")

    driver.get_screenshot_as_file('img.png')

    driver.quit()

  2. Здравствуй Владимир.

    Ваш вариант да, более быстрый, простой и намного меньше кода. Сам его использую в веб-девелопе.

    Я написал статью дабы ознакомить пользователей с прекрасным PyQT. Разминка никогда не бывает лишней.

  3. Владимир | 2016-04-18 в 14:43:45

    Здравствуй Archy.

    На Ваш сайт зашел уже после того, как нашел выше изложенное решение(через selenium). Т.к. оно меня не устраивает, хочется обойтись без браузера. Также меня не устраивает и png, намного лучше, если бы это был pdf. Картинку перевести в pdf не трудно, но интересует полноценный (так говоря) pdf, чтобы можно было скопировать содержимое в буфер. Сейчас пользуюсь решением под линукс:

    $ wkhtmltopdf ya.ru out.pdf

    Но оно тоже не идеально, т.е. не работает с тем сайтом, который указывал ранее.

    Насчет Вашего кода могу добавить, что не плохо бы указывать разрешение, если есть такая возможность, иначе на адаптивных сайтах скриншоты получаются 624px.