Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 2012.05.27;
Скачать: [xml.tar.bz2];

Вниз

Удаление тегов из ХТМЛ-страницы   Найти похожие ветки 

 
Pcrepair ©   (2012-01-18 20:47) [0]

Добрый день
есть код:
var
 Form1: TForm1;
 HTML : ustring;
//////////////////////////////////
procedure TForm1.Button1Click(Sender: TObject);
var
URL : string;
begin
    URL := Edit1.Text;
    Chromium1.Browser.MainFrame.LoadUrl(URL);
end;
procedure TForm1.Chromium1LoadEnd(Sender: TObject; const browser: ICefBrowser;
 const frame: ICefFrame; httpStatusCode: Integer; out Result: Boolean);
begin
 if (httpStatusCode <> 200) then Exit;
 Memo1.Clear;
 Chromium1.Browser.MainFrame.VisitDomProc(
 procedure(const Dom: ICefDomDocument)
 begin
   HTML := Dom.Document.AsMarkup;
 end );
 Memo1.Clear;
 Memo1.Lines.Add(HTML);
end;
end.


Код закачивает страницу с заданным УРЛ, производит обработку скриптов и размещает код страницы в ПЕРЕМ типа ustring
Все работает.
Далее необходимо переработать код в ПЕРЕМ ХТМЛ. В частности нужно удалить все теги типа <script..мусор...>..мусор...</script>, <style type=..мусор>...мусор...</style> и прочие такие же, типа ( ), не содержащие информации. в общем нужно радикально зачистить страницу, оставив только теги ссылок <a href= " ">...........</a> и теги таблиц <TR></TR>, чтоб ни рекламы. ни флеша, ни картинок
ВОПРОС:
каким способом это лучше сделать? может есть каки то проверенные способы уже
может есть какие то модули типа TParser? или типа того
Всем ответившим по делу - спасибо


 
Dennis I. Komarov ©   (2012-01-18 21:55) [1]

