for flooders
:: Главная :: Решения :: Статьи :: Сайт М. Дроздова :: Файловый архив :: Книга по VFP 9 :: Русский Help Online :: OFF-LINE Форум
   Лисоводы   всех   стран,  объединяйтесь !!!  

Список Форумов  :: Обсуждаем проекты
  

Разбор файлов - как вытащить нужную информацию.
maple4

Сообщений: 210
Откуда: Москва
Дата: 05.02.10 10:02:29
В общем, стоит (скорее, стояла...) такая задача:
Из текстового файла (сформированного по какому-то правилу) нужно вытащить НУЖНУЮ информации.
Если известны начальная и конечная позиции блока информации, тогда все очень просто.
Ну а если эти позиции меняются? К чему тогда можно "привязаться"?
Если текстовый файл - страница html, задача значительно упрощается. Якорями (местами "привязки") могут являться характерные комбинации тэгов, особенно если они используют классы или имена.

Как пример - главные новости на mail.ru содержатся между якорями <div class="news"> и </div>

А вот на lenta.ru информация находится между
<TABLE class=peredovica cellSpacing=0 cellPadding=0 width=100% border=0>
и
</TABLE>
Но тут, что бы правильно все вытащить, нужно учитывать парность <TABLE... и </TABLE>, ведь если в содержимом между якорями будет добавлена хотя бы еще одна таблица, результат будет неверным.

Первый вариант - использовать объект IE, и вытаскивать то, что надо, последовательно перебирая тэг за тэгом.
Вариант второй - IE не использовать.

Если присмотреться, блок на lenta.ru заканчивается </TABLE> и далее идет <DIV class=hrg><SPACER type=block></SPACER></DIV>
Так вот, что-бы найти нужный </TABLE> можно найти сначала <DIV class=hrg><SPACER... а потом, уже первый от данной комбинации слева - тот самый тэг </TABLE>.

А вот если таких новостных блоков несколько? Как быть в данном случае, если требуется вытащить их все?

Предлагаю такую схему:
1. Создается некий объект (HC).
2. Ему присваиваются начальный и конечный якоря.
3. Объект по якорям находит начальную и конечную позиции в файле.
4. Если они найдены - вырезается из файла нужный кусок информации, и, далее к шагу 3, но уже к поиску следующих по счету якорей. Если якоря не найдены - выход.



Один нюанс, который касается lenta.ru
Последний блок не заканчивается <DIV class=hrg><SPACER...
Как тогда понять ГДЕ конец блока?
Для этого можно привязаться к другой последовательности символов - <TABLE class=podval> и уже от нее найти первую слева комбинацию символов <br>, которая и является якорем конца блока.

...
Далее, вся информация используется в своих интересах (от вывода на начальную страницу браузера blank ... до незаконного использования в контенте сайта ).

Что бы не быть голословным - пример использования ниже.
А еще чуть ниже - пример альтернативной работы с объектом с помощью скрипта.

