Недавно, мой постоянный клиент решил проводить маркетинговые исследования по изменению цен на товары у конкурентов... и эти данные захотел использовать в 1С в связке с его прайс-листом + куча отчетов с графиками и процентным отклонением от цен основного конкурента
В результате этого, была написана обработка собирающая данные со страниц разных сайтов. Из целей конфиденциальности - сайты раскрывать не буду...
Вид обработки загрузки данных с сайта в 1С
Ниже код загрузки данных со страницы сайта , смысл такой :
в функция передается адрес страницы сайта полученный текст страницы обрабатывается, удаляются теги из полученного текста формируется ТЗ с данными По названию ищется поставщик из вспомогательного справочника Справочники.Pr_Поставщики.НайтиПоНаименованию(, если нет - создается на выходе ТЗ с данными Код 1C v 8.х Функция ПолучитьТаблицуДанных(Строка)
тзДанных = Новый ТаблицаЗначений;
Сервер = "site.ru";
Соединение = Новый HTTPСоединение(Сервер);
Заголовки = Новый Соответствие;
Заголовки.Вставить("host", Сервер);
ТекАдрес = СтрЗаменить(Строка.Наименование.УРЛСтраницы,"http://","");
ТекАдрес = СтрЗаменить(ТекАдрес,Сервер,"");
Запрос = Новый HTTPЗапрос(ТекАдрес, Заголовки);
Ответ =Соединение.Получить(Запрос);
Если Ответ.КодСостояния = 200 Тогда // Данные получены, обрабатываем их
Содержимое= Ответ.ПолучитьТелоКакСтроку();
//Выведем тест полученной страницы
НачалоБлока = "<table id=" + """" + "table-price" + """" + " cellspacing=" + """" + "0" + """" + " border=" + """" + "1" + """" + " bordercolor=" + """" + "#dedede" + """" + " class=" + """" + "tablesorter" + """" + " >";
//НачалоБлока = "<div class=" + """" + "w100fl" + """" + " id=" + """" + "kurs" + """" + ">";
КонецБлока = "</table>";
ТекстБлока = Сред(Содержимое, Найти(Содержимое, НачалоБлока) + СтрДлина(НачалоБлока), Найти(Содержимое, КонецБлока) - Найти(Содержимое, НачалоБлока) - СтрДлина(НачалоБлока));
//Обработаем тест
обрТекст = СтрЗаменить(ТекстБлока,"<tr>","");
обрТекст = СтрЗаменить(обрТекст,"</tr>",Символы.ПС);
обрТекст = СтрЗаменить(обрТекст," >", ">");
обрТекст = СтрЗаменить(обрТекст,"</th> <th>", " | ");
обрТекст = СтрЗаменить(обрТекст,"</td> <td>", " | ");
обрТекст = СтрЗаменить(обрТекст,"</th> <th class=" + """" + "sortable_header" + """" + ">", " | ");
обрТекст = СтрЗаменить(обрТекст,"</th> <th >", " | ");
обрТекст = СтрЗаменить(обрТекст,"</th><th>", " | ");
обрТекст = СтрЗаменить(обрТекст,"</td><td>", " | ");
обрТекст = СтрЗаменить(обрТекст," >", ">");
RegExp = Новый COMОбъект("VBScript.RegExp");
RegExp.IgnoreCase = Ложь;
RegExp.Global = Истина;
RegExp.MultiLine = Истина;
RegExp.Pattern = "<[^>]*>"; //Ищем теги HTML
обрТекст=RegExp.Replace(обрТекст, "");
//Сообщить(обрТекст);
Если СокрЛП(обрТекст) = "Ни одной позиции не найдено." Тогда
Сообщить(Строка(Строка.Наименование)+ " = Ни одной позиции не найдено! Строка " + Строка.Наименование);
Возврат тзДанных;
КонецЕсли;
Если Найти(обрТекст, "Страница не найдена") > 0 Тогда
Сообщить(Строка(ТекАдрес)+" = Страница не найдена, строка " + Строка.Наименование);
Возврат тзДанных;
КонецЕсли;
//Преобразуем полученный текст в таблицу
Для н=1 По СтрЧислоСтрок(обрТекст)Цикл
СтрТекста=СтрПолучитьСтроку(обрТекст,н);
Если Найти(СтрТекста, "Длина Цена") > 0 Тогда
СтрТекста = СтрЗаменить(СтрТекста, "Длина Цена", "Длина | Цена");
КонецЕсли;
Если Найти(СтрТекста, "Марка стали Цена") > 0 Тогда
СтрТекста = СтрЗаменить(СтрТекста, "Марка стали Цена", "Марка стали | Цена");
КонецЕсли;
Если Найти(СтрТекста, ", Поставщик") > 0 Тогда
СтрТекста = СтрЗаменить(СтрТекста, ", Поставщик", " | Поставщик");
КонецЕсли;
//Выводим текст страницы построчно
мсДанных = ПолучитьМассивИзСтрокиСРазделителем(СтрТекста, "|", Истина);
Если н=1 Тогда
Для Каждого ткЗнач из мсДанных Цикл
СтрЗапрещСимволов = " .,<>""\/-";
ИмяКолонки = ткЗнач;
Для сч33 = 1 по СтрДлина(СтрЗапрещСимволов) Цикл
ЗапрещСимв = Сред(СтрЗапрещСимволов, сч33, 1);
ИмяКолонки = СтрЗаменить(ИмяКолонки, ЗапрещСимв, "_");
КонецЦикла;
// добавим нужное количество колонок- если перед колонкой Поставщик не хватает
// бывает, что в шапке определяется меньше колонок, чем реально в таблице
Если НРег(ИмяКолонки) = "поставщик" Тогда
Для Сч_дк = (Строка.Наименование.Родитель.Поставшик - 2) по тзДанных.Колонки.Количество() Цикл
тзДанных.Колонки.Добавить("Колонка_" + (тзДанных.Колонки.Количество() + 1));
КонецЦикла;
КонецЕсли;
тзДанных.Колонки.Добавить(ИмяКолонки);
КонецЦикла;
тзДанных.Колонки.Добавить("ном", , , 7);
Иначе
НовСтр = тзДанных.Добавить(); нмас=0;
Для Каждого ткЗнач из мсДанных Цикл
НовСтр[нмас] = ткЗнач;
нмас=нмас+1;
КонецЦикла;
НовСтр.ном = н;
КонецЕсли;
//Сообщить(стр);
КонецЦикла;
тзДанных.Колонки.Добавить("ЕстьСоответствие", Новый ОписаниеТипов("Булево"));
тзДанных.Колонки.Добавить("СпрPr_Поставщики", Новый ОписаниеТипов("СправочникСсылка.Pr_Поставщики"));
Для каждого стр из тзДанных Цикл
текПоставщик = Справочники.Pr_Поставщики.НайтиПоНаименованию(стр[Строка.Наименование.родитель.Поставшик-1]);
Если текПоставщик = Справочники.Pr_Поставщики.ПустаяСсылка() Тогда
НовЭлем = Справочники.Pr_Поставщики.СоздатьЭлемент();
НовЭлем.Наименование = СокрЛП(стр[Строка.Наименование.родитель.Поставшик-1]);
НовЭлем.Записать();
текПоставщик = НовЭлем.Ссылка;
КонецЕсли;
стр.СпрPr_Поставщики = текПоставщик;
КонецЦикла;
Иначе
тзДанных.Колонки.Добавить("ЕстьСоответствие", Новый ОписаниеТипов("Булево"));
тзДанных.Колонки.Добавить("СпрPr_Поставщики", Новый ОписаниеТипов("СправочникСсылка.Pr_Поставщики"));
Сообщить("Ошибка получения данных для строки " + Строка.Наименование);
КонецЕсли;
Возврат тзДанных;
КонецФункции
В коде используется вспомогательная функция ПолучитьМассивИзСтрокиСРазделителем
Код 1C v 8.2 УП
Функция ПолучитьМассивИзСтрокиСРазделителем(Знач Стр, Разделитель = "." , ОбрезатьНепечатныеСимволы = Ложь) Экспорт
МассивСтрок = Новый Массив;
Если Разделитель = " " Тогда
Стр = СокрЛП( Стр) ;
Пока 1 = 1 Цикл
Поз = Найти( Стр, Разделитель) ;
Если Поз= 0 Тогда
МассивСтрок. Добавить( Стр) ;
Возврат МассивСтрок;
КонецЕсли ;
МассивСтрок. Добавить( Лев( Стр, Поз- 1 ) ) ;
Стр = СокрЛ( Сред( Стр, Поз) ) ;
КонецЦикла ;
Иначе
ДлинаРазделителя = СтрДлина( Разделитель) ;
Пока 1 = 1 Цикл
Поз = Найти( Стр, Разделитель) ;
Если Поз= 0 Тогда
Фрагмент = Стр;
Если ОбрезатьНепечатныеСимволы Тогда
Фрагмент = СокрЛП( Фрагмент) ;
КонецЕсли ;
МассивСтрок. Добавить( Фрагмент) ;
Возврат МассивСтрок;
КонецЕсли ;
Фрагмент = Лев( Стр, Поз- 1 ) ;
Если ОбрезатьНепечатныеСимволы Тогда
Фрагмент = СокрЛП( Фрагмент) ;
КонецЕсли ;
МассивСтрок. Добавить( Фрагмент) ;
Стр = Сред( Стр, Поз+ ДлинаРазделителя) ;
КонецЦикла ;
КонецЕсли ;
Возврат МассивСтрок;
КонецФункции
Конечно, перед тем как мы начали это делать - прошерстили интернет и нашли несколько решений , вот они:
Код 1C v 8.х Соединение = ПолучитьCOMОбъект( "" , "Microsoft.XMLHTTP" ) ;
ИмяВременногоФайла= ПолучитьИмяВременногоФайла( "htm" ) ;
Соединение. open( "GET" , "http://mamba.ru/my" , 0 ) ;
Соединение. send( ) ;
ТаймАут = 200 ;
Начало= ТекущаяДата( ) ;
Пока Соединение. readyState < > 4 И ( ТаймАут= 0 ИЛИ ТекущаяДата( ) - Начало< ТаймАут) Цикл
бфДиалоги. ксОбработкаПрерыванияПользователя( ) ;
КонецЦикла ;
обСохранитьДвоичныйБуферВФайл( Соединение. responseBody, ИмяВременногоФайла) ;
Соединение. open( "POST" , "http://mamba.ru/my" ) ;
Соединение. send( "login=xxx&password=&&&" ) ;
Функция обСохранитьДвоичныйБуферВФайл(Буфер, ИмяФайла) Экспорт
Поток = Новый COMОбъект( "ADODB.Stream" ) ;
Поток. Type = 1 ;
Поток. Mode = 3 ;
Поток. Open( ) ;
Поток. Write( Буфер) ;
Поток. SaveToFile( ИмяФайла) ;
Поток. Close( ) ;
КонецФункции
Код 1C v 8.х НТТР = ПолучитьCOMОбъект( "" , "Microsoft.XMLHTTP" ) ;
ИмяФайлаОтвета = КаталогВременныхФайлов( ) + "filename.tmp" ;
НТТР. open( "GET" , "www.google.com" , 0 , , ) ;
НТТР. send( ) ;
StreamTypeEnum = Новый Структура( "adTypeBinary, adTypeText" , 1 , 2 ) ;
ConnectModeEnum = Новый Структура(
"adModeRead, adModeReadWrite, adModeRecursive, adModeShareDenyNone,
|adModeShareDenyRead, adModeShareDenyWrite, adModeShareExclusive,
|adModeUnknown, adModeWrite" , 1 , 3 , 4194304 , 16 , 4 , 8 , 12 , 0 , 2 ) ;
SaveOptionsEnum = Новый Структура( "adSaveCreateNotExist, adSaveCreateOverWrite" , 1 , 2 ) ;
StreamOut = Новый COMОбъект( "ADODB.Stream" ) ;
StreamOut. Type = StreamTypeEnum. adTypeBinary;
StreamOut. Mode = ConnectModeEnum. adModeReadWrite;
StreamOut. Open( ) ;
StreamOut. Write( НТТР. responseBody) ;
StreamOut. SaveToFile( ИмяФайлаОтвета, SaveOptionsEnum. adSaveCreateOverWrite) ;
StreamOut. Close( ) ;
И даже не этом сайте есть статья : Парсер сайта связного на 1С
Нужен парсер сайта в 1С!? - Обращайтесь, контакты в
профиле Перерыл интернет для поиска решения следующей задачи: Вывести картинку состояния в табличную часть (динамический список).
Входящие данные:1. Дерево значений с колонкой "Документы".
Задача:1. Рядом с ссылкой на документ выводить картинку "Проведен, Помечен на удаление, Записан, Документа нет".
Получилось следующее:
Что нужно что бы так получилось:1. Со стороны кода.
2. Со стороны формы:
За оформление извиняюсь. Рисовал с помощью ножниц =).
С задачей получения среза последних на каждую дату рано или поздно сталкиваются все. Безусловно, это задача достаточно просто решается запросом с соединением по максимальной дате из меньших или равных дат. Но эту же задачу можно решить и с помощью компоновки данных. Не будем рассуждать о том, какой из способов более производителен, все может зависеть от конкретной задачи.
Первый набор данных:
В качестве примера, создадим отчет по продажам, в котором отдельной
колонкой будем выводить цену из прайса на дату продажи.
Создадим набор данных-запрос «ПродажиОбороты»:
Код 1C v 8.х ВЫБРАТЬ
ПродажиОбороты. Период КАК Дата,
ПродажиОбороты. Контрагент КАК Контрагент,
ПродажиОбороты. Номенклатура КАК Номенклатура,
ПродажиОбороты. КоличествоОборот КАК Количество,
ПродажиОбороты. СтоимостьОборот КАК Стоимость
{ВЫБРАТЬ
Дата,
Контрагент. * ,
Номенклатура. * ,
Количество,
Стоимость}
ИЗ
РегистрНакопления. Продажи. Обороты( {( &НачалоПериода)},
{( &КонецПериода)}, День, ) КАК ПродажиОбороты
{ГДЕ
ПродажиОбороты. Период,
ПродажиОбороты. Контрагент. * ,
ПродажиОбороты. Номенклатура. * ,
ПродажиОбороты. КоличествоОборот,
ПродажиОбороты. СтоимостьОборот}
Рис. 1 Вкладка ресурсы набора данных ПродажиОбороты
Рис. 2 Настройки отчета
Сейчас наш отчет будет иметь следующий вид:
Рис. 3 Формирование отчета с одним набором данных
Теперь необходимо добавить в отчет колонку «Цена по прайсу», которая будет подтягиваться из регистра сведений «Цены номенклатуры» на дату продажи.
Второй набор данных:
Добавим второй набор данных-запрос «Цены», цены будем брать для фиксированного типа цен:
Код 1C v 8.х ВЫБРАТЬ
&Дата КАК Дата,
ЦеныНоменклатурыСрезПоследних. Номенклатура КАК Номенклатура,
ЦеныНоменклатурыСрезПоследних. Цена КАК Цена
{ВЫБРАТЬ
Дата,
Номенклатура. * ,
Цена}
ИЗ
РегистрСведений. ЦеныНоменклатуры. СрезПоследних(
&Дата,
Номенклатура = &Номенклатура
И ТипЦен = &ТипЦен) КАК ЦеныНоменклатурыСрезПоследних
{ГДЕ
( &Дата),
ЦеныНоменклатурыСрезПоследних. Номенклатура. * ,
ЦеныНоменклатурыСрезПоследних. Цена}
В данном наборе данных три параметра: Дата, Номенклатура и тип цен. Из низ самые интересные Дата и Номенклатура. Они будут использованы при соединении наборов данных, причем параметр данных присутствует как в параметрах виртуальной таблицы, так и в выбранных полях.
Соединения наборов:
Приступим к основной «фишке» данного метода – соединениям наборов:
Рис. 4 Соединение наборов данных
Здесь самое основное правильно настроить параметры. Если указан параметр,то СКД передает в приемник связи параметры, указанные в соединении. Значениями этих параметров будут значения соответствующих полей источника связи.
Далее добавим поле цена в ресурсы и в выбранные поля.
Рис. 5 Вкладка ресурсы
Рис. 6 Выбранные поля
Результат:
Теперь можно формировать отчет. Проверим правильность работы отчета на примере «Дивана для отдыха».
Рис. 7 Итоговый отчет
Первоисточник
Как получить Срез Последних значений на Каждую Дату
То же самое простым запросом