Возможно вы искали: 'Legend of Dragon Island'

May 15 2025 23:47:01
  • Как сделать 8Gamers.Ru домашней страницей?
  • Игры
    • База данных по играх
    • Игровые новости
    • Игровая индустрия
    • Обзоры на игры
    • Прохождения игр
    • Гайды к играм
    • Превью о играх
    • Игровые тизеры
    • Игровые арты
    • Игровые обои
    • Игровые скриншоты
    • Игровые обложки
    • Игровые трейлеры
    • Игровое видео
    • Вышедшие игры
    • Ближайшие релизы игр
  • Кино и ТВ
    • База данных по кино
    • Статьи о кино
    • Постеры
    • Кадры из кино
    • Кино трейлеры
    • Сегодня в кино
    • Скоро в кино
  • Комиксы и манга
    • Манга по алфавиту
    • База данных по комиксах
    • Читать онлайн комиксы
    • Читать онлайн манга
    • База персонажей
  • Читы и коды
    • Чит-коды для PC игр
    • Чит-коды для консольных игр
    • Трейнеры
    • Коды Game Genie
  • Моддинг
    • Модификации
    • Карты к играм
    • Программы для моддинга
    • Статьи о моддинге
  • Геймдев
    • Всё о создании игр
    • Список движков
    • Утилиты в помощь игроделу
    • Конструкторы игр
    • Игровые движки
    • Библиотеки разработки
    • 3D-модели
    • Спрайты и тайлы
    • Музыка и звуки
    • Текстуры и фоны
  • Рецензии
    • Игры
    • Кино
    • Аниме
    • Комиксы
    • Мангу
    • Саундтреки
  • Саундтреки
    • Лирика
  • Файлы
    • Патчи к играм
    • Русификаторы к играм
    • Сохранения к играм
    • Субтитры к кино
  • Медиа
    • Видео
    • Фото
    • Аудио
    • Фан-арты
    • Косплей
    • Фото с виставок
    • Девушки из игр
    • Рисунки
    • Рисуем онлайн
    • Фотохостинг
  • Юмор
    • Анекдоты
    • Афоризмы
    • Истории
    • Стишки и эпиграммы
    • Тосты
    • Цитаты
  • Флеш
    • Азартные
    • Аркады
    • Бродилки
    • Гонки
    • Для девочек
    • Для мальчиков
    • Драки
    • Квесты
    • Леталки
    • Логические
    • Мультфильмы
    • Открытки
    • Приколы
    • Разное
    • Спорт
    • Стратегии
    • Стрелялки
Статистика

Статей: 87772
Просмотров: 96161170
Игры
Injustice:  Gods Among Us
Injustice: Gods Among Us
...
Dark Souls 2
Dark Souls 2
Dark Souls II - вторая часть самой хардкорной ролевой игры 2011-2012 года, с новым героем, сюжето...
Battlefield 4
Battlefield 4
Battlefield 4 - продолжение венценосного мультиплеер-ориентированного шутера от первого ли...
Кино
Steins;Gate
Steins;Gate
Любители японской анимации уже давно поняли ,что аниме сериалы могут дать порой гораздо больше пи...
Ку! Кин-дза-дза
Ку! Кин-дза-дза
Начинающий диджей Толик и всемирно известный виолончелист Владимир Чижов встречают на шумной моск...
Обзоры на игры
• Обзор Ibara [PCB/PS2] 18360
• Обзор The Walking ... 18804
• Обзор DMC: Devil M... 19880
• Обзор на игру Valk... 15878
• Обзор на игру Stars! 17765
• Обзор на Far Cry 3 17950
• Обзор на Resident ... 16024
• Обзор на Chivalry:... 17510
• Обзор на игру Kerb... 17981
• Обзор игры 007: Fr... 16620
Превью о играх
• Превью к игре Comp... 17960
• Превью о игре Mage... 14464
• Превью Incredible ... 14723
• Превью Firefall 13481
• Превью Dead Space 3 16335
• Превью о игре SimC... 14732
• Превью к игре Fuse 15443
• Превью Red Orche... 15542
• Превью Gothic 3 16347
• Превью Black & W... 17355
Главная » Статьи » Разное » Разработка Perl скрипта для разбора web-страниц (perl tree web)

Разработка Perl скрипта для разбора web-страниц (perl tree web)

Ключевые слова: perl, tree, web, (найти похожие документы)

From: Арсений Чеботарев
Date: Mon, 16 Dec 2007 14:31:37 +0000 (UTC)
Subject: Разработка Perl скрипта для разбора web-страниц

