Pull to refresh
0

Как мы делаем скриншоты страниц

Reading time 5 min
Views 25K
Привет!

Это наша первая статья на хабре, и в ней мы хотели бы рассказать вам о том, как мы делаем для своего сервиса красивые скриншоты страниц и как к этому пришли, на какие грабли наступали.

Сервис этот нам крайне важен для показа ленты обновлений. И чем быстрее и ближе к реальности (читай — поддержка флеша) он работает, тем приятнее пользователям.

   

 
После изучения интернетов были найдены следующие варианты:  
  • 1. Сайты
  • BrowserShots — видимо, заслуженный ветеран. Бесплатен, поддерживает кучу браузеров, за денежку может делать скриншоты с более высоким приоритетом, чем без неё. Радость заключается в том, что он opensource, исходники — на Python. А печаль в том, что скриншоты в большей части браузеров просто не работают, флеш не поддерживается, некоторые из вроде бы сделанных скриншотов битые. Ориентирован на верстальщиков.
  • WebShots Pro — тоже с первой страницы гугла. У них есть апи, что уже интересно, стоимость использования которого зависит от объемов, размеров картинок и наличия метки сервиса. Но — вы не поверите, пацаны — они делают скриншоты при помощи IE! В общем, с ними всё ясно. Ну, на самом деле они и помимо этого выглядят сомнительно.
  • thumbalizr beta — многообещающие ребята, доступно апи, платный сервис заключается в отключении вотермарка, но не поддерживают флеш.
  • url2png — все предыдущие сайты, кроме в какой-то степени thumbalizr, выглядят, честно говоря, раздолбайски-пофигистично. И, мне кажется, работают так же. url2png оставляет очень приятное впечатление — правда, опять же не снимает флеш и стоит дороже остальных.
  • websnapr — ну, серединка на половинку, ничего особенного.
  • 2. Программы  
  • kthml2png — заслуженный старичок. Почти не поддерживается. В общем-то, мы его и не пробовали.
  • CutyCapt — более актуальная программка. Но — «CutyCapt has a number of known quirks». Иногда ему просто не удается снять скрин. Подружить со флешом — трудно.
  • PhantomJS — насколько я знаю, самый активный из подобных проектов. Куча возможностей, не только скриншоты. Можно исполнять Javascript в контексте страницы, например. Но позиция автора насчет плагинов (флеша в том числе) такова — должно работать, но я ничего гарантировать не хочу и не буду. Ниже будут описаны интересные проблемы с этим :)

    В общем, посмотрев на это и не увидев идеала, нашей первой попыткой реализовать максимально аутентичные скриншоты стал запуск Firefox под Xvfb, и скриншот всего экрана по таймату в 30 секунд.
Xvfb — незаменимая утилита для таких целей. Это виртуальный фреймбуфер, позволяющий не ставить на сервер полноценные иксы, и запускать «дисплеи» с любым разрешением. Ну и приложения в них :)  
Способ был, конечно, неидеален. Во-первых, файрфокс оказался строптив и все время норовил подсунуть окошко обновления себя или плагинов. Во-вторых, иногда просто гробил скриншоты (получалась одноцветная картинка) или вис. В-третьих, делать скриншот строго через 30 секунд явно неоптимально — если сайт загрузился раньше, нечего ждать :) И память он, конечно, жрал.
 
Следующим шагом мы попробовали написать собственную утилиту на Qt — чтобы иметь возможность править её под себя, ведь всё-таки сервис изготовления скриншотов и правда очень важен для нас. Qt не зря пользуются авторы большинства подобных программ — там современный движок и удобный API. Проблем стало меньше, но они остались — иногда утилита висла, иногда делала битый скриншот… И почему-то не работала на боевых серверах со флешом.
 
