понедельник, 3 октября 2016 г.

Использование службы геокодирования Google в 1С 7.7 + чтение динамических страниц

Задание: В 1С для каждой торговой точки записан адрес, необходимо по адресу торговой точки получить ее координаты, для последующего отображения на карте.

Решение: Для получения координат ТТ по адресу используется Google Maps Geocoding API, описание и документация здесь: https://developers.google.com/maps/documentation/geocoding/intro?hl=ru


"Быстрое" решение - использование функций v7plus.dll:

Функция ПолучитьОтветСлужбыГеокодирования(_Адрес)
 
    Попытка
        Соединение = СоздатьОбъект("Addin.V7HttpReader");
        Соединение.КоличествоПопытокАвторизации = 10;
    Исключение
        Сообщить("Не удалось создать объект Addin.V7HttpReader!");
        Возврат 0;
    КонецПопытки;
   
    //
можем указать json или xml
    Адрес = "http://maps.googleapis.com/maps/api/geocode/xml?address=";
    Адрес = Адрес + "ukraine" + "," + СокрЛП(_Адрес);
    Адрес = Адрес + "&components=country:UA";
 
    Стр = ""; // сюда вернется xml или json ответ сервера, который 
    Попытка
        Соединение.Получить(Адрес, Стр, 2); //строка
    Исключение
        Сообщить("Неудачная попытка соединения.");
    КонецПопытки;
   
    Возврат стр;

   
КонецФункции

"Быстрое" решение было рабочим, однако, периодически ответ сервера усекался до 1-2 килобайт. При этом если строку запроса вставить в браузер - всегда возвращается нормальный ответ.

Оказалось, проблема известная, рассматривалась неоднократно:

1. V7Plus не полностью выкачивает страничку
"AddIn.V7HttpReader прекрасно работает с любыми страницами и качает всю как надо. Проблема в самих страницах, которые не отдают заголовок "Content-length". Поэтому по-умолчанию используется 1Кб."


2.V7HttpReader метод получить файл
"С помощью метода ПолучитьКакФайл пытаюсь с сайта выгрузить файл xml нужного формата. Проблема - файл не загружается полностью. ... Пробовал по всякому и через ПолучитьКакСтроку и с циклом после получения (типа для докачивания, если оно в фоне).
Все-равно файл загружается не полностью. Если через браузер все скачивается без проблем."

"Это не работает, когда динамически генерируется страница через пост-запрос. ПолучитьКакФайл работает для скачивания ТОЛЬКО статического содержимого."

И приводится код решения:
    Скрипт = СоздатьОбъект("MSScriptControl.ScriptControl");
    Скрипт.language = "vbscript";
          
    x = CreateObject("Microsoft.XMLHTTP");
    x.Open("GET", АдресСтраницы, 0,"","");
    x.Send();
          
    s = CreateObject("ADODB.Stream");
    s.Mode = 3;
    s.Type = 1;
    s.Open();
          
    Скрипт.AddObject("s",s);
    Скрипт.AddObject("x",x);
    Скрипт.Eval("s.Write(x.responseBody)");
          
    s.SaveToFile(ИмяФайлаЗагрузки, 2);
3. Наиболее подробно и полно вопрос рассматривается здесь: Мои опыты чтения динамических WEB-страниц
  • Вариант 1-5 - различные модификации использования V7HttpReader, и делается вывод, что внешняя компонента v7plus.dll и ее объект AddIn.V7HttpReader не годятся для чтения  динамических WEB-страниц.
  • Вариант 6:  ФС.КопироватьФайл(Адрес,Результат) - нерабочий
  • Вариант 7: WinHttp.WinHttpRequest.5.1
  • Вариант 8: InternetExplorer.Application
  • Вариант 9. MSXML2.XMLHTTP
  • Вариант 10. WinHttp.WinHttpRequest.5.1 + MSScriptControl
  • Вариант 11.MSXML2.XMLHTTP +  MSScriptControl  + VBScript
  • Вариант 12. MSXML2.XMLHTTP (http-test.vbs + WScript.Shell)
  • Вариант 13. Microsoft.XMLHTTP+ MSScriptControl+ADODB.Stream

В итоге, пришлось переписать процедуру на вариант с использованием Microsoft.XMLHTTP +
ADODB.Stream + MSScriptControl.ScriptControl.

Код функции под катом:
Функция ПолучитьКоординатыТТПоАдресу1С(_Адрес)
   
    сз = СоздатьОбъект("СписокЗначений");
   
    ПолноеИмяФайла = КаталогВременныхФайлов() + "geocoding_answer.xml";
   
    Имя = "";
    Пароль = "";

    Адрес = "http://maps.googleapis.com/maps/api/geocode/xml?address=";

    Адрес = Адрес + "ukraine" + "," + СокрЛП(_Адрес);
    Адрес = Адрес + "&components=country:UA";
 

    XMLHTTP = CreateObject("Microsoft.XMLHTTP");
    XMLHTTP.Open("GET", Адрес, 0, Имя, Пароль);
    XMLHTTP.Send();

    Stream = CreateObject("ADODB.Stream");
    Stream.Mode = 3;
    Stream.Type = 1;
    Stream.Open();

    Скрипт = СоздатьОбъект("MSScriptControl.ScriptControl");
    Скрипт.language = "vbscript";
    Скрипт.AddObject("Stream", Stream);
    Скрипт.AddObject("XMLHTTP", XMLHTTP);
    Скрипт.Eval("Stream.Write(XMLHTTP.responseBody)");
   
    // сохраняем результат во временный файл

    Stream.SaveToFile(ПолноеИмяФайла, 2);

   
    // а теперь прочитаем полученный и записанный файл
   
    XMLАнализатор = СоздатьОбъект("AddIn.XMLParser");

    док = XMLАнализатор.СоздатьДокумент();
    //док.Кодировка="UTF-8";    // пока работает и без этого

    Попытка 

        док.Загрузить(СокрЛП(ПолноеИмяФайла));
    Исключение
        Сообщить("Операция не вполнена: " + ОписаниеОшибки());
        Сообщить("Файл " + СокрЛП(ПолноеИмяФайла) + " поврежден или удален.");
        Возврат 0;
    КонецПопытки;
   
    КорневойУзел = док.ЭлементДокумента;    // корневой узел документа   

    УзелСтатуса = КорневойУзел.ВыбратьУзел("status");
    сз.ДобавитьЗначение(УзелСтатуса.Значение, "СтатусОтветаСервера");

    УзелРезультата = КорневойУзел.ВыбратьУзел("result");

    УзелАдреса = УзелРезультата.ВыбратьУзел("formatted_address");
    сз.ДобавитьЗначение(УзелАдреса.Значение, "АдресGoogle");
   
    Узел_geometry = УзелРезультата.ВыбратьУзел("geometry");

    Узел_location = Узел_geometry.ВыбратьУзел("location");

    УзелШироты = Узел_location.ВыбратьУзел("lat");
    сз.ДобавитьЗначение(Число(УзелШироты.Значение), "ШиротаGoogle");
   
    УзелДолготы = Узел_location.ВыбратьУзел("lng");
    сз.ДобавитьЗначение(Число(УзелДолготы.Значение), "ДолготаGoogle");
   
    Узел_location_type = Узел_geometry.ВыбратьУзел("location_type");
    сз.ДобавитьЗначение(Узел_location_type.Значение, "ТипОтветаСервера");
   
    //   
    XMLHTTP = 0;
    Stream = 0;
    Скрипт = 0;
    XMLАнализатор = 0;
    

    //
    Возврат сз;
   
КонецФункции


Комментариев нет: