gifts2017

Парсинг многостраничного сайта "Рейтинг Центров Компетенции 1С"

Опубликовал Анатолий Бычин (tolyan_ekb) в раздел Обмен - Интеграция с WEB

После прочтения интересной статьи http://infostart.ru/public/88106/ от opx, у меня осталось несколько вопросов, связанных с парсингом многостраничных сайтов. Кроме того, хотелось закрепить полученные навыки.

Обработка позволяет получить данные о показателях фирм франчайзи, что в конечном итоге определяет их место в общем списке.

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

В обработке создадим две дополнительные формы: ДопФорма (размещен элемент ПолеHTML документа, имя Сайт), ДопФорма2 (размещен элемент ПолеHTML документа, имя Сайт)

//описание переменных главной формы
Перем ТЗСтраниц;
Перем НТТР; // - переменная для хранения соединения с сервером
Перем ИмяВходящегоФайла;
Перем СерверИсточник;
Перем Адрес; // - переменная для хранения адреса начальной страницы
Перем НомСтр; // - переменная для подсчета строк в таблице
Перем ТекНом; // - текущий номер страницы франчайзи
Перем ФлагОперации; //- переменная определяет, что нужно грузить (всех франчей или тех что выбрал пользователь)

 Устанавливаем соединение с сайтом

СерверИсточник = "http://www.1c.ru/";
Адрес = "/rus/partners/ckp.jsp";
ИмяВходящегоФайла= КаталогВременныхФайлов()+"input.txt";
Если прокси Тогда
    ПроксиСервер = Новый ИнтернетПрокси;
    ПроксиСервер.Пользователь = Пользователь;
    ПроксиСервер.Пароль = Пароль ;
    ПроксиСервер.Установить(Протокол, АдресПрокси,  Порт);

    // Укажем в HTTP соединении что у нас есть прокси 
    НТТР = Новый HTTPСоединение(СерверИсточник,,,, ПроксиСервер);
иначе
    НТТР = Новый HTTPСоединение(СерверИсточник,,,,);
КонецЕсли; 

НТТР.Получить(Адрес, ИмяВходящегоФайла);
ТекстИзФайла = Новый ТекстовыйДокумент;
ТекстИзФайла.Прочитать(ИмяВходящегоФайла);
Тест = ТекстИзФайла.ПолучитьТекст();
ФлагОперации="ПервичнаяЗагрузка";
ЭлементыФормы.Сайт.УстановитьТекст(Тест);

Заполняем список регионов на форме

Процедура ЗаполнитьРегионы()
    //очищаем поле выбора
    ЭлементыФормы.ПолеВыбораРегион.СписокВыбора.Очистить();
    //цикл по всей страничке
    Для Каждого Стр из ЭлементыФормы.Сайт.Документ.body.all Цикл
        //ищем элемент с именем тэга "SELECT"  и именем "r"              
        Если Стр.tagName = "SELECT" и Стр.name="r" Тогда 
            //ищем регионы цикл по подчиненным элементам списка
            Для каждого Стр1 из Стр.all Цикл
                //для всех подчиненных элементов получаем значения, кроме пустых                      
                Если Стр1.value<>"" Тогда
                    СтрСп=ЭлементыФормы.ПолеВыбораРегион.СписокВыбора.Добавить();
                    СтрСп.Значение=Стр1.value;
                    СтрСп.Представление=Стр1.text;
                КонецЕсли;
            КонецЦикла;
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

Заполняем список городов на форме.