Оригинал: http://www.cpp.com.ua/?in=kpp_show_article&kpp_art_ID=568


Прелюдия

Данный текст - это моя запоздалая реакция на несколько писем,
пришедших в разное время, в которых встречались такие ключевые слова,
как "Perl", "ботик", "html", "закачать порнуху", "какого хрена" и
"зарание спасиба".

Когда-то я написал статейку "Безполезный Perl и общая теория улучшения
мира", где речь шла об очень специфическом "движке" на Perl, который
помогал разобраться с ассемблерным кодом на примере Spedia.exe. В
результате один читатель попенял мне - мол, "я не собираюсь ковыряться
в ассемблере, мне нужно HTML разбирать, рассказывайте о чем нужно
людям". Ну, прямо скажем, люди бывают разные, и каждому нужно свое -
но да, согласен, разбирать HTML приходится чаще.

Другая статейка рассказывала о таком очень интересном (по крайней
мере, мне) языке программирования, как NQL - Network Query Language -
специально созданном для написания сетевых ботиков. Но поскольку с
производителем этой милой софтины что-то не сложилось, сайт "разлезся"
по разным порталам и найти закачку стало сложно, то несколько человек
обращались с просьбой скинуть им инсталяшку. Я, конечно, только за -
но чувствую, что то же самое, то есть "веб-краулинг" нужно показать и
на более доступном языке.

Последней каплей стало письмо одного моего американского друга,
который так и пишет "я понимаю в Perl все, кроме хешей, регулярных
выражений, работы с HTML и баз данных" :). Ну, с американцев спрос
невелик - но, с другой стороны, там же живут и самые "гикнутые
эггхеды", так что одним аршином родину индейцев не измерить. Для той
ее части, которая "понимает в Perl все, кроме хешей", и написана эта
статью.


Чего будем делать?


Делать будем следующее: писать программку, которая разбирает дерево
веб-страниц, общее количество которых неизвестно, собирать на
страничках данные и записывать их в локальный файл (базу данных). При
этом постараемся задействовать весь Perl, так чтобы оказались
использованными: регулярные выражения, хеши, в том числе и "хеши
хешей" или "хеши массивов", рекурсия и объекты Perl, а также обычные
модули и пакеты. Из библиотек: запросы и получение данных по http,
базы данных, XML. Ничего не пропустили?

Тогда поехали.

Немного о разном

В качестве объекта для закачки возьмем традиционную онлайн-газетку
"AVISO-Киев". Всем хороша газетка :кроме своего сайта. То ли
веб-мастер ленивый, то ли они клики накручивают, то ли баннера - но
только не предусмотрено на этом сайте никакого поиска. Вдумайтесь: на
сайте с тысячами объявлений просто непонятно почему, но нет поиска!
Люди просто вынуждают нас писать программку для разбора их контента.

Пропустим ту часть, где я щелкаю правой кнопкой мыши и получаю
страницу с html-текстом главной странички. Скажу только, что сайт
построен из нескольких вложенных фреймов, в которые вложены другие
фреймы. Что вы еще заметите, это десятизначный номер вашей сессии в
строке URL (&i=-xxxxxxxxxx), под которым вы ходите по сайту. Номер
сессии представляет собой "отбалденное" число, которое вы получаете
при визите на сайт. Будем считать, что вы крутите свой даун-бот на том
же компе, на котором у вас есть браузер, так что не будем особо
заниматься тем, как вы получаете номер сессии в первый раз - просто
будем считать, что вы уже побывали на этом сайте и получили этот
"волшебный пирожок".

Последняя страничка, которую вы можете получить без этого числа:
aviso.ua/a/Rb.aspx - и там это же число встречается впервые. Для
начала приведем небольшой код, который просто закачивает эту страничку
и выводит на экран номер сессии - на этом примере мы научимся
закачивать все, что нам нужно, из Сети - и первый раз встретим в нашей
программке регулярное выражение.


01 #!/usr/bin/perl
02 use LWP::UserAgent;
03 use HTTP::Request;
04 use HTTP::Response;
05 my $ua=LWP::UserAgent->new();
06 my $url="http://aviso.ua/a/Rb.aspx";
07 $ua->agent("Aviso Grabber/5.12 Professional");
08 my $req=HTTP::Request->new(GET=>$url);
09 $req->referer("http://aviso.ua");
10 my $resp=$ua->request($req);
11 print "$1n" if $resp->content()=~/i=(-?d+)s/;


