воскресенье, 4 апреля 2010 г.

Parsing сайта

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

Есть такой сайт - knigka.info, на котором можно скачать книги. Я решил глянуть там литературу по компьютерам, ну и по другим разделам пройтись. Но дело в том, что на каждой странице там выводится только по 10 книг, а ещё надоедливая реклама постоянно мелькает. Это существенно замедляет работу. И я решил скачать все описания к книгам раздела, собрать их в одном файле, а потом уже сидеть и изучать его. Конечно, всё в автоматическом режиме. Без HiAsm - никуда!

Адреса всех разделов сайта имеют примерно одинаковую структуру. В разделе может быть много страниц, и адрес каждой указывается номером в конце типа http://www.knigka.info/category/pc/page/40/. Передо мной стояла задача пройтись через все страницы и собрать описания книг. Именно описания книг, а не весь HTML-код страницы: зачем он мне с рекламой и прочими ненужными вещами?

Прежде всего, нужно скачать HTML-код страницы.



В HTTP_Get должно быть установлено Wait=False, чтобы программа не зависала на время загрузки. Закачивать данные мы будем не в файл, а в программу, потому указывать имя файла не нужно.



HTTP_Get выдаёт на onDownload данные типа файловый поток, и их нужно преобразовать в текстовые данные, что и делает конвертор. А затем уже разбирать HTML-код.


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

Если открыть HTML-код любой страницы разбираемого сайта, то можно увидеть, что каждое описание - это отдельная таблица, которая заключена в такие теги:

< table class="cblock">
< /table>


Вот мы и вытаскиваем данные из таблиц компонентом BlockFind. Но проблема в том, что в такие теги заключены не только описания книг - в такие теги заключена одна из реклам, самая первая в HTML-коде. И её нужно отсеять. Для этого и нужен счётчик. У него всего 11 возможных значений: от 0 до 10. При нахождении каждой таблицы значение счётчика увеличивается. Первым будет 0; программа проверяет его на равенство нулю и при равенстве - не пропускает такую таблицу. А остальные 10 таблиц (они содержат описания книг) - пропускает.

После этого указанные таблицы на странице кончаются, загружается новая страница, и всё повторяется. А счётчик со значения 10 переходит на 0, и рекламная таблица опять не попадает в файл. Файл же сохраняется после разбора каждой страницы.

Но так мы загружаем только одну страницу, а нужно - все из данного раздела.



В данном случае мы просто меняем адрес страницы в поле ввода, но разбор этого адреса - не такое просто дело, как может показаться. Для начала мы отделяем число. Оно идёт после 6-го слеша, поэтому это легко делается одним компонентом. Затем отнимаем единицу и проверяем, не равно ли оно нулю. Если равно - ничего не происходит, потому что нулевых страниц на сайте нет.

Если число не равно нулю, то предыдущее нужно заменить новым, которое меньше на 1. Просто Replace здесь может не помочь, потому что если такое же число будет в названии какого-то раздела сайта, то заменится и оно, а нам нужно только изменить страницу. Удалить N-ное количество последних символов тоже не получится, потому что страница может иметь и номер 1, и номер 144, и количество цифр будет разным.

Возможно, можно было как-то по-другому решить эту проблему, более красиво, но я думать над этим не стал, потому что программа эта одноразовая, и чем скорее я её сделаю, тем лучше. В данном случае я просто сравниваю символы с конца на равенство «/» и при неравенстве - удаляю символ. Когда дело дойдёт до «/», это будет значить, что номер страницы полностью стёрт. Конечно, в этом случае самый последний слеш (который после номера страницы) нужно убирать ещё в поле ввода вручную, иначе алгоритм удаления на нём и остановится, не добравшись до номера страницы.

А потом оставалось только найти файл CSS в Temporary Internet Files и поместить его рядом с файлом HTML, прописав в последнем положение файла CSS, чтобы форматирование было одинаковым.

Конструирование этой программы заняло у меня минут 15 (это ещё с небольшим перерывом, чтобы ответить по телефону), а сэкономило мне пару часов как минимум....
Вот так.






Хотите что-нибудь интересного и новенького, а ещё и полезного? Рекомендую посмотреть компьютерные самоделки. Там реально прикольные вещи, которые можно сделать самостоятельно!

