HelpF.pro

Универсальный парсер RSS для 1С

На одном проекте - клиент попросил отображать в программе данные, которые выдаю специализированные сайта в формате RSS - Что делать !?

Писать парсер rss для 1С

Первым делом, взглянув на ссылки, подумал что  - обычный XML, сейчас его разложу и быстренько загружу в базу, но:

Выяснилось что сайты имеют разные форматы ввода RSS и главное они не валидные(

таким образом, написав небольшой код, который получает ссылку, далее XMLФайл.Прочитать()  на одном сайте проходил на ура (этот пример я описывал в статье: Чтение данных с сайта в формате XML и загрузка в 1С), а вот второй сайт, и третий тоже, при попытке прочитать() выдавали:

{ОбщийМодуль.РегЗадания.Модуль(79)}: Ошибка при вызове метода контекста (Прочитать)

Пока XMLФайл.Прочитать() Цикл

по причине:

Ошибка разбора XML: - [1,1]

Фатальная ошибка:

Extra content at the end of the document 

SystemId url rss

решил попробовать на rss других известных сайтов -  80% из проверяемых выдавали ошибку )

Пришлось написать прямой построчный парсер RSS:

Структура конфигурации

 ИсточникиRSS - URL на RSS, ДанныеRSS - сюда записываются загруженные данные новостей

Код получился таким(в принципе код универсальный, но возможно что-то придется подпилить):

Код 1C v 8.3
 
// RSS
Процедура ПрочитатьRSS(ИсточникRSS)
url = ИсточникRSS.UrlRSS;

// Получим Сервер
Если Найти(url,".ru")>0 Тогда urlСервер = Лев(url,Найти(url,".ru")+2);
ИначеЕсли Найти(url,".com")>0 Тогда urlСервер = Лев(url,Найти(url,".com")+3);
ИначеЕсли Найти(url,".org")>0 Тогда urlСервер = Лев(url,Найти(url,".org")+3);
ИначеЕсли Найти(url,".info")>0 Тогда urlСервер = Лев(url,Найти(url,".info")+4);
ИначеЕсли Найти(url,".pro")>0 Тогда urlСервер = Лев(url,Найти(url,".pro")+3);
КонецЕсли;

//Определим тип соединения
Если Лев(url,5)="https" Тогда
//ssl = Новый ЗащищенноеСоединениеOpenSSL(Новый СертификатКлиентаWindows(), Новый СертификатыУдостоверяющихЦентровWindows());   
ssl = Новый ЗащищенноеСоединениеOpenSSL( неопределено, неопределено );
ТекАдрес = СтрЗаменить(url,urlСервер,""); Сервер = СтрЗаменить(urlСервер,"https://",""); 
Соединение = Новый HTTPСоединение(Сервер,,,,,
5, // таймаут в секундах
ssl // защищенное HTTPS соединение
);
Иначе //Обычный HTTP
ТекАдрес = СтрЗаменить(url,urlСервер,""); Сервер = СтрЗаменить(urlСервер,"http://","");
Соединение = Новый HTTPСоединение(Сервер);
КонецЕсли;


Заголовки = Новый Соответствие;
Заголовки.Вставить("host", Сервер);  
Запрос = Новый HTTPЗапрос(ТекАдрес, Заголовки);
Ответ =Соединение.Получить(Запрос);
Если Ответ.КодСостояния = 200 Тогда // Данные получены, обрабатываем их
Содержимое= Ответ.ПолучитьТелоКакСтроку();
//Преобразуем содержимое
Содержимое = СтрЗаменить(Содержимое,"<br/>","|"); 
Содержимое = СтрЗаменить(Содержимое,"<![CDATA[",""); Содержимое = СтрЗаменить(Содержимое,"]]>","");  
Содержимое = СтрЗаменить(Содержимое,Символы.ПС,""); Содержимое = СтрЗаменить(Содержимое,Символы.ВК,""); 
Содержимое = СтрЗаменить(Содержимое,Символы.ВТаб,""); Содержимое = СтрЗаменить(Содержимое,Символы.Таб,""); 
Содержимое = СтрЗаменить(Содержимое,"><",">"+Символы.ПС+"<"); 

RegExp = Новый COMОбъект("VBScript.RegExp"); //Регулярка
RegExp.IgnoreCase = Ложь; 
RegExp.Global = Истина;    
RegExp.MultiLine = Истина;  
RegExp.Pattern = "<[^>]*>"; //Ищем теги HTML   

//Разберем полученный текст в таблицу
ЭтоЗапись=Ложь;
Для н=1 По СтрЧислоСтрок(Содержимое)Цикл
обрТекст=СтрПолучитьСтроку(Содержимое,н);

Если обрТекст = "<item>" Тогда //Началась запись 
ЗаписьСтр = Новый Структура(); ЭтоЗапись=Истина; Продолжить;  
ИначеЕсли обрТекст = "</item>" Тогда //Закончилась запись 

