Pull to refresh

Сам себе сервис скриншотов

Reading time 3 min
Views 24K

Все началось с ...


Несколько лет назад я только начал знакомиться с web-программированием, и одним из моих первых «проектов» был каталожек сайтов. Разработка велась для себя, в целях повышения опыта. Но т.к. аналогичных сайтов тьма-тьмущая, хотелось сделать что-то особенное. Я решил, что каждый сайт в каталоге будет представлен со скриншотом. Как все это автоматизировать я не знал, потому первое время я делал все скриншоты руками и заливал их уже как готовые файлы.

Шло время, проект «покрылся пылью», времени заниматься ним не было, но примерно год назад накатила новая «волна креатива» и захотелось мне решить «задачку автоскриншотера».

Первое, что пришло на ум — это готовые сервисы по созданию скриншотов, предоставяющие API. Но, перебрав некоторые (сейчас уже названия не помню), понял, что это не для меня: возможности были довольно урезаны, иногда приходилось довольно долго ждать «очереди», иногда сайты на скринах выглядели довольно убого. А главной проблемой было то, что все это должно было работать асинхронно и из скрипта я бы не смог понять — то ли сервис отдал мне временную картинку-заглушку, то ли уже готовый скриншот сайта.

Итого, я решил сделать собственный «велосипед».

Выбор инструмента


Для начала, нужно было найти утилитку, умеющую делать скриншоты, работающую в linux из командной строки (сайт крутится у меня на ubuntu server, потому иксов нет). Мне помог коллега по работе, дав ссылку на CutyCapt.

CutyCapt — небольшая кросс-платформенная утилита (работающая из командной строки) для создания скриншота веб-страницы и сохранения в различные векторные и растровые форматы, включая SVG, PDF, PS, PNG, JPEG, TIFF, GIF, BM P(перевод оригинального описания с оф. сайта).

Чтобы не заниматься копипастом с официального сайта просто скажу, что там уже все описано: установка, зависимости, параметры запуска, пример, а также способ использования при отсутствии X-сервера (через xvfb-run).

Кодинг


Итак, с инструментом определились. Вернемся к сайту. Я видел это так: у администратора на страничке описания есть кнопка «сделать скриншот», которая через AJAX запрос вызывает скрипт, создающий картинку, выполняющий с ней нужные обработки (ресайз/кроп/эскиз) и др.
Сказано — сделано. Приведу часть кода моего PHP-скрипта (оставив самое основное):


<?PHP

// тут какие-то действия по получению URL сайта, скрин которого нужно создать
// будь то выборка из БД (по переданному id), или еще что-то

$url = 'http://habrahabr.ru'; // "хардкод" для примера

// имя временного файла для сохранения скриншота
$tmpfname = tempnam('/tmp', 'catalog') . '.jpg';

// эскейпим перед вставкой в строку команды
$url = escapeshellarg($url);

// собираем командную строку
// из параметров для CutyCapt я передавал только мин. ширину экрана, url и имя файла, куда сохранять скриншот - мне этого хватило
// о "xvfb-run" я писал выше
$cmd = sprintf('xvfb-run --server-args="-screen 0, 1024x768x24" /ПАПКА/C/БИНАРНИКОМ/CutyCapt --min-width=1280 --url=%s --out=\'%s\'', $url, $tmpfname);

// Выполняем
exec($cmd);
// Проверяем, что скрин создался
if (file_exists($tmpfname)) {
    // проверяем, что он не 0 байт (у меня иногда так случалось)
    if (filesize($tmpfname) > 1) {
        // а тут уже делаем с файлом по имени $tmpfname все, что душе угодно
        // делаем его копию в нужную папку, изменяем размер, обрезаем в нужных пропорциях, создаем дополнительный эскиз.....

        // я, например, использовал phpthumb (phpthumb.gxdlabs.com) для обработки
        
        $f = date("ymd_his", time()).".jpg"; // имя для скрина
        if (copy($tmpfname, IMAGES_DIR.$f)) {
            if (file_exists(IMAGES_DIR.$f)) {
               try{
                                    $thumb = PhpThumbFactory::create(IMAGES_DIR.$f);
                                    // качество jpg
				    $thumb->setOptions( array('jpegQuality' => 90) );
                                    // изменение размер
                                    $thumb->resize(800);
                                    // обрезка до квадрата 800x800px
                                    $thumb->crop(0, 0, 800, 800);
                                    $thumb->save(IMAGES_DIR.$f);
                                    // эскизик
                                    $thumb->resize(200)->crop(0,0,200,150);
                                    $thumb->save(IMAGES_DIR.'t_'.$f);
                }
                catch(exception $e) {
			// обрабатываем исключение...						
                }

                // здесь я сохранял имя скрина в БД, и др.
            }
        }
    }

    // удаляем временный файл
    unlink($tmpfname);
}

// тут я отправлял результат работы в json - инфу об удачном/неудачном создании скрина

?>

Ах да, хотел бы поделиться информацией о «подводных камнях»:
  1. Иногда CutyCapt очень долго скринил, но так и не доделывал свою работу;
  2. Иногда делал 0-байтные скрины
  3. Иногда вылетал с ошибкой на некоторых flash-сайтах. Пришлось пожертвовать ими и просто удалить flash-plugin из системы. Теперь просто на скринах на месте флеша — пусто, зато вылетов больше нет из-за флеша.


Литература:
Официальный сайт CutyCapt
PHP.net

P.S. Если кому кажется, что я мало написал про CutyCapt, говорите — я дополню статью (просто мне показалось, что на оф. сайте все четко описано)
Tags:
Hubs:
+59
Comments 24
Comments Comments 24

Articles