Search
Write a publication
Pull to refresh

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

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

Сначала задача была решена посредством сервиса iprobki.ru. J2ME-приложение запрашивало страницу с адресом типа iprobki.ru/images/YYYYMMDD. На странице искалась последняя временная отсечка (TS), после чего делался запрос вида 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()


* This source code was highlighted with Source Code Highlighter.

Да, чуть не забыл. Само J2ME приложение здесь не привожу. Оно очень простое, основано на первом попавшемся примере загрузки изображения по HTTP
Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.