Процедура ЗаполнитьГорода()
    //очищаем поле выбора
    ЭлементыФормы.ПолеВыбораГород.СписокВыбора.Очистить();
    //цикл по всей страничке
     Для Каждого Стр из ЭлементыФормы.Сайт.Документ.body.all Цикл
         //ищем элемент с именем тэга "SELECT"  и именем " city "        
         Если Стр.tagName = "SELECT" и Стр.name="city" Тогда
             //ищем города цикл по подчиненным элементам списка
             Для каждого Стр1 из Стр.all Цикл
                 //для всех подчиненных элементов получаем значения, кроме пустых
                 Если Стр1.value<>"" Тогда              
                     СтрСп=ЭлементыФормы.ПолеВыбораГород.СписокВыбора.Добавить();
                     СтрСп.Значение=Стр1.value;
                     СтрСп.Представление=Стр1.text;
                 КонецЕсли;
             КонецЦикла;
         КонецЕсли;
     КонецЦикла;            
КонецПроцедуры

Заполняем отрасли. 

Процедура ЗаполнитьОтрасли()
    //очищаем поле выбора
    ЭлементыФормы.ПолеВыбораОтрасль.СписокВыбора.Очистить();
    Для Каждого Стр из ЭлементыФормы.Сайт.Документ.body.all Цикл
        //ищем элемент с именем тэга "SELECT"  и именем " branch_ckp "
        Если Стр.tagName = "SELECT" и Стр.name="branch_ckp" Тогда 
            //ищем отрасли цикл по подчиненным элементам списка
            Для каждого Стр1 из Стр.all Цикл
                Если Стр1.value<>"" Тогда
                    СтрСп=ЭлементыФормы.ПолеВыбораОтрасль.СписокВыбора.Добавить();
                    СтрСп.Значение=Стр1.value;
                    СтрСп.Представление=Стр1.text;
                КонецЕсли;
            КонецЦикла;
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

Считываем количество страниц и заполняем доп данные для отбора.

Процедура СайтДокументСформирован(Элемент)
    фл=0;
    Если НомСтр=1 Тогда
        ОпределитьКоличествоСтраниц();
        ЗаполнитьРегионы();
        ЗаполнитьОтрасли();
    КонецЕсли; 
КонецПроцедуры

 