/////////////// ЗАПИСЬ Закончилась //////////////
/// теперь запишем ее в базу - Справочник ДанныеRSS
// сначала ПОИСК ДУБЛЕЙ - вдруг уже загружен
Запрос = Новый Запрос;
Запрос.Текст = 
"ВЫБРАТЬ
| ДанныеRSS.Ссылка
|ИЗ
| Справочник.ДанныеRSS КАК ДанныеRSS
|ГДЕ
| ДанныеRSS.ИсточникRSS =ИсточникRSS
| И ДанныеRSS.link ПОДОБНОlink";

Запрос.УстановитьПараметр("link", "%"+ЗаписьСтр.link+"%");
Запрос.УстановитьПараметр("ИсточникRSS", ИсточникRSS);
РезультатЗапроса = Запрос.Выполнить().Выбрать();
Если РезультатЗапроса.Следующий() Тогда
// Такая запись уже есть, пока ничего не делаем
Иначе
//СОЗДАЕМ Новый
НовЭлем  = Справочники.ДанныеRSS.СоздатьЭлемент();
ЗаполнитьЗначенияСвойств(НовЭлем,ЗаписьСтр);
НовЭлем.ИсточникRSS = ИсточникRSS;
НовЭлем.Записать();
КонецЕсли;
/////////////////////// *** /////////////////////

ЭтоЗапись=Ложь; Продолжить; 
КонецЕсли; //Данные записи

Если ЭтоЗапись Тогда
Если Найти(обрТекст,"title>")>0 и Найти(обрТекст,"/title>")>0 Тогда
обрТекст = СтрЗаменить(обрТекст,"title",""); обрТекст = СтрЗаменить(обрТекст,"<>",""); обрТекст = СтрЗаменить(обрТекст,"</>","");
ЗаписьСтр.Вставить("Наименование",СокрЛП(обрТекст));
КонецЕсли;

Если Найти(обрТекст,"link>")>0 и Найти(обрТекст,"/link>")>0 Тогда
обрТекст = СтрЗаменить(обрТекст,"link",""); обрТекст = СтрЗаменить(обрТекст,"<>",""); обрТекст = СтрЗаменить(обрТекст,"</>","");
ЗаписьСтр.Вставить("link",СокрЛП(обрТекст));
КонецЕсли;

Если Найти(обрТекст,"description>")>0 и Найти(обрТекст,"/description>")>0 Тогда
обрТекст = СтрЗаменить(обрТекст,"description",""); обрТекст = СтрЗаменить(обрТекст,"<>",""); обрТекст = СтрЗаменить(обрТекст,"</>","");
обрТекст=RegExp.Replace(обрТекст, ""); //Удалим все теги
ЗаписьСтр.Вставить("desc",СокрЛП(обрТекст));
КонецЕсли;

Если Найти(обрТекст,"pubDate>")>0 и Найти(обрТекст,"/pubDate>")>0 Тогда
обрТекст = СтрЗаменить(обрТекст,"pubDate",""); обрТекст = СтрЗаменить(обрТекст,"<>",""); обрТекст = СтрЗаменить(обрТекст,"</>","");
ЗаписьСтр.Вставить("pubDate",ПреобразоватьRFC822КДате0(СокрЛП(обрТекст)));
КонецЕсли;

