Загрузка пробок от Яндекса в мобильный одной небольшой картинкой

12 ноября 2010 г.

В связи с временным переездом в Москву, а именно за МКАД пришлось пользоваться сервисом Яндекс.пробки. Если в Москве скорость загрузки «родного» приложения от Яндекса вполне меня удовлетворяла, то на новом месте это уже не лезло ни в какие ворота. С тем уровнем сигнала одна надпись о проверке версии в течении пары минут начинала раздражать очень сильно. Поэтому, я принял решение написать свое приложение J2ME, позволяющее загрузить небольшое изображение (до 30-60 кб) с пробками в заданном регионе на свой мобильный телефон. Как? Об этом ниже.

Сначала задача была решена посредством сервиса iprobki.ru. J2ME-приложение запрашивало страницу с адресом типа http://iprobki.ru/images/YYYYMMDD На странице искалась последняя временная отсечка (TS), после чего делался запрос вида http://iprobki.ru/images/YYYYMMDD/TS/3.gif Номер картинки — требуемый участок карты.

Но у данного решения оказалось два недостатка:

  1. невысокая гибкость — карта разбита автором, а не мной
  2. излишние затраты трафика. Первый запрос к вечеру превышает 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

Теги:
рубрика Python, Интернет
  • Похожие статьи
  • Предыдущие из рубрики