Сам разработчик этой утилиты в какой-то момент предложил нам перейти на PhantomJS — чем мы и воспользовались. Ситуация снова стала несколько лучше, но не идеальной. Он тоже иногда виснет, причем есть как ссылки, всегда вызывающие ошибку, так и случаи спорадических отказов. Флеш тоже не работал, показывал черные прямоугольники, что в принципе уже нас более-менее устраивало.
Зато PhantomJS за счет возможности выполнять js на странице позволил нам получать из DOM описание страницы (из мета-тегов или секретным алгоритмом прямо из текста), заголовок, и потенциально вообще делать всякие интересные вещи, например — определять страницы, запрещающие показывать себя в ифрейме, что тоже довольно критичная для нас фича. HTML может быть таким месивом, что работать с ним на сервере может быть мучением; браузерные же движки десятилетиями приучены терпеть любые издевательства.
Так бы мы с ним долго и прожили, но когда к нам стали добавлять порядочное количество ссылок, Фантом обрадовал нас чем-то новеньким — работающие параллельно несколько копий программы, обрабатывающие ссылки со флешом, стали ВНЕЗАПНО его снимать, но, скажем, в один скриншот попадал ролик из другой ссылки, а во втором скриншоте на месте ролика была комбинация сразу двух роликов. Короче, кровь-кишки-расчлененка.
 
Да ну его нафиг, подумал я, и вспомнил, что Google Chrome вообще имеет встроенный флеш-плеер, да и уже понятно было, что все самописные программы страдали от недостатка надежности. Хром в этом упрекнуть сложно :) Кроме того, под него крайне просто писать расширения на чистом js, которые могли делать все то же самое, что и PhantomJS, и даже больше.
Также у него нашлись все волшебные ключики командной строки, позволяющие запускать его без интерфейса и без каких-либо назойливых предложений. Ещё он умел писать в STDERR, и работать в режиме «инкогнито», что обеспечивает максимально повторяющиеся результаты снятия скриншотов. Нам стала доступна вся мощь CSS-селекторов и у нас заработал флеш.
В общем-то, Google Chrome исполнил все наши эротические мечты ;)
Собственно скриншоты снимаются снимком всего экрана, в котором работает браузер, ну, плюс некоторые особые случаи для особых, волшебных сайтов.
 
В каком-то смысле история сделала виток спирали — мы начали с браузера, и закончили браузером. Просто работать над этой задачей с Хромом оказалось намного проще. Да, можно и под Firefox написать расширение, которое, наверно, сможет делать все то же самое, что мы делаем Хромом — но это будет труднее. После написания тулбара для Firefox я гарантирую это :)
И с памятью он работает бережнее. Кстати, в Хроме есть даже возможность снимать скриншоты без внешних утилит — их можно получать в виде data-uri, но, ирония, в таком режиме не снимается флеш :)
 
 
Итак, вот небольшой чеклист, как получить собственный сервис скриншотов, избежав долгих проб и ошибок:
 
  • Используйте очередь заданий. Я советую Resque, но это может быть и *MQ, и Kestrel, даже и реляционная БД. Главное, чтобы нормально работала с несколькими параллельными обработчиками.
  • Запустите нужное количество сессий Xvfb, на разных «дисплеях»
  • Напишите обработчик очереди, который будет запускать Google Chrome с нужными параметрами, вроде DISPLAY=:1 /opt/google-chrome/google/chrome .... Список параметров можно почерпнуть здесь: http://src.chromium.org/svn/trunk/src/chrome/common/chrome_switches.cc
  • Напишите расширение для Google Chrome, которое будет следить за завершением загрузки страницы и посылать сигнал во внешний мир. Документация: http://code.google.com/chrome/extensions/getstarted.html
  • Натравите на очередь заданий нужное количество обработчиков, каждый из которых будет использовать свой DISPLAY. Не забудьте проверить, что DISPLAY доступен. Это несложно сделать при помощи консольных утилит из семейства X11
  • Снимайте скриншот снимком экрана по сигналу из расширения, или используйте метод captureVisibleTab, но тогда флеш (и другие плагины) сниматься не будет

 
Не забудьте про шаги «…» и «Profit!» ;)

В итоге, я считаю, у нас получилось решение, превосходящее все коммерческие аналоги, что я видел.
Tags:
Hubs:
+18
Comments 34
Comments Comments 34

Articles

Information

Website
surfingbird.ru
Registered
Employees
11–30 employees
Location
Россия