Если Найти(обрТекст,"enclosure")>0 Тогда  
обрТекст = СтрЗаменить(обрТекст,"""",""); обрТекст = СтрЗаменить(обрТекст,"<enclosure url=","");
обрТекст = СтрЗаменить(обрТекст,"<enclosure url=",""); обрТекст = СтрЗаменить(обрТекст,"type=image/png length=/>","");
ЗаписьСтр.Вставить("img",СокрЛП(обрТекст));
КонецЕсли;
КонецЕсли;

КонецЦикла;

КонецЕсли;

КонецПроцедуры




Процедура ПроверкаRSS() Экспорт
Запрос = Новый Запрос;
Запрос.Текст = 
"ВЫБРАТЬ
| ИсточникиRSS.Ссылка КАК Ссылка
|ИЗ
| Справочник.ИсточникиRSS КАК ИсточникиRSS
|ГДЕ
| ИсточникиRSS.Использовать
| И ДОБАВИТЬКДАТЕ(ИсточникиRSS.ДатаПоследнегоОбновления, СЕКУНДА, ИсточникиRSS.ПериодОбновленияВСекундах) <ТекДата";
Запрос.УстановитьПараметр("ТекДата", ТекущаяДата());
РезультатЗапроса = Запрос.Выполнить();
ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
ПрочитатьRSS(ВыборкаДетальныеЗаписи.Ссылка);
// Запишем дату последнего обновления
ТекОб = ВыборкаДетальныеЗаписи.Ссылка.ПолучитьОбъект();
ТекОб.ДатаПоследнегоОбновления = ТекущаяДата();
ТекОб.Записать();
КонецЦикла;
КонецПроцедуры

Функция ПреобразоватьRFC822КДате0(ДатаВФорматеRFC822) Экспорт
    КопияСтроки = ДатаВФорматеRFC822;
    СтруктураДаты = Новый Структура("Год,Месяц,День,Час,Минута,Секунда",  "","","","","","");
    Месяцы = Новый Структура("Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec",  "01","02","03","04","05","06","07","08","09","10","11","12");
    Для каждого КлючИЗначение Из Месяцы Цикл
        Позиция = Найти(КопияСтроки,КлючИЗначение.Ключ);
        Если Позиция > 0  Тогда
             СтруктураДаты.Месяц = КлючИЗначение.Значение;
            Прервать;
        КонецЕсли;
    КонецЦикла; 
Состояние = 0;
КопияСтроки = СтрЗаменить(КопияСтроки,", 1 ",", 01 ");
КопияСтроки = СтрЗаменить(КопияСтроки,", 2 ",", 02 ");
КопияСтроки = СтрЗаменить(КопияСтроки,", 3 ",", 03 ");
КопияСтроки = СтрЗаменить(КопияСтроки,", 4 ",", 04 ");
КопияСтроки = СтрЗаменить(КопияСтроки,", 5 ",", 05 ");
КопияСтроки = СтрЗаменить(КопияСтроки,", 6 ",", 06 ");
КопияСтроки = СтрЗаменить(КопияСтроки,", 7 ",", 07 ");
КопияСтроки = СтрЗаменить(КопияСтроки,", 8 ",", 08 ");
КопияСтроки = СтрЗаменить(КопияСтроки,", 9 ",", 09 ");
Для ш=0 По СтрДлина(КопияСтроки) Цикл
        ТекущийСимвол = Сред(КопияСтроки,ш,1); //ПолучитьСимвол(КопияСтроки, ш);
        ТекСимволЦифра= ЭтоЦифра(ТекущийСимвол);
        Если ТекСимволЦифра И Состояние = 0  Тогда
            СтруктураДаты.День = СтруктураДаты.День + ТекущийСимвол;
            Состояние = 1; //начало день
        ИначеЕсли ТекСимволЦифра И Состояние = 1  Тогда
            СтруктураДаты.День = СтруктураДаты.День + ТекущийСимвол;
            Состояние = 2; //ждем год
        ИначеЕсли ТекСимволЦифра И Состояние = 2  Тогда
            СтруктураДаты.Год = СтруктураДаты.Год + ТекущийСимвол;
            Состояние = 3; //продолжаем год
        ИначеЕсли ТекСимволЦифра И Состояние = 3  Тогда
            СтруктураДаты.Год = СтруктураДаты.Год + ТекущийСимвол;
        ИначеЕсли ТекущийСимвол = " " И Состояние = 3 Тогда
               Состояние = 4; //дальше час    
        ИначеЕсли ТекСимволЦифра И Состояние = 4  Тогда
            СтруктураДаты.Час = СтруктураДаты.Час + ТекущийСимвол;
        ИначеЕсли ТекущийСимвол = ":" И Состояние = 4  Тогда
            Состояние = 5; //дальше минута
        ИначеЕсли ТекСимволЦифра И Состояние = 5  Тогда
            СтруктураДаты.Минута = СтруктураДаты.Минута +  ТекущийСимвол;
        ИначеЕсли ТекущийСимвол = ":" И Состояние = 5  Тогда
            Состояние = 6; //дальше секунда
        ИначеЕсли ТекСимволЦифра И Состояние = 6  Тогда
            СтруктураДаты.Секунда = СтруктураДаты.Секунда +  ТекущийСимвол;
        ИначеЕсли ТекущийСимвол = " " И Состояние = 6 Тогда
            Прервать;
        КонецЕсли;
    КонецЦикла;
    Попытка
        Результат = Дата(СтруктураДаты.Год+СтруктураДаты.Месяц+СтруктураДаты.День
                        +СтруктураДаты.Час+СтруктураДаты.Минута+СтруктураДаты.Секунда);
    Исключение
        Результат = Неопределено;    
    КонецПопытки;
    Возврат Результат;
КонецФункции

Функция ЭтоЦифра(Символ) Экспорт
     Если (КодСимвола(Символ)>=48) И (КодСимвола(Символ)<=57) Тогда Возврат Истина; Иначе Возврат ложь; КонецЕсли;
КонецФункции

Функция ПолучитьСимвол(КопияСтроки, ш)
Возврат Сред(КопияСтроки,ш,1);
КонецФункции

Результат загрузки новостей RSS HelpF.pro

Кстати, как позже выяснилось, здесь уже есть статья с примером через IE и DOM: Получения новостей с RSS-канала сайта buh.ru


Опубликовано на сайте: https://HelpF.pro
Прямая ссылка: https://HelpF.pro/faq/view/1676.html