Загрузка пробок от Яндекса в мобильный одной небольшой картинкой
В связи с временным переездом в Москву, а именно за МКАД пришлось пользоваться сервисом Яндекс.пробки. Если в Москве скорость загрузки «родного» приложения от Яндекса вполне меня удовлетворяла, то на новом месте это уже не лезло ни в какие ворота. С тем уровнем сигнала одна надпись о проверке версии в течении пары минут начинала раздражать очень сильно. Поэтому, я принял решение написать свое приложение J2ME, позволяющее загрузить небольшое изображение (до 30-60 кб) с пробками в заданном регионе на свой мобильный телефон. Как? Об этом ниже.
Сначала задача была решена посредством сервиса iprobki.ru. J2ME-приложение запрашивало страницу с адресом типа http://iprobki.ru/images/YYYYMMDD На странице искалась последняя временная отсечка (TS), после чего делался запрос вида http://iprobki.ru/images/YYYYMMDD/TS/3.gif Номер картинки — требуемый участок карты.
Но у данного решения оказалось два недостатка:
- невысокая гибкость — карта разбита автором, а не мной
- излишние затраты трафика. Первый запрос к вечеру превышает 30 килобайт, так как содержит все отсечки за день
Дело было даже не в размере трафика (мой оператор все равно округляет до 100 кб), а в скорости загрузки. Хотелось не делать лишний запрос и получать картинку почти мгновенно.
Посему было принято решение написать свой небольшой сервис непосредственно над яндекс.пробками. Причем без определения последних отсечек времени и вообще без javascript. Первое, что приходит на ум — получить снимок страницы.
В качестве источника для скриншота можно использовать как минимум два варианта адреса страницы от яндекса. Первая — это оригинальная ссылка на карты яндекса, например, карта. В качестве альтернативы можно взять участок карты для печати: карта для печати.
Главное, что нужно понимать — от полученной картинки придется обрезать лишнее. Первый вариант, возможно лучше подходит, так как там картинка занимает не центральную область, а смещена в нижний правый угол.
Теперь нужно получить, собственно, скриншот. Один из вариантов — запускать браузер с нужным адресом, ждать некоторое время, пока загрузится страница, потом делать снимок экрана, обрезать, уменьшать и передавать его на мобильник. Недостатки очевидны: активация окна на сервере (если сервер), непонятное время ожидания (3, 5, 10 секунд, чтобы наверняка). Или как-то опрашивать браузер на предмет завершения операции?
Более оптимальным решением в данном случае может стать встроенный браузер, позволяющий загрузить страницу с нужным адресом, с возможностью сохранения контента как изображения (хотя есть онлайновые сервисы, но не хотелось завязываться на их работу). К счастью, велосипед не пришлось изобретать, поиски привели к небольшой утилите, основанной на WebKit: CutyCapt. У автора, кстати, там же оказалась ссылка на аналогичное приложение, основанное на IE.
Ну а дальше — дело техники. Подойдет абсолютно любой сервер. На мой взгляд, здесь отлично сработает CGI, сам скрипт может быть на Python’е, а для работы с изображением можно использовать PIL или ImageMagic.
Здесь же приведу законченный и работающий веб-сервер, основанный на BaseHTTPServer из стандартной библиотеки питона:
import BaseHTTPServer from subprocess import Popen from PIL import Image HOST_NAME = '127.0.0.1' PORT_NUMBER = 8080 MAP_URL = 'http://maps.yandex.ru/?ll=37.424895%2C55.596491&spn=0.16737%2C0.078927&z=13&l=map%2Ctrf' TMP_FILE = 'tmp.png' OUT_FILE = 'out.jpg' class MapHandler(BaseHTTPServer.BaseHTTPRequestHandler): def do_GET(s): try: process = Popen('CutyCapt --min-width=1280 --min-height=1024 --url="%s" --out=%s' % (MAP_URL, TMP_FILE), shell=False) process.wait() im = Image.open(TMP_FILE) im.crop((300, 100, 1280, 1024)).resize((480, 450), Image.ANTIALIAS).save(OUT_FILE) s.send_response(200) s.send_header("Content-type", "image/jpeg") s.send_header("Content-Disposition", "inline; filename=probki.jpeg") s.end_headers() with open(OUT_FILE, 'rb') as f: s.wfile.write(f.read()) except Exception, e: s.send_response(500) s.send_header("Content-type", "text/plain") s.end_headers() s.wfile.write('Internal server error: %s' % e) if __name__ == '__main__': server_class = BaseHTTPServer.HTTPServer httpd = server_class((HOST_NAME, PORT_NUMBER), MapHandler) try: httpd.serve_forever() except KeyboardInterrupt: pass httpd.server_close()
Да, чуть не забыл. Само J2ME приложение здесь не привожу. Оно очень простое, основано на первом попавшемся примере загрузки изображения по HTTP