Pos[Ex](


 
KilkennyCat ©   (2012-01-19 03:16) [2]

Pos вряд ли эффективно...

тут проще пробежаться побайтово, накапливая и сравнивая. то есть, бежим, читаем байт, тут же пишем в новый текст. как только встречаем < начинаем в отдельную переменую копить, до ближайшего пробела, в новый текст не пишем. анализируем полученное, если ненужный тэг - бежим дальше, проверяем /, после него проверяем > и алгоритм улетает в начало. если нужный тэг - переменную добавляем в новый текст, алгоритм улетает в начало. это в общих чертах, конечно, но я такое когда-то делал, примитивный парсер, довольно-таки просто и очень быстро. проверка / и >  - тут надо повнимательней. ее не надо проверять, если  тэг не встречен или нужен.


 
int64 ©   (2012-01-19 06:33) [3]

Видел библиотеку-конвертор из HTML в XHTML.
Задача сводится к работе с XML. Немного ресурсоемко, зато архитектурно прозрачно.

зы. Есть ощущение, что сабж не раз решался через регулярные выражения.

ззы. Откуда уверенность, что в <script..мусор...>..мусор...</script>, не будет нужного отображаемого контента?


 
DVM ©   (2012-01-19 10:13) [4]

Вот посмотри этот когда, я когда то писал машину состояний для разбора HTML. Не идеальна она конечно, но с моей задачей справлялась (замена всех URL на нужные мне). Класс TURLTransformer в данном случае тебе не нужен, как и функция TagHasUrl.


procedure ReplaceURLs(var S: string; ATransformer: TURLTransformer);
type
 TState = (stStart, stDocType, stTag, stParam, stParamValue, stText, stComment);
var
 State: TState;
 i: integer;
 TagName, ParamName, ParamValue: string;
 Quotes, DQuotes: boolean;
 S2: string;

 procedure ProcessTag;
 begin
   //
 end;

 procedure ProcessParam;
 begin
   //
 end;

 procedure ProcessParamValue;
 begin
   if TagHasUrl(TagName, ParamName) then
     ATransformer.TransformURL(ParamValue);
   S2 := S2 + "="" + ParamValue + """;
 end;

begin
 Quotes := False;
 DQuotes := False;
 S2 := "";
 State := stStart;
 for i := 1 to Length(S) do
   begin

     case State of
       stStart:
         case S[i] of
           "<":
             begin
               State := stTag;
               TagName := "";
             end;
         end;
       stDocType:
         case S[i] of
           ">": State := stStart;
         end;
       stTag:
         case S[i] of
           "!":
             if TagName = "" then
               begin
                 if S[I+1] = "-" then
                   State := stComment
                 else
                   State := stDocType;
               end;
           " ", #9, #13, #10:
             if TagName <> "" then
             begin
               ProcessTag;
               State := stParam;
               ParamName := "";
             end;
           ">":
             begin
               ProcessTag;
               State := stStart;
             end;
           "/":
             if S[i + 1] = ">" then
             begin
               ProcessTag;
               State := stStart;
             end
             else
               TagName := TagName + S[i];

         else
           TagName := TagName + S[i];
         end;
       stParam:

         case S[i] of
           " ", #9, #13, #10:
             ;
           "=":
             if ParamName <> "" then
             begin
               State := stParamValue;
               ProcessParam;
               ParamValue := "";
               Quotes := false;
               DQuotes := false;
             end;

           ">", "/":
             begin
               if ParamName <> "" then
                 ProcessParam;
               State := stStart;
             end;
         else
           ParamName := ParamName + S[i];
         end;

       stParamValue:
         case S[i] of
           """":
             if not DQuotes then
               Quotes := not Quotes
             else
               ParamValue := ParamValue + S[i];
           """:
             if not Quotes then
               DQuotes := not DQuotes
             else
               ParamValue := ParamValue + S[i];
           " ", #9, #13, #10:
             if Quotes or DQuotes then
               ParamValue := ParamValue + S[i]
             else
             begin
               ProcessParamValue;
               State := stParam;
               ParamName := "";
             end;
           "/":

             if S[i + 1] = ">" then
             begin
               State := stStart;
               ProcessParamValue;
             end
             else
               ParamValue := ParamValue + S[i];

           ">":
             begin
               State := stStart;
               ProcessParamValue;
             end
         else
           ParamValue := ParamValue + S[i];
         end;
       stText:
         ;
       stComment:
         case S[i] of
           "-":
             if S[i + 1] = ">" then
               State := stStart;
         end;
     end;

     if State <> stParamValue then
       S2 := S2 + S[i];

   end;
 S := S2;
end;



 
DVM ©   (2012-01-19 10:16) [5]

По аналогии [4] несложно переделать под замену/удаление/извлечение любых тегов и их параметров


 
Pcrepair ©   (2012-01-19 15:10) [6]


>  Откуда уверенность, что в <script..мусор...>..мусор...</script>,
>  не будет нужного отображаемого контента?

уверенность есть, поскольку результаты работы скриптов уже есть в коде, загруженном в ПЕРЕМ. проверено.

>
> Есть ощущение, что сабж не раз решался через регулярные
> выражения.


конечно есть что такое уже, осталось найти и посмотреть

DVM, спасибо, будем пробовать


 
Dimka Maslov ©   (2012-01-19 15:15) [7]


> ПЕРЕМ


п е р е м е н н а я
Запиши на большими буквами на бумаге и повесь на стену.


 
Eraser ©   (2012-01-19 16:27) [8]

> [0] Pcrepair ©   (18.01.12 20:47)

это тривиальная задача для любого php программера, решаемая с помощью регулярных выражений. Прикрути regexp.


 
Pcrepair ©   (2012-01-19 21:32) [9]

есть теория что использование pos/regexp может привести к непредсказуемым результатам, при обработке самых разных страниц (это будет поисковая программа)


 
Eraser ©   (2012-01-19 22:25) [10]

> [9] Pcrepair ©   (19.01.12 21:32)

кто автор теории? )


 
Dimka Maslov ©   (2012-01-19 22:38) [11]