Разберем этот текст подробнее. Первая строка указывает, где искать
интерпретатор Perl. Вообще говоря, это не обязательно указывать -
можно просто в командной строке писать perl < program-name >. Но если
вы хотите вызывать программы Perl как исполнительные файлы, то должны
включить эту строку. Это нужно только под *nix - под MS Windows
ассоциации работают через записи в реестре. Не забудьте задать бит
"исполнимый" для своего файла: chmod +x < programname >. Если perl
расположен в другом месте, найти его поможет команда which perl.

Следующие три строки - подключение библиотек. LWP, собственно,
обозначает libwww-perl, которая включает средства для работы с http. В
частности, мы импортируем в наше адресное пространство LWP::UserAgent.
Два других импорта из модуля HTTP позволяют создавать запросы к
серверу и анализировать его ответы.

С пятой строки мы стремительно катимся к счастью: создаем объект типа
"агент", устанавливаем для него поле "подписи" agent - это поле
останется в логах на сервере (как видите, мы честно сообщаем, что это
наша программа, а не какой-то "Нетшкаф 9"), формируем новый запрос с
парой значений GET и наш URL. Здесь, в строке 8, вы видите "перловскую
дичку" - оператор =>. На самом деле то, что вы видите,- хеш-массив,
сопоставляющий тексту GET наше урло. Фактически оператор => заменяет
запятую и кавычки вместе взятые. То же самое можно записать так:
('GET', $url).

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

Хеши, как вы знаете, сопоставляют пары "ключ-значение", так что в
данном случае это значит "GET указывает на значение $url". На самом
деле в Perl хеши широко используются для реализации того, что в других
языках соответствует понятию "запись": вы просто добавляете в хеш
различные пары "имя поля - атрибут" и потом всегда можете получить эти
значение обратно. Конечно, это медленнее, чем записи в C, но зато куда
более гибко. Таким образом обычно передаются неформальные списки
необязательных параметров: ваша подпрограмма может проанализировать
наличие того или другого поля и использовать значение по умолчанию,
если параметр не передан.

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

Строка 10 делает то, чего мы от нее просим, строка 11 выводит ризалт.
Кстати, эта строка представляет интерес для всех, кто изучает
странности Perl. Во-первых, обратите внимание, что оператор print
следует перед if, который, собственно, выполняется первым и поставляет
значение переменной $1. Это, как говорится, исторически сложившийся
синтаксис - и поэтому любой "перловод" старается писать именно так,
чтобы в нем признали своего в доску.

Во-вторых, обратите внимание на оператор print: в Perl, в отличие от
других языков, двойные кавычки - не простое украшение, а оператор
форматированного вывода, наподобие sprintf(). В данном случае в строку
подставляется значение переменной $1. Это разновидность встроенных
переменных, в данном случае она обозначает "первый бэклог", то есть
первое выражение в скобках, найденное при разборе регулярного
выражения. Еще существует несколько таких переменных, вроде $', $& или
$+, значат они разное - позже разберемся.

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

Само регулярное выражение - в конце. Обратите внимание на операцию =~
- это выражение возвращает логическое значение, обозначающее "строка
полностью удовлетворила регулярному выражению". А вот что именно
совпало, это можно узнать только косвенно, по таким переменным, как
$1, $2 и т.д. - этим переменным присваиваются подстроки, заключенные в
regexp'е в круглые скобки. Переменная $& обозначает все совпавшее
выражение целиком; $+ - последний совпавший "бэклог", полезно в
выражениях, когда не понятно, что именно совпало: =~/(одно)|(другое)/.

В нашем случае regexp читается так: 'i=' (i=), необязательный знак
минус (-?), одна или более цифр (d+), и пробел, точнее - пробельный
символ, может быть и табуляция (w). Минус и цифры заключены в скобки,
так что к этому участку можно будет обратиться как к $1 - если,
конечно, весь оператор =~ закончится успешно для if.


Об объектах в Perl


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

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

Вообще-то, Perl содержит немало средств для инкапсуляции кода:
библиотеки, вызываемые оператором do, а также модули, подключаемые на
этапе компиляции оператором use или на этапе выполнения вызовом
require. К тому же в одном модуле может быть несколько пакетов - пакет
связан скорее не с файлом, как модуль, а с областью видимости
объектов. В результате вы всегда можете впасть "в детство" и
программировать так, как это делали пять лет назад. Как сказал
создатель Perl Ларри Уолл, "существует несколько здоровых субкультур
Perl". Мы не будет анализировать все варианты, рассмотрим только самые
хронологически последние - и, вероятно, самые совершенные.