Процедура ОпределитьКоличествоСтраниц()
    //ищем параграф со страницами и вычисляем максимальное их число
    Если ФлагОперации="ПервичнаяЗагрузка" Тогда
        ТЗСтраниц=Новый ТаблицаЗначений;
        ТЗСтраниц.Колонки.Добавить("Номер");
        ТЗСтраниц.Колонки.Добавить("Ссылка");
  
        Для Каждого Стр из ЭлементыФормы.Сайт.Документ.body.all Цикл
            Если Стр.tagName = "P" и Найти(Стр.innerText,"Страницы:")>0 Тогда  //ищем раздел страниц
                стррез=Стр.innerHTML;
                поз=Найти(стррез,"href=");
                стрперехода=Прав(стррез,СтрДлина(стррез)-поз-5);
                поз=Найти(стрперехода,"""");
                стрПерехода=Лев(стрперехода,поз);
                Если стрПерехода<>Неопределено Тогда
                    //определим тело ссылки
                    ТелоСсылки=Лев(стрПерехода,Найти(стрПерехода,"=")-1);
                    колссылок=СтрЧислоВхождений(стррез,ТелоСсылки);
                    СтрТЗ=ТЗСтраниц.Добавить();
                    СтрТЗ.Ссылка=ТелоСсылки;
                    СтрТЗ.Номер=1;
     
                    Пока колссылок>0 Цикл
                        СтрТЗ=ТЗСтраниц.Добавить();
                        стррез=Сред(стррез,Найти(стррез,"href=")+5);
                        стррез=Сред(стррез,СтрДлина(ТелоСсылки)+2);
                        СтрТЗ.Ссылка=ТелоСсылки;
                        Если СокрЛП(стррез)<>"" Тогда
                            СтрТЗ.Номер=число(сред(стррез,2,Найти(стррез,"""")-2));//Лев(стррез,Найти(стррез,"""")-1));
                        КонецЕсли;
                        колссылок=колссылок-1; 
                    КонецЦикла;
                КонецЕсли;
            КонецЕсли;
        КонецЦикла; 
  
  
        ТЗСтраниц.Свернуть("ССылка,Номер");
        //дополняем недостающие страницы
        РазностьСтраниц=число(СтрЗаменить(ТЗСтраниц[ТЗСтраниц.Количество()-1].Номер,"=",""))-число(СтрЗаменить(ТЗСтраниц[0].Номер,"=",""))+1;
        Пока РазностьСтраниц>1 Цикл
            РазностьСтраниц=РазностьСтраниц-1;
   
            СтрокаТЗ=ТЗСтраниц.Найти(РазностьСтраниц,"Номер");
            Если СтрокаТЗ<>Неопределено Тогда
                Продолжить;
            иначе
                СтрТЗ=ТЗСтраниц.Добавить();
                СтрТЗ.Ссылка=ТелоСсылки;
                СтрТЗ.Номер=число(РазностьСтраниц);
            КонецЕсли;
        КонецЦикла; 
        ТЗСтраниц.Сортировать("Номер возр");
    ИначеЕсли ФлагОперации="ВыборРегиона" Тогда
        ЗаполнитьГорода();
    КонецЕсли; 
КонецПроцедуры 

Затем у нас два варианта: заполнить по всем франчам без отбора или заполнить с отбором.

//заполняем таблицу данными с указанынми регионом/городом/отраслью
Процедура ОсновныеДействияФормыЗагрузитьВыбранные(Кнопка)
    ЭтотОбъект.Франчайзи.Очистить();
    НТТР.Получить(Адрес+"?armRange=&r="+?(ВыбранныйРЕгион="","",ВыбранныйРЕгион)+"&city="+?(ВыбранныйГород="","",ВыбранныйГород)+"&branch_ckp="+ЭлементыФормы.ПолеВыбораОтрасль.Значение, ИмяВходящегоФайла);
    ТекстИзФайла = Новый ТекстовыйДокумент;
    ТекстИзФайла.Прочитать(ИмяВходящегоФайла);
    Тест = ТекстИзФайла.ПолучитьТекст();
    Форма = ПолучитьФорму("ДопФорма");
    Форма.Город=ЭлементыФормы.ПолеВыбораГород.Значение;
    Форма.ЭлементыФормы.Сайт.УстановитьТекст(Тест);
    Форма.ОткрытьМодально();
КонецПроцедуры

 

//загружаем всех франчей без отбора
Процедура ОсновныеДействияФормыЗагрузитьДанные(Кнопка)
    ЗаполнитьТаблФранчей();
КонецПроцедуры

Обработать все страницы и заполнить табличную часть

Процедура ЗаполнитьТаблФранчей()
    кол=0;
    Для каждого НомСтр из ТЗСтраниц Цикл
        ЗаполнитьДопТаблицу(НомСтр.Номер,НомСтр.ссылка);
    КонецЦикла;
    ЗаписатьДанныеВРегистр()
КонецПроцедуры

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

Код первой допформы:

Перем ТекущийФранчайзи,Город Экспорт;
Перем флЗагрузки;

Процедура ГрузимДанные()
    строканом=0;
 
    Для Каждого Стр из ЭлементыФормы.Сайт.Документ.body.all Цикл
        Если Стр.tagName = "TABLE" и Стр.classname = "content" Тогда
            фл=1;
        ИначеЕсли Стр.tagName = "TABLE" и Стр.classname <> "content" Тогда
            фл=0;
        КонецЕсли; 
        Если Стр.tagName = "TR" и фл=1 Тогда
            строканом=строканом+1;
            Если строканом>1 тогда
                Если Стр.childNodes.length>1 Тогда //если узлов больше то это данные
                    новСтр = Франчайзи.Добавить();
     
                    Для каждого стрТЧ из Стр.childNodes Цикл
                        //сообщить(стрТЧ.innerText);
                        Если стрТЧ.cellIndex=1 Тогда
                            Если НЕ ЗначениеЗаполнено(Город) Тогда
                                новСтр.Город=Лев(стрТЧ.innerText,Найти(стрТЧ.innerText,"/")-1);
                                стрТЧ.innerText=Прав(стрТЧ.innerText,СтрДлина(стрТЧ.innerText)-Найти(стрТЧ.innerText,"/"));
                                новСтр.Наименование =Лев(стрТЧ.innerText,Найти(стрТЧ.innerText,"/")-1);
                            Иначе
                                новСтр.Город =Город;
                                новСтр.Наименование =Лев(стрТЧ.innerText,Найти(стрТЧ.innerText,"/")-1);
                            КонецЕсли;
                            //регион ищем в адресном классификаторе
                            Запрос=Новый Запрос;
                            Запрос.Текст="ВЫБРАТЬ
                                         | АдресныйКлассификатор1.Наименование,
                                         | АдресныйКлассификатор1.Сокращение,
                                         | АдресныйКлассификатор1.КодРегионаВКоде,
                                         | АдресныйКлассификатор1.ТипАдресногоЭлемента
                                         |ИЗ
                                         | РегистрСведений.АдресныйКлассификатор КАК АдресныйКлассификатор1
                                         |  ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдресныйКлассификатор КАК АдресныйКлассификатор
                                         |  ПО АдресныйКлассификатор1.КодРегионаВКоде = АдресныйКлассификатор.КодРегионаВКоде
                                         |ГДЕ
                                         | АдресныйКлассификатор.Наименование = &Наим
                                         | И АдресныйКлассификатор.Сокращение = ""г""
                                         | И АдресныйКлассификатор1.ТипАдресногоЭлемента = 1";
                            Запрос.УстановитьПараметр("Наим",сокрлп(новСтр.Город));
                            ТЗЗапрос=Запрос.Выполнить().Выгрузить();
                            Если ТЗЗапрос.Количество()>0 Тогда
                                новСтр.Регион=ТЗЗапрос[0].Наименование+" "+ТЗЗапрос[0].Сокращение;
                            КонецЕсли; 
      
                        ИначеЕсли стрТЧ.cellIndex=2 Тогда
                            новСтр.Спец=стрТЧ.innerText;
                        ИначеЕсли стрТЧ.cellIndex=3 Тогда
                            новСтр.АРМ =Лев(стрТЧ.innerText,Найти(стрТЧ.innerText,"/")-1);
                            новСтр.Внедр = Прав(стрТЧ.innerText,Найти(стрТЧ.innerText,"/")-3);       
                        ИначеЕсли стрТЧ.cellIndex=4 Тогда
                            //новСтр.Отрасль=стрТЧ.innerText;
                        ИначеЕсли стрТЧ.cellIndex=5 Тогда
                            ЛевЧасть=Лев(стрТЧ.innerHTML,Найти(стрТЧ.innerHTML,""""));
                            стрТЧ.innerHTML=СтрЗаменить(стрТЧ.innerHTML,ЛевЧасть,"");
                            новСтр.Ссылка=Лев(стрТЧ.innerHTML,Найти(стрТЧ.innerHTML,"""")-1);
                            //парсим страницы со ссылками
                            СерверИсточник = "www.1c.ru";
                            Адрес = "/rus/partners/";
                            ИмяВходящегоФайла= КаталогВременныхФайлов()+"input.txt";
                            Если прокси Тогда
                                ПроксиСервер = Новый ИнтернетПрокси;
                                ПроксиСервер.Пользователь = Пользователь;
                                ПроксиСервер.Пароль = Пароль;
                                ПроксиСервер.Установить(Протокол,  АдресПрокси,  Порт);
                                // Укажем в HTTP соединении что у нас есть прокси 
                                НТТР = Новый HTTPСоединение(СерверИсточник,,,, ПроксиСервер);
                            иначе
                                НТТР = Новый HTTPСоединение(СерверИсточник,,,,);
                            КонецЕсли; 
                            НТТР.Получить(Адрес+новСтр.Ссылка, ИмяВходящегоФайла);
                            ТекстИзФайла = Новый ТекстовыйДокумент;
                            ТекстИзФайла.Прочитать(ИмяВходящегоФайла);
                            Тест = ТекстИзФайла.ПолучитьТекст();
       
                            Форма = ПолучитьФорму("ДопФорма2");
                            Форма.СтрокаТЗ=новСтр;
                            Форма.ЭлементыФормы.Сайт.УстановитьТекст(Тест);
                            Форма.ОткрытьМодально();
                        КонецЕсли;
                    КонецЦикла; 
                КонецЕсли; 
            КонецЕсли; 
        КонецЕсли; 
    КонецЦикла;
    Закрыть();
КонецПроцедуры

Процедура СайтДокументСформирован(Элемент)
    флЗагрузки=флЗагрузки+1;
    Если флЗагрузки=1 Тогда
        Если ЭлементыФормы.Сайт.Документ.body.all.length>1 Тогда
            ГрузимДанные();
        КонецЕсли;
    КонецЕсли; 
КонецПроцедуры

Процедура ПриОткрытии()
    флЗагрузки=0;
КонецПроцедуры

Код ДопФорма2 (переход по ссылке для получения показателей):

Перем СтрокаТЗ Экспорт;
Перем флЗагрузки;

Процедура ГрузимДанные()
    Для Каждого Стр из ЭлементыФормы.Сайт.Документ.body.all Цикл
        Если Стр.tagName = "TABLE" и Стр.classname = "content" Тогда
            фл=1;
            Если фл=1 Тогда
                Для каждого стр2 из Стр.all Цикл
                    СтрТекст="";
                    ЗначениеСтр="";
                    //Число стандартных внедрений, выполненных по технологии СМК:
                    Если Стр2.tagName = "TR" И Найти(Стр2.innerText,"Число стандартных внедрений, выполненных по технологии СМК:")>0 Тогда
                        //сообщить(Стр2.innerText);
                        СтрТекст=СтрЗаменить(Стр2.innerText,"Число стандартных внедрений, выполненных по технологии СМК:","");
                        ЗначениеСтр=Лев(СтрТекст,Найти(СтрТекст,"/")-1);
                        СтрокаТЗ.ЧислоСтандартныхВнедрений=?(СокрЛП(ЗначениеСтр)="",0,число(ЗначениеСтр));
                    КонецЕсли; 
                    //Число проектных внедрений, выполненных по технологии СМК:
                    Если Стр2.tagName = "TR" И Найти(Стр2.innerText,"Число проектных внедрений, выполненных по технологии СМК:")>0 Тогда
                        СтрТекст=СтрЗаменить(Стр2.innerText,"Число проектных внедрений, выполненных по технологии СМК:","");
                        ЗначениеСтр=Лев(СтрТекст,Найти(СтрТекст,"/")-1);
                        СтрокаТЗ.ЧислоПроектныхВнедрений=?(СокрЛП(ЗначениеСтр)="",0,число(ЗначениеСтр));
                    КонецЕсли; 
                    Если Стр2.tagName = "TR" И Найти(Стр2.innerText,"Количество отчетов о ходе внедрения УПП и отраслевых решений на основе УПП, вошедших в число 10% наиболее полезных по содержанию для фирмы «1С»: ")>0 Тогда
                        СтрТекст=СтрЗаменить(Стр2.innerText,"Количество отчетов о ходе внедрения УПП и отраслевых решений на основе УПП, вошедших в число 10% наиболее полезных по содержанию для фирмы «1С»:","");
                        ЗначениеСтр=СокрЛП(СтрТекст);//Лев(СтрТекст,Найти(СтрТекст,"/")-1);
                        СтрокаТЗ.КоличествоОтчетовОВнедрении=?(СокрЛП(ЗначениеСтр)="",0,число(ЗначениеСтр));
                    КонецЕсли;
          
                    //РАЗРАБОТКА 1C-СОВМЕСТНЫХ РЕШЕНИЙ НА БАЗЕ УПП
                    //Число разработанных отраслевых решений на базе УПП:
                    Если Стр2.tagName = "TR" И Найти(Стр2.innerText,"Число разработанных отраслевых решений на базе УПП:")>0 Тогда
                        СтрТекст=СтрЗаменить(Стр2.innerText,"Число разработанных отраслевых решений на базе УПП:","");
                        ЗначениеСтр=Лев(СтрТекст,Найти(СтрТекст,"/")-1);
                        СтрокаТЗ.ЧислоРазработанныхОтраслевыхРешенийУПП=?(СокрЛП(ЗначениеСтр)="",0,число(ЗначениеСтр));
                    КонецЕсли;
     
                    //"Число разработанных модулей, интегрирующихся в УПП и расширяющих возможности УПП (не включая модули, входящие в состав отраслевых решений на УПП): "
                    Если Стр2.tagName = "TR" И Найти(Стр2.innerText,"Число разработанных модулей, интегрирующихся в УПП и расширяющих возможности УПП (не включая модули, входящие в состав отраслевых решений на УПП)")>0 Тогда
                        СтрТекст=СтрЗаменить(Стр2.innerText,"Число разработанных модулей, интегрирующихся в УПП и расширяющих возможности УПП (не включая модули, входящие в состав отраслевых решений на УПП):","");
                        ЗначениеСтр=Лев(СтрТекст,Найти(СтрТекст,"/")-1);
                        СтрокаТЗ.ЧислоРазработанныхМодулейУПП=?(СокрЛП(ЗначениеСтр)="",0,число(ЗначениеСтр));
                    КонецЕсли;
                КонецЦикла;
            КонецЕсли; 
        КонецЕсли; 
    КонецЦикла;
 
    Закрыть();
КонецПроцедуры

Процедура ПолеHTMLДокумента1ДокументСформирован(Элемент)
    флЗагрузки= флЗагрузки+1;
    Если  флЗагрузки=1 Тогда
        Если ЭлементыФормы.Сайт.Документ.body.all.length>1 Тогда
            ГрузимДанные();
        Иначе
            Закрыть();
        КонецЕсли;
    КонецЕсли; 
КонецПроцедуры

Процедура ПриОткрытии()
    флЗагрузки=0;
КонецПроцедуры

Для получения названия города и некоторых регионов нужно перевести символы в 16-тиричную систему, в обработке это есть. Полученные даныне можно сохранить в регистр сведений и затем анализировать динамику, стоить графики.

Скачать файлы

Наименование Файл Версия Размер
Парсер сайта 1С 8.1 17
.epf 21,26Kb
01.11.12
17
.epf 21,26Kb Скачать
Парсер сайта 1С 8.2 16
.epf 22,12Kb
01.11.12
16
.epf 22,12Kb Скачать

См. также

Подписаться Добавить вознаграждение
Комментарии
1. Дмитрий Луканов (TheGrr) 02.11.12 15:34
Познавательно! Скоро мне это пригодится.

PS Разукрасьте код, пожалуйста. )
2. Анатолий Бычин (tolyan_ekb) 03.11.12 09:04
(1) TheGrr, спасибо за совет, обязательно раскрашу. Буду рад, если публикация пригодиться.
3. Юрий Н (graphbuh) 07.11.12 10:56
Прикольно! Помню мой экс-шеф во франчайзи проводил подобную работу. Было бы неплохо сделать мини конфигурацию, чтобы можно было увидеть динамику.
4. Анатолий Бычин (tolyan_ekb) 07.11.12 11:13
(3) graphbuh, на самом деле достаточно будет добавить регистр сведений, где хранить результаты. Тогда можно будет следить за динамикой.
Для написания сообщения необходимо авторизоваться
Прикрепить файл
Дополнительные параметры ответа