есть теория, что использование таких  вот программистов может привести к непредсказуемым результатам


 
Dimka Maslov ©   (2012-01-19 22:48) [12]


> Eraser ©   (19.01.12 22:25) [10]


Мы уже узнали, что нет переменных есть только ПЕРЕМ, что читать MSDN и RFC бесполезно, что буфер обмена работает только на виртуальной машине, что нельзя использовать pos и regexp (как будто есть что-то другое). Но зато это будет поисковая программа! Круче чем гугл! Супер-пупер-мега-крутая. Вот только флудеры и теоретики мешают гению бездумно тырить код в этих ваших интернетах, а кроме того нагло отказываются писать за автора код... Тем более, что и в хромиуме наверняка есть свойства innerText и аnchors (или их аналоги), которые решают поставленную задачу мгновенно.


 
DVM ©   (2012-01-19 22:54) [13]

Имхо не тривиальная задача это и не для регулярных выражений. Только для выборки URL придется написать нехилое выражение. Например, надо не тупо выделять то, что начинается с http, а находить урлы, записанные самым экзотическим способом. Есть прорва тегов, которые могут содержать URL. Не надо реагировать на URL встречающиеся в тексте как текст и на те что внутри некоторых особых тегов.
Например, теги в которых может быть URL:


function TagHasUrl(const ATagName, ATagParam: string): Boolean;
var
 Tag, Param: string;
begin
 Tag := LowerCase(ATagName);
 Param := LowerCase(ATagParam);
 Result := ((Tag = "a") and (Param = "href")) or
   ((Tag = "applet") and (Param = "codebase")) or
   ((Tag = "applet") and (Param = "code")) or
   ((Tag = "applet") and (Param = "archive")) or
   ((Tag = "area") and (Param = "href")) or
   ((Tag = "bgsound") and (Param = "src")) or
   ((Tag = "blockquote") and (Param = "cite")) or
   ((Tag = "body") and (Param = "background")) or
   ((Tag = "del") and (Param = "cite")) or
   ((Tag = "embed") and (Param = "src")) or
   ((Tag = "frame") and (Param = "longdesc")) or
   ((Tag = "frame") and (Param = "src")) or
   ((Tag = "head") and (Param = "profile")) or
   ((Tag = "iframe") and (Param = "longdesc")) or
   ((Tag = "iframe") and (Param = "src")) or
   ((Tag = "ilayer") and (Param = "background")) or
   ((Tag = "ilayer") and (Param = "src")) or
   ((Tag = "img") and (Param = "longdesc")) or
   ((Tag = "img") and (Param = "src")) or
   ((Tag = "img") and (Param = "usemap")) or
   ((Tag = "img") and (Param = "dynsrc")) or
   ((Tag = "img") and (Param = "lowsrc")) or
   ((Tag = "input") and (Param = "src")) or
   ((Tag = "input") and (Param = "usemap")) or
   ((Tag = "input") and (Param = "dynsrc")) or
   ((Tag = "input") and (Param = "lowsrc")) or
   ((Tag = "ins") and (Param = "cite")) or
   ((Tag = "layer") and (Param = "background")) or
   ((Tag = "layer") and (Param = "src")) or
   ((Tag = "link") and (Param = "href")) or
   ((Tag = "link") and (Param = "href")) or
   ((Tag = "object") and (Param = "codebase")) or
   ((Tag = "object") and (Param = "classid")) or
   ((Tag = "object") and (Param = "data")) or
   ((Tag = "object") and (Param = "archive")) or
   ((Tag = "object") and (Param = "usemap")) or
   ((Tag = "q") and (Param = "cite")) or
   ((Tag = "script") and (Param = "src")) or
   ((Tag = "table") and (Param = "background")) or
   ((Tag = "td") and (Param = "background")) or
   ((Tag = "th") and (Param = "background")) or
   ((Tag = "xml") and (Param = "src")) or
   ((Tag = "base") and (Param = "href"));
end;



Это к моей задаче.