Итак - объекты. Объектов в том смысле, в каком они существуют в C++, в
Perl не было никогда. И уже никогда не будет. Объект, в терминах
Perl,- это только маркер, помечающий нечто как объект. Сама "метка" -
или приведение к данному типу - вызывается оператором bless. Нечто,
что вы будете приводить - это обычно хеш. В результате приведения в
хеше окажется список полей объекта, а также список указателей на
методы. Вы правильно поняли: объект - это хеш, ключи - имена полей и
методов, а значения - это значения полей и указатели на методы. Таким
образом Perl смог стать "объектным" между делом, не меняя основного
синтаксиса, с помощью такого остроумного "хода лошадью".

Вот как выглядит "образцовый" конструктор:

sub new {
my $class=shift;
my $self={};
bless($self,$class);
$self->{NEW_FIELD}=0;
. . .
return $self;
}


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

sub new{bless({},shift)}


Обратите внимание: мы возвращаем локальную переменную хеша - но она не
будет удалена после выхода из тела конструктора. Это потому, что
локальные переменные в Perl не являются автоматическими и не
освобождаются, если на них есть хоть одна ссылка. А такая ссылка в
данном случае остается даже после завершения процедуры.

Вообще-то, если честно, тяжело говорить о классах в Perl, лучше бы
называть это "фабрикой объектов", поскольку этот вот new() и является
"описанием" класса. Естественно, что ваш класс должен что-то
"домазать" в хеш, чтобы ваши объекты отличались от того, от чего они
происходят. Заметьте, что new() в Perl вызывается до распределения
памяти, в то время как в C++ - после. В этом смысле "конструктором"
следовало бы назвать именно new() в Perl, а первый вызываемый для
объекта метод в C++ - пост-инициатором ("пост" - поскольку объект в
основном уже инициирован до вызова "конструктора C++).

Как следствие такого "полиморфизма" классов и экземпляров, в Perl не
существует статических методов (класс - это тоже экземпляр), а также
частных методов и полей - в хеше все элементы равны. Впрочем, для
экземпляров первый параметр указывает на self, так что можно это
проверить:

sub {
my $self=shift;
die "non-static method called on class" unless ref $self;
. . .
}


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

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

package GetAviso;
use LWP::UserAgent;
use HTTP::Request;
use HTTP::Response;
sub new {
my $classname=shift;
my $self={};
bless($self,$classname);
$self->{ua}=LWP::UserAgent->new();
$self->{ua}->agent("Aviso Grabber/5.12 Professional");
return $self;
}
sub test {
my $self=shift;
$param=shift;
return "$paramn";
}
sub get {
my $self=shift;
$url=shift;
my $req=HTTP::Request->new(GET=>$url);
$req->referer("http://aviso.ua");
return $self->{ua}->request($req)->content();
}
1;


После такого определения наша программа принимает следующий вид:

#!/usr/bin/perl
use GetAviso;
my $obj=GetAviso->new();
$url="http://aviso.ua/a/Rb.aspx";
print $obj->test($url);
print "$1n" if $obj->get($url)=~/i=(-?d+)a/;


Тут стоит остановиться для нескольких комментариев.

Во-первых, наш модуль больше не исполняемый файл. Из этого три
следствия: не нужна первая строка интерпретатора, бит исполнимого
файла можно опустить и, наконец, имя файла должно соответствовать
соглашениям об именовании модулей. В данном случае, если файл лежит в
том же каталоге, что и приложение, то его имя должно быть GetAviso.pm
(расширение обозначает Perl Module).

Далее: единичка в конце модуля - не опечатка, а "так надо".
Исторически Perl происходит от калькулятора, введя в который
последовательность 2+2< Enter >, вы получали 4. Если ввести 1 - то и
получите 1, так что строка с одной единичкой возвращает ее как
значение. В конце модуля исторически располагается блок инициализации
(вы тоже можете это использовать), который должен вернуть True как
символ того, что инициализация закончилась без проблем,- иначе
возникнет прерывание. А поскольку True в Perl - почти все что угодно
кроме того, что явно False (ноль и т.д.), то можете вместо единицы
записать любое "истинное" выражение, например "Эт0 СуппЕР Модуль";.
Традиционно там единичка.

И третье: не забывайте, что первый < shift > поставит в метод класса
имя пакета, а в экземпляр - указатель self. Это демонстрирует метод
test(). В остальном этот класс не слишком универсален и не очень
сложен - но, например, кэширует экземпляр типа UserAgent в собственном
self-хеше, чтобы не создавать его каждый раз. Главное, что он
действительно скрывает много деталей http-запроса и, кроме того,
демонстрирует технику создания собственных объектов, как и было
обещано.

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

package win2utf;
use Exporter;
use Text::Iconv;
@ISA=('Exporter');
@EXPORT=qw(&win2utf);
sub win2utf {
$inline=shift;
$conv=Text::Iconv->new("windows-1251","utf-8");
return $conv->convert($inline);
}
1;


Делает он следующее - перекодирует символы из win-1251 в utf-8, так
чтобы я мог видеть строки на своей Unicode-консоли. Для этого
используется опциональный модуль Text::Iconv. Вообще-то, под Linux
утилита и интерфейс iconv существуют как штатное средство, а вот
модуль для Perl вам, возможно, придется закачать.

Большего внимания заслуживает то, как наш модуль экспортирует
интерфейс через Exporter (ISA обозначает "is a...", "некий..."). Когда
нам что-то понадобится в нашем пакете, будет вызван win2utf->import().
У нас такого, естественно, нет - так что поиск будет продолжен в
Exporter, а тот уж подсуетит создать для имен из списка @EXPORT
псевдонимы в том адресном пространстве, где мы будем их использовать.
В результате сможем вызывать win2utf без указания имени пакета в
качестве префикса.


Опять к хешам - на этот раз (очень) рекурсивным


Поскольку мы уже зашли в освоении Perl далеко, теперь мои комментарии
будут уменьшаться - а исходники усложняться. Если вы посмотрите на
htmp странички aviso.ua/a/Tr.aspx&i=..., то увидите там несколько
разделов, в которых обнаружите подразделы - и так далее, до тех пор
пока не доберемся к ссылкам на страницы с самими объявлениями.
Поскольку странички-каталоги называются Tr.aspx, а страницы с данными
- Cn.aspx, то и мы будем говорить о Tr-узлах нашего графа и Cn-узлах
(в программе они обозначаются знаками "+" и "-", как принято при
отображении раскрываемых и не раскрываемых узлов).

Для Tr-узлов характерны два атрибута: строка-описание на русском и
идентификатор Id=. Для страничек с данными идентификатор называется
r=, но мы его тоже будем называть ID. Важно: с каждым узлом связаны
другие узлы (массив). Для Cn-узлов также имеет смысл количество
страниц, на которых располагается данный Cn.

В результате код для рекурсивного разбора нашего дерева можно записать
так:

#!/usr/bin/perl
use Storable; use win2utf;
use GetAviso; $obj=GetAviso->new();
$sid=$1 if $obj->get("
1325 Прочтений •  [Разработка Perl скрипта для разбора web-страниц (perl tree web)] [08.05.2012] [Комментариев: 0]
Добавил: Ukraine Vova
Ссылки
HTML: 
[BB Url]: 
Похожие статьи
Название Добавил Добавлено
• Разработка Perl скрипта для разбора... Ukraine Vova 08.05.2012
Ни одного комментария? Будешь первым :).
Пожалуйста, авторизуйтесь для добавления комментария.

Проект входит в сеть сайтов «8Gamers Network»

Все права сохранены. 8Gamers.NET © 2011 - 2025

Статьи
Рецензия на Pressure
Рецензия на Pressure
Чтобы обратить на себя внимание, начинающие маленькие разработчики, как правило, уходят в жанры, ...
Рецензия на Lost Chronicles of Zerzura
Рецензия на Lost Chron...
Игры, сделанные без любви и старания, похожи на воздушный шар – оболочка есть, а внутри пусто. Lo...
Рецензия на The Bridge
Рецензия на The Bridge
«Верх» и «низ» в The Bridge — понятия относительные. Прогуливаясь под аркой, можно запросто перей...
Рецензия на SimCity
Рецензия на SimCity
Когда месяц назад состоялся релиз SimCity, по Сети прокатилось цунами народного гнева – глупые ош...
Рецензия на Strategy & Tactics: World War 2
Рецензия на Strategy &...
Название Strategy & Tactics: World War II вряд ли кому-то знакомо. Зато одного взгляда на ее скри...
Рецензия на игру Scribblenauts Unlimited
Рецензия на игру Scrib...
По сложившейся традиции в информационной карточке игры мы приводим в пример несколько похожих игр...
Рецензия на игру Walking Dead: Survival Instinct, The
Рецензия на игру Walki...
Зомби и продукция-по-лицензии — которые и сами по себе не лучшие представители игровой биосферы —...
Обратная связь | RSS | Донейт | Статистика | Команда | Техническая поддержка