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

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

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

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

>> Python Канал в Telegram

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

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

13 ноября 2015 г. Archy Просмотров: 16880 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.

Оставьте комментарий!

Используйте нормальные имена.

Имя и сайт используются только при регистрации

Если вы уже зарегистрированы как комментатор или хотите зарегистрироваться, укажите пароль и свой действующий email. При регистрации на указанный адрес придет письмо с кодом активации и ссылкой на ваш персональный аккаунт, где вы сможете изменить свои данные, включая адрес сайта, ник, описание, контакты и т.д., а также подписку на новые комментарии.

(обязательно)