Задача автора вопроса не менее сложная, а то и более.
Мне кажется лучше всего будет произвести построение DOM модели чем то вот таким http://htmlp.sourceforge.net/ , фильтрация не нужных параметров и тегов и обратная сборка документа. Там есть пример подобного. Но с конечным автоматом быстрее конечно, но более трудоемко.


 
DVM ©   (2012-01-19 23:02) [14]

А на реальных страницах есть еще такая штука как не совсем корректный html, который тем не менее глотается браузерами.И это далеко не редкость. Почти любой крупный интернет ресурс изобилует ошибками в html. Если парсить по каким то заранее заданным правилам, то парсер может сработать неправильно. Ориентироваться надо по конкретной ситуации на странице иногда на ходу исправляя неверный код.


 
DVM ©   (2012-01-19 23:06) [15]

А для поисковика есть еще одна непростая задачка - комбинация базового и относительного урлов на странице для перехода паука. Это очень непростая задача. На сайте консорциума WWW есть специальные тесты для функций выполняющих комбинацию, практически ни один браузер не проходит их все.

Вот большинство из них:


 TestCombineUrl("http://a/b/c/d;p?q", "g", "http://a/b/c/g");
 TestCombineUrl("http://a/b/c/d;p?q", "./g", "http://a/b/c/g");
 TestCombineUrl("http://a/b/c/d;p?q", "g/", "http://a/b/c/g/");
 TestCombineUrl("http://a/b/c/d;p?q", "/g", "http://a/g");
 TestCombineUrl("http://a/b/c/d;p?q", "//g", "http://g");
 TestCombineUrl("http://a/b/c/d;p?q", "?y", "http://a/b/c/d;p?y");
 TestCombineUrl("http://a/b/c/d;p?q", "g?y", "http://a/b/c/g?y");
 TestCombineUrl("http://a/b/c/d;p?q", "#s", "http://a/b/c/d;p?q#s");
 TestCombineUrl("http://a/b/c/d;p?q", "g#s", "http://a/b/c/g#s");
 TestCombineUrl("http://a/b/c/d;p?q", "g?y#s", "http://a/b/c/g?y#s");
 TestCombineUrl("http://a/b/c/d;p?q", ";x", "http://a/b/c/;x");
 TestCombineUrl("http://a/b/c/d;p?q", "g;x", "http://a/b/c/g;x");
 TestCombineUrl("http://a/b/c/d;p?q", "g;x?y#s", "http://a/b/c/g;x?y#s");
 TestCombineUrl("http://a/b/c/d;p?q", ".", "http://a/b/c/");
 TestCombineUrl("http://a/b/c/d;p?q", "./", "http://a/b/c/");
 TestCombineUrl("http://a/b/c/d;p?q", "..", "http://a/b/");
 TestCombineUrl("http://a/b/c/d;p?q", "../", "http://a/b/");
 TestCombineUrl("http://a/b/c/d;p?q", "../g", "http://a/b/g");
 TestCombineUrl("http://a/b/c/d;p?q", "../..", "http://a/");
 TestCombineUrl("http://a/b/c/d;p?q", "../../", "http://a/");
 TestCombineUrl("http://a/b/c/d;p?q", "../../g", "http://a/g");
 TestCombineUrl("http://a/b/c/d;p?q", "../../../g", "http://a/g");
 TestCombineUrl("http://a/b/c/d;p?q", "../../../../g", "http://a/g");
 TestCombineUrl("http://a/b/c/d;p?q", "/./g", "http://a/g");
 TestCombineUrl("http://a/b/c/d;p?q", "/../g", "http://a/g");
 TestCombineUrl("http://a/b/c/d;p?q", "g.", "http://a/b/c/g.");
 TestCombineUrl("http://a/b/c/d;p?q", ".g", "http://a/b/c/.g");
 TestCombineUrl("http://a/b/c/d;p?q", "g..", "http://a/b/c/g..");
 TestCombineUrl("http://a/b/c/d;p?q", "..g", "http://a/b/c/..g");
 TestCombineUrl("http://a/b/c/d;p?q", "./../g", "http://a/b/g");
 TestCombineUrl("http://a/b/c/d;p?q", "./g/.", "http://a/b/c/g/");
 TestCombineUrl("http://a/b/c/d;p?q", "g/./h", "http://a/b/c/g/h");
 TestCombineUrl("http://a/b/c/d;p?q", "g/../h", "http://a/b/c/h");
 TestCombineUrl("http://a/b/c/d;p?q", "g;x=1/./y", "http://a/b/c/g;x=1/y");
 TestCombineUrl("http://a/b/c/d;p?q", "g;x=1/../y", "http://a/b/c/y");
 TestCombineUrl("http://a/b/c/d;p?q", "g?y/./x", "http://a/b/c/g?y/./x");
 TestCombineUrl("http://a/b/c/d;p?q", "g?y/../x", "http://a/b/c/g?y/../x");
 TestCombineUrl("http://a/b/c/d;p?q", "g#s/./x", "http://a/b/c/g#s/./x");
 TestCombineUrl("http://a/b/c/d;p?q", "g#s/../x", "http://a/b/c/g#s/../x");
 TestCombineUrl("http://a/b/c/d;p?q", "./g:h", "http://a/b/c/g:h");
 TestCombineUrl("http://a/b/c/d;p?q", "http://a/b/c/g", "http://a/b/c/g");

 TestCombineUrl("http://a", "/b/c/g", "http://a/b/c/g");
 TestCombineUrl("a", "../b/c/g", "http://a/b/c/g");
 TestCombineUrl("a", "./b/c/g", "http://a/b/c/g");
 TestCombineUrl("a", "b/c/g", "http://a/b/c/g");
 TestCombineUrl("", "a/b/c/g", "a/b/c/g") ;
 TestCombineUrl("http://a/", "", "http://a/");
 TestCombineUrl("http://a", "", "http://a/");
 TestCombineUrl("", "", "");


 