54 комментария:

  1. Крутая прога ХиАсм! и бесплатная!
    Выражаю своё уважение.

    ОтветитьУдалить
  2. Бесплатен только кодогенератор, оболочка и компилляторы, входящие в инсталляционный пакет, но вот если тебе нужен платный компиллятор - то это уже придется платить

    ОтветитьУдалить
  3. Да, и кстати, сделаю полезное замечание автору статьи, если знаешь точный байт начала и конца блока ифно (надо смотреть сохраненную страницу одной из страниц инфо), то можно использовать свойство length и точку position, это сэкономит трафик

    ОтветитьУдалить
  4. Когда же появятся новые видео уроки???
    Микрофон еще не приобрели?
    А еще такой вопрос:
    Для чего нужен продвинутый хаб и где его применять, в чем отличие от разветвителя?
    Заранее спасибо!

    ОтветитьУдалить
  5. Приобрёл, но хочу выложить все видеоуроки сразу, а не по отдельности. Думая, на днях выложу, когда запишу ещё несколько.
    Продвинутый хаб, насколько мне известно, не создаёт лишнего кода в программах, программы будут чуть меньше за счёт этого. В самой схеме он тоже не мешается, т.к. очень мал (хотя из-за этого его трудно перетаскивать). Отличие ещё и в том, что количество точек в нём изменять нельзя. Из-за этого его можно применять только тогда, когда надо несколько потоков объединить в один, а разбить на несколько поток один поток не получится.

    ОтветитьУдалить
  6. Скажите пожалуйста, почему в контроллёре страниц неполучается в редактаре форм установить нужную страницу, чтобы вынести на нее визуальные компоненты (выносятся только на первую страницу)? Почему после компиляции на всех страницах отображаются компоненты первой страницы? Как вообще правильно работать с контроллёром страниц?

    ОтветитьУдалить
  7. С контроллёром страниц работают так. На сам контроллёр компоненты устанавливать бессмысленно, т.к. он не имеет вкладок, а только корешки-закладки. Компоненты устанавливаются на отдельные панели, которые должна находиться друг под другом и полностю закрыть друг друга, чтобы при переключении из-под одной вкладки не высовывалась другая.

    ОтветитьУдалить
  8. Спасибо огромное, Вы меня очень выручили!

    ОтветитьУдалить
  9. Очень нужна Ваша помощь!
    В элементе "панель инструментов", не удается осуществить всплывающие подсказки при навидении на какой либо из значков (разумеется при навидении на конкретный значек, должна всплывать конкретно его подсказка). Пожалуйста, помогите осуществить мне эту идею!!!
    С уважением Макс.

    ОтветитьУдалить
  10. Буквально вчера наткнулся на ваш блог. Спасибо за проделанный труд. Теперь есть повод снова засесть за hi-asm, уже по-серьезному!

    ОтветитьУдалить
  11. Можно ли осуществить стандартные операции "Отменить или Шаг назад" и "Повторить или Шаг вперед" при работе со String TableMT (во время редактирования таблицы)?
    Заранее, спасибо!

    ОтветитьУдалить
  12. Имеется в виду редактирование схемы? Сервис - Редактор команд, там есть команда "отмена", её надо поместить в какое-либо меню среды. Тогда из него можно будет отменять действия. Обратной операции я не нашёл (в HiAsm 4.02 build 179)

    ОтветитьУдалить
  13. Нет. Я собрал программу для учета запчастей, в этой программе приходится часто редактировать таблицу (добавлять записи, изменять и т.д.), иногда получается, что ошибочно удаляешь или изменяешь данные в этой таблице, так вот затем и нужна отмена последнего действия в этой програме.
    Еще такой вопрос:
    Можно ли выделенную строку в этой же таблице перемещать на одну позицию выше/ниже в этой же таблице?
    И еще как можно распечатать (корректно) таблицу? Может можно сделать снятия скриншота по периметру таблицы (в зависимости от количества строк), а то текстовый файл полная ерунда ничего непоймешь?
    Большое Спасибо!!!

    ОтветитьУдалить
  14. Отмена изменений. С помощью массива данных можно реализоват и возврат отмен.

    Для перемещения строки можно использовать точки doDelete и doInsert (последняя - на вкладке "Точки"), запоминая необходимую к перемещению строку.

    Насчёт печати честно скажу - не знаю, т.к. я не автор HiAsm (автор HiAsm - Dilma, сайт hiasm.com).

    ОтветитьУдалить
  15. Для печати таблицы как мы ее видим в программе есть компонент (не установленный в ХайАсме)-PrinterPR. Ссылка на скачивание: http://narod.ru/disk/21694224000/%D0%B2%D1%8B%D0%B2%D0%B5%D1%81%D1%82%D0%B8%20%D0%BD%D0%B0%20%D0%BF%D0%B5%D1%87%D0%B0%D1%82%D1%8C%20%D1%82%D0%B0%D0%B1%D0%BB%D0%B8%D1%86%D1%83%20%D1%81%D1%82%D1%80%D0%BE%D0%BA%20StringTable.rar.html
    Что я только с ним ниделал неполучается хоть тресни. Может я его не правильно установил (кинул INI файл в окно с программой, обычно так устанавливают новые компоненты). Есть пример использования PrinterPR (http://hiasm.com/xf/topic.php?p=43268), но я не могу скачать пример (рейтинг мал).
    Пожалуйста помогите, выложите примерчик и как установить компонент, очень очень нужно!
    Доброты не забуду!

    ОтветитьУдалить
  16. Тот пример, видимо, удалён. Да и компонент стар, вряд ли пойдёт на версии 179. К сожалению, это не в моей компетенции. Попробуйте на форуме попросить помощи или зайти в раздел "Купи-продай" там же.

    ОтветитьУдалить
  17. Новая версия 184 (у меня тоже).
    Спасибо за ответы!

    ОтветитьУдалить
  18. Почему тишина ? Когда продолжим учиться

    ОтветитьУдалить
  19. Обязательно продолжим! Только сейчас я записываю видеоуроки к предыдущим статьям, так что пока времени не остаётся.

    ОтветитьУдалить
  20. вот это хорошо , а то я все уроки собираю. Сейчас пытаюсь архиватор по своему алгоритму сделать . Вряд ли получится архиватор но экспериментировать с алгоритмами а Hi-Asm очень удобно , интересно и быстро. Сразу видно удачная идея или нет.

    ОтветитьУдалить
  21. Архиватор - это хорошая идея, т.к. вещь очень полезная и нужная. Только сложная. Не изучив предыдущие алгоритмы, можно просто "изобрести велосипед". Удачи в начинаниях!

    ОтветитьУдалить
  22. да я изучал .Перерыл весь интернет . И как сказал вряд ли что изобрету . Но так ведь когда есть стимул и интерес намного продуктивнее получается . Я в своё время на ZX Spectrum тоже оригинальные программы делал. Например порченные кассеты ( а программы загружались с магнитофона) программавостанавливала с большим успехом. Многоголосый орган который играл аккордами ( а звук в спектрумах был одноголосный ).И тоже говорили так на получится. А программировать медиаплеер путем вставки компонента медиаплеер мне не интересно.

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

    ОтветитьУдалить
  24. Подскажите, а как можно отдать логин и пароль через http. Так как иногда надо пропарсить сайт на который можно попасть только залогинившись. А в уроке этого нет. Вообще такое возможно?

    ОтветитьУдалить
  25. Для авторизации лучше посылать запрос на сервер, как, например, в примере Elements\Delphi\Example\Internet\PostBuilder.sha. Только в компоненте URLBuilder нужно для верхних точек задать другие имена - те, которые соответствуют именам полей в форме авторизации сайта, скорее всего. Это могут быть login и password или что-то вроде этого. А потом уже скачивать страницу через http.

    ОтветитьУдалить
  26. При распаковке видео, требует файл v064.part01.rar1 ,,ЕГО ЖЕ ТАМ НЕТ!!! Что за глюк автор залил.

    ОтветитьУдалить
  27. rar0 надо переименовать просто в rar. Для всех файлов.

    ОтветитьУдалить
  28. Суперская программа HiAsm! Только я с ней никак разобраться не могу. Уж сколько месяцев бьюсь - и всё никак!!! Кошмар. :( Хотя с другой программой - Алгоритм - давно разобрался, но она не такая крутая, как HiAsm.

    ОтветитьУдалить
  29. Как и почти в любом программировании, главное - понять, что методы вызываются событиями. Т.е. действия в программе должны начинаться с каких-то событий, например нажатие кнопки, достижение определённого времени, вставка диска в дисковод и пр. Ну а действия программы при этом зависят от самой программы: на что она рассчитана.

    ОтветитьУдалить
  30. Цитата:
    «...С контроллёром страниц работают так. На сам контроллёр компоненты устанавливать бессмысленно, т.к. он не имеет вкладок, а только корешки-закладки. Компоненты...»

    А по ссылочке «так» у нас... не нужно смеяться, участок программного кода Delphi!
    Господин Админ! Извините за раздражённый тон. Если бы я знал Delphi, мне бы не понадобился Ваш конструктор программ. Я бы просто установил бы среду программирования Delphi.

    Иными словами, в графическом режиме, создать многооконное приложение со вкладками в Вашей программе невозможно?!!!

    ОтветитьУдалить
  31. Во-первых, HiAsm - не моя программа, её создатель - Dilma (см. сайт hiasm.com). Я только веду блог по HiAsm.
    Во-вторых, это не код Delphi, а код схемы HiAsm. Схему HiAsm можно представить и в виде текста. Однако вышеуказанная ссылка указывает на файл-схему HiAsm. Её надо сохранить на компьютер и там открыть в HiAsm! А вкладки создать в HiAsm, разумеется, можно.

    ОтветитьУдалить
  32. Уф! Благодарю! Я пытался быстро, без знания программирования, создать необходимую утилиту. Не получилось! Этим и обусловлен мой раздражённый тон.
    Прошу прощения.
    _____________________

    Кстати я думаю, в последующих версиях следует больше внимания уделять программам – заготовкам! И даже включить их в системное меню!
    Ну, действительно. Какие могут варианты создания меню с вкладками? Не лучше ли, не программисту - модифицировать уже готовую схему? :)

    ОтветитьУдалить
  33. Кстати вот, помогу людям, которые впадают в ужас при виде программного кода!

    http://savepic.org/2025759.jpg

    ОтветитьУдалить
  34. Где-нибудь можно скачать/посмотреть собственно файл
    этого проекта?

    ОтветитьУдалить
  35. очень интересует вопрос, а что если адреса страниц не такие, как в примере, т.е. /45,

    а имеют тип:
    /35127245.html

    что делать?

    ОтветитьУдалить
  36. "Где-нибудь можно скачать/посмотреть собственно файл этого проекта?"

    Конечно, вот же он: hi-asm.narod.ru/sha/bh244.sha. В тексте стать есть ссылка-картинка на него.

    "очень интересует вопрос, а что если адреса страниц не такие, как в примере, т.е. /45,
    а имеют тип: /35127245.html
    что делать?"

    Немного переделать код. Если страницы идут по порядку (т.е. 35127245, 35127246, 35127247 и т. д.), то будет работать и тогда.

    ОтветитьУдалить
  37. Вот так. Но тут я изменил лишь смену номеров страниц, а выдирание нужного текста - нет, т.к. не знаю, что конкретно вам нужно.

    ОтветитьУдалить
    Ответы
    1. Спасибо, фрагмент думаю смогу добавить.

      Удалить
  38. Уважаемый администратор, вот нарыл на просторах форума HiAsm вашу схемку для работы с IE. Заполнить поля: логин и пароль получилось, а вот нажать кнопку для входа в аккаунт нет! Не могли бы вы подправить вставленный код
    ЧАСТЬ-1
    Add(MainForm,2953706,21,21)
    {
    Width=690
    Height=566
    }
    Add(WebBrowser,15563951,105,21)
    {
    Left=5
    Top=85
    Width=665
    Height=430
    URL="http://www.igra3k.ru/"
    Point(PHandle)
    Point(doFromText)
    Point(Handle)
    }
    Add(InlineCode,5978023,119,175)
    {
    WorkPoints=#6:Parsel|
    DataPoints=#2:ph|4:name|5:value|
    Code=#15:unit HiAsmUnit;|0:|9:interface|0:|40:uses kol,Share,Debug,ActiveX,KOLSHDocVw;|0:|4:type|28: THiAsmClass = class(TDebug)|10: private|0:|9: public|17: ph:THI_Event;|19: name:THI_Event;|20: value:THI_Event;|0:|47: procedure Parsel(var dt:TData; index:word);|0:|5: end;|0:|14:implementation|0:|4:type|31: TKOLWebBrowser = PWebBrowser;|31: PKOLWebBrowser = PWebBrowser;|0:|29:procedure THiAsmClass.Parsel;|16:var pc:PControl;|15: txt:string;|14: i:integer;|5:begin|36: pc := PControl(ToIntegerEvent(ph));|80: for i:=0 to PKOLWebBrowser(pc).OleObject.Document.all.tags('input').length-1 do|100: if PKOLWebBrowser(pc).OleObject.Document.all.tags('input').Item(i).name = ToStringEvent(name) then|76:// PKOLWebBrowser(pc).OleObject.Document.all.tags('input').Item(i).focus;|98: PKOLWebBrowser(pc).OleObject.Document.all.tags('input').Item(i).value := ToStringEvent(value);|4:end;|0:|4:end.|
    link(ph,8569342:getVar,[])
    link(name,15375584:Text,[])
    link(value,12692327:Text,[(139,163)(176,163)])
    }

    ОтветитьУдалить
  39. ЧАСТЬ-2
    Add(Edit,15375584,126,119)
    {
    Left=10
    Top=5
    Width=135
    Text="signin[login]"
    }
    Add(Edit,12692327,170,120)
    {
    Left=155
    Top=5
    Width=135
    Text="privet"
    }
    Add(Button,3488175,70,175)
    {
    Left=295
    Top=5
    TabOrder=-1
    Caption="Set"
    link(onClick,5978023:Parsel,[])
    }
    Add(InlineCode,4357583,119,294)
    {
    WorkPoints=#6:Parsel|
    DataPoints=#2:ph|4:name|5:value|
    Code=#15:unit HiAsmUnit;|0:|9:interface|0:|40:uses kol,Share,Debug,ActiveX,KOLSHDocVw;|0:|4:type|28: THiAsmClass = class(TDebug)|10: private|0:|9: public|17: ph:THI_Event;|19: name:THI_Event;|20: value:THI_Event;|0:|47: procedure Parsel(var dt:TData; index:word);|0:|5: end;|0:|14:implementation|0:|4:type|31: TKOLWebBrowser = PWebBrowser;|31: PKOLWebBrowser = PWebBrowser;|0:|29:procedure THiAsmClass.Parsel;|16:var pc:PControl;|15: txt:string;|14: i:integer;|5:begin|36: pc := PControl(ToIntegerEvent(ph));|80: for i:=0 to PKOLWebBrowser(pc).OleObject.Document.all.tags('input').length-1 do|100: if PKOLWebBrowser(pc).OleObject.Document.all.tags('input').Item(i).name = ToStringEvent(name) then|76:// PKOLWebBrowser(pc).OleObject.Document.all.tags('input').Item(i).focus;|98: PKOLWebBrowser(pc).OleObject.Document.all.tags('input').Item(i).value := ToStringEvent(value);|4:end;|0:|4:end.|
    link(ph,8154932:getVar,[])
    link(name,3057939:Text,[])
    link(value,6191608:Text,[(139,282)(176,282)])
    }

    ОтветитьУдалить
  40. ЧАСТЬ-3
    Add(Edit,3057939,126,238)
    {
    Left=10
    Top=30
    Width=135
    Text="signin[password]"
    }
    Add(Edit,6191608,170,239)
    {
    Left=155
    Top=30
    Width=135
    Text="privet"
    }
    Add(Button,16300376,70,294)
    {
    Left=295
    Top=30
    TabOrder=-1
    Caption="Set"
    link(onClick,4357583:Parsel,[])
    }
    Add(InlineCode,15424916,119,413)
    {
    WorkPoints=#6:Parsel|
    DataPoints=#2:ph|4:name|5:value|
    Code=#15:unit HiAsmUnit;|0:|9:interface|0:|40:uses kol,Share,Debug,ActiveX,KOLSHDocVw;|0:|4:type|28: THiAsmClass = class(TDebug)|10: private|0:|9: public|17: ph:THI_Event;|19: name:THI_Event;|20: value:THI_Event;|0:|47: procedure Parsel(var dt:TData; index:word);|0:|5: end;|0:|14:implementation|0:|4:type|31: TKOLWebBrowser = PWebBrowser;|31: PKOLWebBrowser = PWebBrowser;|0:|29:procedure THiAsmClass.Parsel;|16:var pc:PControl;|15: txt:string;|14: i:integer;|5:begin|36: pc := PControl(ToIntegerEvent(ph));|80: for i:=0 to PKOLWebBrowser(pc).OleObject.Document.all.tags('input').length-1 do|102: if PKOLWebBrowser(pc).OleObject.Document.all.tags('input').Item(i).value = ToStringEvent(value) then|74: PKOLWebBrowser(pc).OleObject.Document.all.tags('input').Item(i).focus;|100:// PKOLWebBrowser(pc).OleObject.Document.all.tags('input').Item(i).value := ToStringEvent(value);|4:end;|0:|4:end.|
    link(ph,2799169:getVar,[])
    link(name,11771908:Text,[])
    link(value,5124459:Text,[(139,403)(183,403)])
    }

    ОтветитьУдалить
  41. ЧАСТЬ-4
    Add(Button,15211543,70,413)
    {
    Left=295
    Top=55
    TabOrder=-1
    Caption="Set"
    link(onClick,15424916:Parsel,[])
    }
    Add(LineBreakEx,1930990,119,77)
    {
    Caption="PHandle"
    Type=3
    link(_Data,15563951:PHandle,[])
    }
    Add(LineBreakEx,8569342,119,98)
    {
    Caption="PHandle"
    Type=2
    }
    Add(LineBreakEx,8154932,119,217)
    {
    Caption="PHandle"
    Type=2
    }
    Add(Edit,11771908,126,360)
    {
    Left=10
    Top=55
    Width=135
    Text=""
    }
    Add(Edit,5124459,177,361)
    {
    Left=155
    Top=55
    Width=135
    Text="Начать игру"
    }
    Add(LineBreakEx,2799169,119,336)
    {
    Caption="PHandle"
    Type=2
    }

    ОтветитьУдалить
  42. P.S.
    Уважаемый администратор, если Вам не трудно,
    отправте исправленную схемку на Sova-kmv@yandex.ru чтобы не заграмождать огромными схемами ваш блог.
    С уважением к Вам, Николай.

    ОтветитьУдалить
  43. Но это не моя схемка! Наверное, это администратор форума (Dilma) делал, а я только администратор этого блога, но не форума hiasm.com! Поэтому вам лучше обратиться к нему.
    С уважением, Сергей.

    ОтветитьУдалить
  44. Доброго времени суток Сергей.
    Вот ссылка на стр. (http://forum.hiasm.com/forum.html?q=3&p=137922).
    Данную схемку выставил пользователь 3042.
    В разделе (Профиль) у пользователя 3042 ссылка на этот блог
    ([url=http://hi-asm.blogspot.com]Блог о HiAsm[/url])
    Это что, HiAsm-овский косяк?

    ОтветитьУдалить
  45. А вы скиньте всю свою схему целиком на smvid@yandex.ru, я посмотрю, а то из блога она почему-то в hiasm не вставляется.

    ОтветитьУдалить
  46. В третьем IC надо просто заменить "Item(i).focus;" на "Item(i).click;".

    ОтветитьУдалить
  47. БРАВО Сергей, всё прекрасно работает!
    Спасибо Вам ОГРОМНОЕ.
    С уважением к Вам, Николай

    ОтветитьУдалить
  48. Привет Сергей, доброго времени суток тебе.
    Сергей, ну загляни пожалуйста в свою почту.
    Есть кое-какая проблемка, может поможеш разобраться!
    С уважением к тебе, Николай

    ОтветитьУдалить
  49. а как просмотреть видео урок? Скачал все 3, собрал 7-Zip, включается и на середине зависает, как будто неполный архив.

    ОтветитьУдалить