И класс в архиве.
-------------------------------------------------------------------------------------------
SET PROCEDURE TO hc.prg ADDITIVE  
    
  local tst,tkt  
    
    
  && перебор новостей, и формирование своей таблицы из них (блоки располагаются в отдельной колонке) + самый первый блок внизу таблицы  
  tst=CREATEOBJECT("hc")  
  tst.hc_text([<table border=1><tr>]) && вставка таблицы и строки  
  IF tst.hc_loadresource("http://www.mail.ru"+"?id="+SYS(2015)) && загрузка с ресурса  
  	WAIT WINDOW "Load ok (1)" TIMEOUT 1  
  ELSE  
  	WAIT WINDOW "Load ERROR (1)" TIMEOUT 1  
  	RETURN  
  ENDIF  
    
    
    
  DO WHILE tst.hc_start_open() ; && начальный якорь  
  	AND tst.hc_tag([<div class="news">],"IN=TRUE") ; && определение комбинации <div class="news"> для якоря  
  	AND tst.hc_start_close() && конец описания якоря и определение позиции "откуда" (START)  
  && цикл работает только если последовательность <div class="news"> найдена  
    
  	tst.hc_end_open()&& конечный якорь  
  	tst.hc_tag([</div>],"IN=TRUE") && определение комбинации </div> для якоря  
  	tst.hc_end_close() &&  конец описания якоря и определение позиции "досюда" (END)  
  	tst.hc_text([<td align=left valign=top><font size=-1>]) && вставка своего текста в результат - колонки и форматирования текста  
  	tst.hc_insert() && вставка в результат вырезанного от START до END текста  
  	tst.hc_text([</font></td>]) && вставка своего текста - закрытия форматирования текста и колонки  
  ENDDO  
  tst.hc_text([</tr></table>]) && вставка своего текста - закрытие строки и таблицы  
    
  tst.hc_pointer("SET=0") && перемещение указателя на начало для поиска ТОЛЬКО первого блока <div class="news">  
  tst.hc_text(CHR(13)+[<hr>]+CHR(13)+CHR(13)+CHR(13)+CHR(13)) && вставка своего текста  
  tst.hc_start_open()  
  tst.hc_tag([<div class="news">],"IN=FALSE") && IN=FALSE - текст <div class="news"> в результат не войдет  
  tst.hc_start_close()  
  tst.hc_end_open()  
  tst.hc_tag([</div>],"IN=FALSE") && IN=FALSE - сам якорь </div> в результат не войдет  
  tst.hc_end_close()  
  tst.hc_text([<font size=-1>])  
  tst.hc_insert()  
  tst.hc_text([</font>])  
    
    
    
    
    
  && перебор блоков, когда конечный якорь может быть различным и составным  
    
  tkt=CREATEOBJECT("hc")  
  && создание второго объекта  
  IF tkt.hc_loadresource("http://www.lenta.ru"+"?id="+SYS(2015)) && с ресурса  
  	WAIT WINDOW "Load ok (2)" TIMEOUT 1  
  ELSE  
  	WAIT WINDOW "Load ERROR (2)" TIMEOUT 1  
  	RETURN   
  ENDIF  
    
  DO WHILE tkt.hc_start_open();  
  		AND tkt.hc_tag([<TABLE class=peredovica cellSpacing=0 cellPadding=0 width=100% border=0>],"IN=TRUE");  
  		AND tkt.hc_start_close()  
  && поиск комбинации <TABLE class=peredovica cellSpacing=0 cellPadding=0 width=100% border=0> для начального якоря  
    
    
  	IF NOT (tkt.hc_end_open() ;  
  			AND tkt.hc_tag([<DIV class=hrg><SPACER type=block></SPACER></DIV>],"IN=FALSE") ; && сам якорь - <DIV class=hrg>... - в результат не входит, IN=FALSE  
  			AND tkt.hc_tag([</TABLE>],"IN=TRUE POSITION=-1") ; && найти первую слева (POSITION=-1) комбинацию </TABLE> от <DIV class=....; якорь в результат ВХОДИТ, IN=TRUE  
  			AND tkt.hc_end_close())  
  && поиск комбинации </TABLE><DIV class=hrg><SPACER type=block></SPACER></DIV> для конечного якоря  
  && если нет такой комбинации (или если это последний блок), то  
  		IF NOT (tkt.hc_end_open() ;  
  				AND tkt.hc_tag([<TABLE class=podval>],"IN=FALSE") ; && якорь в результат не входит, IN=FALSE  
  				AND tkt.hc_tag([<br>],"IN=FALSE POSITION=-1") ; && найти первую слева (POSITION=-1) комбинацию <br> от <TABLE class=podval>;  якорь в результат не входит, IN=FALSE  
  				AND tkt.hc_end_close())  
  && поиск комбинации <br><TABLE class=podval> для конечного якоря  
  && если такой комбинации не найдено - выход из цикла  
  			EXIT  
  		ENDIF  
  	ENDIF  
  	tkt.hc_insert()  
  ENDDO  
    
  && замена всех относительных ссылок на абсолютные (самый простой способ, но не самый правильный)  
  tkt.hcv_vihod=STRTRAN(tkt.hcv_vihod,"href=/","href=http://www.lenta.ru/",-1,-1,1)  
  tkt.hcv_vihod=STRTRAN(tkt.hcv_vihod,[href="/],[href="http://www.lenta.ru/],-1,-1,1)  
    
  STRTOFILE(tst.hcv_vihod+"<br><br><hr>"+tkt.hcv_vihod,"vihod.html") && формирование конечного файла  
    
    
  RETURN
-------------------------------------------------------------------------------------------
Функции объекта:
hc_loadresource (resource) - загрузка текста из файла ресурса . Если ресурс начинается с http:// - берется с Интернет, иначе - локально. Текст загружается в hcv_vhod

hc_start_open() - открытие описание начального якоря
hc_start_close() - закрытие описание начального якоря и поиск его в содержимом (при неудаче возвращает .f.), запись позиции в hcv_nacalo
hc_end_open() - открытие описания конечного якоря
hc_end_close() - закрытие описания конечного якоря, поиск его в содержимом (при неудаче возвращает .f.), запись позиции в hcv_konec
hc_text(TEXT) - вставка в результат (hcv_vihod) произвольного текста TEXT
hc_insert(parameters) - запись в hcv_part содержимого между hcv_nacalo и hcv_konec, и, в зависимости от параметра, запись в результат hcv_vihod
hc_pointer(parameters) - перемещение указателя (hcv_ukaz) в нужную позицию
hc_tag(TEXT,parameters) - описание якоря. TEXT - символьная комбинация


Свойства объекта:
hcv_ukaz - позиция указателя. "Перемещается" при поиске якорей.
hcv_nacalo - позиция начального якоря
hcv_konec - позиция конечного якоря
hcv_vihod - результат
hcv_part - последний найденный блок
hcv_vhod - текст, обрабатываемый объектом
hcv_resource - с какого ресурса получен текст


Для некоторых методов можно задавать параметры:
hc_tag
POSITION=-NNNNN|NNNN : где искать комбинацию символов, слева от указателя (при -) или справа, и какой по счету - NNNN. Если не указан параметр, действие аналогично как при POSITION=1
IN=FALSE|TRUE : не входит или входит якорь в результат (касается только последнего, если он составной)
CASE=FALSE|TRUE : поиск не зависит или зависит от регистра

hc_insert
NOINSERT=FALSE|TRUE : НЕ вставлять (TRUE) или вставлять вырезанный блок текста в результат (в hcv_part - находится вырезанный кусок, его можно обработать и решить, что с ним делать дальше)

hc_pointer
SET=NNNN : перемещение указателя на нужную позицию, например при SET=0 казатель переместится на начало обрабатываемого текста.


-------------------------------------------------------------------------------------------


А вот пример того же самого, но сделанного по другому (типа, "смотрите, как еще можно ") для сайта mail.ru
Предварительно пишется некий файл разбора (не на FoxPro!), называется mailru.txt (кладется в каталог запуска, хотя можно задать и ресурс в Интернет-е, начиная с http:// ).

*************************************************************  
 **** mailru.txt - файл разбора  
  [[[[TEXT]]]]<table border=1><tr>[[[[/TEXT]]]]    -   код таблицы со строкой  
    
  [[[[ADDRESS ADDRESS=T1]]]]    -    адрес (согласен, не структурное программирование...)  
  				задание начального якоря, если якорь не будет найден - переход на адрес T2  
  	[[[[START ELSE=T2]]]]  
  		[[[[TAG IN=TRUE]]]]<div class="news">[[[[/TAG]]]]  
  	[[[[/START]]]]  
    
  				задание конечного якоря  
  	[[[[END]]]]  
  		[[[[TAG IN=TRUE]]]]</div>[[[[/TAG]]]]  
  	[[[[/END]]]]  
  				вставка колонки  
  	[[[[TEXT]]]]<td align=left valign=top><font size=-1>[[[[/TEXT]]]]  
  				... и данных  
  		[[[[INSERT]]]]  
  				вставка закрытия колонки  
  	[[[[TEXT]]]]</font></td>[[[[/TEXT]]]]  
    
  		переход на адрес T1  
  	[[[[GOTO GOTO=T1]]]]  
    
  [[[[ADDRESS ADDRESS=T2]]]]	- адрес T2  
    
  [[[[TEXT]]]]</tr></table>[[[[/TEXT]]]]   - вставка кода закрытия таблицы  
    
  [[[[POINTER SET=0]]]]		-   переместить указатель на начало  
    
  	вставка текста  
  [[[[TEXT]]]]  
  <hr>  
    
    
    
  [[[[/TEXT]]]]  
  			далее - поиск и вставка только САМОГО первого блока новостей  
  	[[[[START]]]]  
  		[[[[TAG IN=FALSE]]]]<div class="news">[[[[/TAG]]]]  
  	[[[[/START]]]]  
    
  	[[[[END]]]]  
  		[[[[TAG IN=FALSE]]]]</div>[[[[/TAG]]]]  
  	[[[[/END]]]]  
    
  [[[[TEXT]]]]<font size=-1>[[[[/TEXT]]]]  
  [[[[INSERT]]]]  
  [[[[TEXT]]]]</font>[[[[/TEXT]]]]  
    
 *****  
 *************************************************************  



Далее, уже на FoxPro, создается объект, который и делает всю работу сам:

*************************************************************  
  SET PROCEDURE TO hc.prg ADDITIVE  
  local tst  
  tst=CREATEOBJECT("hc")  
  tst.run_script("http://www.mail.ru"+"?id="+SYS(2015),"mailru.txt")  
  STRTOFILE(tst.HCV_VIHOD,"vihod.html")  
 *************************************************************


В общем, два варианта работы с объектом:
1. На чистом FoxPro - в этом случае у Вас полный контроль над объектом
2. Варант со скриптом, который позволяет сделать многое, не особо вникая в Fox.


самый новый архив с объектом и примерами работы находится здесь (прямая ссылка на загрузку, 8кб):

www.maple4.ru

-------------------------------------------------------------------------------------------
P.S.
Может, кто делает по другому? Например, с помощью регулярных выражений.

P.P.S.
Про RSS знаю. И "разбирать" похожим образом можно не только html-файлы.

P.P.P.S.
Все пока на этапе тестирования. Кроме того, хотелось бы для себя понять - "а зачем?"
Есть возможность развиваться дальше.
Например, считывание блока информации размером сколько-то символов, если структура данных статична.
Ratings: 0 negative/0 positive

Re: Разбор файлов - как вытащить нужную информацию.
JS
Автор

Сообщений: 12158
Откуда: Эстония
Дата: 05.02.10 13:27:06
maple4
А вот на lenta.ru информация находится между
<TABLE class=peredovica cellSpacing=0 cellPadding=0 width=100% border=0>
и
</TABLE>

Как все было бы проще, если бы создатели сайтов и их страниц использовали
атрибут id. В таком случае, большинство задач бы по разбору информации
упрощалась бы многократно, так как есть замечательный метод getElementById.


------------------
Knowledge is better than ignorance!
Website: juri.foxhelp.eu
Ratings: 0 negative/0 positive



Извините, только зарегистрированные пользователи могут оставлять сообщения в этом форуме.

On-line: 6 Божья_коровка  (Гостей: 5)

© 2000-2021 Fox Club 
Яндекс.Метрика