Pcrepair ©   (2012-01-20 16:07) [16]

DVM, интересная информация, буду думать
с другой стороны речь идет об удалении ненужного.
например:
если написать циклический код, просматривающий все символы в ПЕРЕМ (код хтмл-страницы) и удаляющий конструкции типа то что между тегами не удаляется, это нужно, удаляются сами теги, как не несущие информации или  <script..мусор...> вот тут все удаляется, ЖАБА код уже не нужен</script>
вроде проблем быть не должно? при обработке самых разных страниц. какой вариант предпочтительнее (pos или regexp) по критериям:
1. возможной глючности
2. скорости обработки (средняя страница 200 кб, ну 10 000 символов?)
3. сложности написания кода (regexp надо устанавливать в РАД, а pos это ведь "Работы со строками"?)


 
Pcrepair ©   (2012-01-20 16:09) [17]

глючит сервис
(б)
то что между тегами не удаляется, это нужно, удаляются сами теги, как не несущие информации(/б) - вот так правильно, имелся ввиду тег Б


 
нонамэ   (2012-01-21 00:21) [18]


> роде проблем быть не должно?

нет не должно, делай


 
KilkennyCat ©   (2012-01-21 01:35) [19]

Как народ любит регулярные выражения... я иногда их такие монструозные встречаю, что мне хочется или самому повеситься, или любителя того повесить.


> 3. сложности написания кода (regexp надо устанавливать в
> РАД, а pos это ведь "Работы со строками"?)

не нужен тут пос. долго будет, а простоты реализации не даст. DVM [4] - идеальное решение для данной задачи. и готовое почти.


 
Eraser ©   (2012-01-21 19:29) [20]

> [13] DVM ©   (19.01.12 22:54)

задача весьма тривиальна для preg_replace. года 4 назад я бы не задумываясь написал да выложил пример, но сейчас увы, у рег. выражений есть такое неприятное свойство, если не пользуешься ими - напрочь забываются )
автору рекомундую глянуть
http://php.net/manual/en/function.preg-replace.php и погуглить по запросу "preg_replace remove html tags"


 
Eraser ©   (2012-01-21 19:37) [21]

> [13] DVM ©   (19.01.12 22:54)

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

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


 
DVM ©   (2012-01-21 21:36) [22]


> Eraser ©   (21.01.12 19:37) [21]

Облажаются регулярные выражения, споткнувшись о первую незакрытую кавычку на реальных страницах, готов спорить. Точнее сами по себе регулярные выражения не виноваты, но человек составляющий это выражение непременно что-то не учтет ибо нереально (хотя теоретически наверное возможно).


 
DVM ©   (2012-01-21 22:25) [23]

По сути регулярное выражение это ни что иное как общее описание работы конечного автомата аналогичного приведенному мной. При компиляции регулярного выражения движком как раз примерно такой код и будет построен.

Но платой за универсальность является меньшая их наглядность начиная с некоторого момента. Мне попадались регулярные выражения аж на 100 строк(!) Таким выражением например будет выражение выделяющее 99.9% всех валидных emal адресов в тексте (кто думает что в таком выражение от силы символов 50, тот сильно ошибается). Понять как работает такое выражение непросто даже писавшему его через некоторое время. Тем более модифицировать.

Другим моментом является скорость. Конечно все сильно зависит от конкретной реализации движка для работы с регулярными выражениями, но быстрее чем один проход по строке они точно быть не могут. Иногда это критично.


 
Eraser ©   (2012-01-22 03:08) [24]

> [22] DVM ©   (21.01.12 21:36)

насчет ковычек - одна из самых распространенных проблем, главное разработать правило, как работать со сбойными ковычками. соглашусь, что 100% вариантов предусмотреть не получится, но получится куда лучше и на порядки проще, чем писать конечный автомат вручную.
я разрабатывал типограф для одной известной cms в свое время, да, есть ряд сложностей, но все решаемо. при нынешних мощностях процессоров просчет даже сложнейших рег. выражений точно не узкое место.


 
Eraser ©   (2012-01-22 03:13) [25]

я вообще к чему веду. для задачи автора в интернетах наверняка можно нарыть ряд типовых и качественных решений написанных для preg_replace и работающих с удовлетворительным качеством. все можно найти адаптировать за пару-тройку часов и заниматься проектом дальше. для того, чтобы написать такое вручную, может потребоваться куда больше времени и в самый не подходящий момент могут (даже наверняка) начнут лезть баги.


 
megavoid ©   (2012-01-22 10:29) [26]

[0] Можно так, убираем все тэги, при этом то, что за неправильной кавычкой отбрасываем, предварительно помечаем a href, потом возвращаем его на место
function RemoveTags(const s: string): string;
var
 i: Integer;
 InTag: Boolean;
begin
 Result := "";
 InTag := False;
 for i := 1 to Length(s) do begin
   if s[i] = "<" then inTag := True
   else if s[i] = ">" then inTag := False
   else if not InTag then Result := Result + s[i];
 end;
end;

S := "код хтмл";
S := AnsiReplaceStr(S, "<a href=", "$$$$$");
S := AnsiReplaceStr(S, "</a>", "#####");
S := ReplaceTags;
S := AnsiReplaceStr(S, "$$$$$", "<a href=");
S := AnsiReplaceStr(S, "#####", "</a>");



Страницы: 1 вся ветка

Форум: "Начинающим";
Текущий архив: 2012.05.27;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.57 MB
Время: 0.005 c
2-1327559321
rusmus
2012-01-26 10:28
2012.05.27
Использование edit1


1-1292333775
jiny007
2010-12-14 16:36
2012.05.27
Проблема с запуском TFrxPreview из FastReport


4-1257275310
mihail
2009-11-03 22:08
2012.05.27
Как на прямую обращаться к байтам файлового носителя?


2-1327425569
sem
2012-01-24 21:19
2012.05.27
Вызов процедуры


3-1276183014
REX
2010-06-10 19:16
2012.05.27
Вывод времени в QRDBText





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский