Регистрация | Вход
[ Главная · Новые сообщения ]
  • Страница 1 из 1
  • 1
Форум » Основной раздел » Мастерская » Шаблон для инет-скриптов
Шаблон для инет-скриптов
Vladislav 06.01.11 20:30 #1
Ранее уже выкладывал этот шаблон в скриптах, но по каким-то причинам был удалён, и вот новая версия вполне работоспособна.

Типа инструкция

Сейчас мы сделаем скрипт pritcha.tcl который будет выводить притчи на канал:
1. открываем template.tcl, редактируем шапку скрипта.
2. заменяем везде template на pritcha
3. в variable pub:pritcha "$unamespace шаблон" заменяем шаблон на притча
4. в variable fetchurl "http://сайт" указываем ссылку http://pritchi.ru/id_
5. заменяем строку:
Код
lput puthelp "Формат: $::gprefix(1)pritcha - описание." $prefix ; return

на:
Код
lput puthelp "Формат: $::gprefix(1)притча - выводит случайную притчу." $prefix ; return

6. в данном случае для того чтобы получать случайную притчу нам нужно открывать страничку со случайным числом на конце, для этого строку:
Код
set aurl ""

заменяем на:
Код
set aurl [expr [rand 6000]+1]

7. парсер. Указываем ту часть кода странички которая нас интересует
Код
if {[regexp -nocase -- { к о д } $str garb text]} {

заменяем на:
Код
if {[regexp -nocase -- {<h1>(.*?)</h1>.*?<p>(.*?)<div class="additional">} $str garb text text2]} {

(.*?) - это название притчи (text)
(.*?) - это сама притча (text2)

8. вставляем ниже:
Код
regsub -all -nocase -- {<p>|<br />} $text2 " " text2
regsub -all -nocase -- {<i>|</i>} $text2 "\002" text2

Это своего рода замена html кода на IRC, мы <p> <br /> <i> </i> заменили на пробел и выделение жирным.

9. изменяем вывод информации, а именно:
Код
put putserv "[sspace [sconv $text]]" $prefix

заменим на:
Код
lput putserv "$::gcolor(5):: [sspace [sconv $text]]" $prefix
lput putserv "[sspace [sconv $text2]]" $prefix

Получим в одной строке название притчи, а с новой строки саму притчу. sspace - убирает лишние пробелы, sconv - заменяет различные html-символы, ниже, в самой процедуре sconv их можно дополнить.

P.S: если нужно текст свыше 2 строк отправлять не на канал, а в приват, дабы не флудить, надо раскоментировать:
Код
#if {[string length $str] > 800 && $uchan ne $unick} {set prefix [subst -noc $msgsend]}

P.S.S: если кодировка сайта не cp1251 то указывает ту кодировку в:
Код
if {[info exists ::sp_version]} {set str [encoding convertfrom cp1251 $lbody]} {set str $lbody]]}


Пример работы скрипта pritcha.tcl:
Цитата
<Vladislav> !притча
<Windrop> :: Кто больше?
<Windrop> Вечером над лесом поднялась полная Луна. — Посмотрите, какая я большая! — сказала Луна. — Я больше Солнца, потому что прогнала его с небосвода. — Да, это так! — подтвердила одноглазая Ворона, сидевшая на дереве у болота. К полуночи Луна отразилась в маленькой Лужице. Тогда болотная Лужица обрадовано воскликнула: — Смотрите, а я, оказывается, больше Луны! Луна полностью уместилась в моих берегах, да ещё осталось достаточно
<Windrop> места для звёзд. — Да, это верно, — согласилась одноглазая Ворона и принялась размышлять. — Если Луна, отразившись в тебе, уместилась в твоих берегах, и осталось ещё место для звёзд, ты больше неё. Но мой глаз больше тебя. — Это каким образом? — спросила болотное Лужица. — Очень просто, — ответила одноглазая Ворона. — Ты, Лужица, умещаешься в моём глазу вместе с Луной и звёздами, да ещё остается место, чтобы уместить
<Windrop> всё болото. Бельмо, сидевшее на левом глазу Вороны, важно сказало: — Самое большое в мире — это я. Стоит мне пересесть на твой правый зрячий глаз, Ворона, и я закрою не только Лужицу с Луной, но и весь мир. — Да, это правда, — ещё раз согласилась Ворона. — Ты, Бельмо, самое большое в мире.
<Vladislav> !притча
-Windrop- пожалуйста повторите попытку позже. Сервис будет доступен для использования через 6 сек.


Цитата
<Vladislav> !притча #windrop 5
-Windrop- Включен автоматический постинг в канал #windrop (раз в 5 мин.)


Если бот перезагружался, то автоматический вывод начнётся после команды !притча.

Цитата
<Vladislav> !притча #windrop 0
-Windrop- Выключен автоматический постинг в канал #windrop
template.tcl (15.0 Kb)
Vladislav 12.07.11 11:45 #2
Ещё один вариант более простой и менее функциональный, однако может чему-то научить.

В качестве примера будем забирать статистику форума - http://city.is74.ru/forum/forum.php

Цитата
Тем: 78,887 Сообщений: 3,300,923 Пользователи: 31,608 Активные участники: 10,125


Начнем с бинда команды которая будет вызывать процедуру парсинга:

Код
bind pub - !статфорум parsing


Ну и сама процедура:

Код
proc parsing {nick uhost hand chan text} {
....Далее мы будем сюда записывать код....
}


Следующей строкой в процедуре указываем юзерагент с которым бот будет конектиться к сайту. В ::http::config может быть много параметров, но пока нам это не надо.

Код
::http::config -useragent "Mozilla/4.0 (compatible; MSIE 4.01; Windows CE; PPC; 240x320)"


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

Код
set parsing_tok [::http::geturl "http://city.is74.ru/forum/forum.php" -timeout 20000]


Тут в переменную data мы получаем содержимое нашей страницы без переноса строк и прочей ненужности:

Код
set data [regsub -all -- {\n|\r|\t|\v} [::http::data $parsing_tok] ""]


И удаляем переменные более не используемые в токене:

Код
::http::cleanup $parsing_tok


На этом этапе стоит обратить своё внимание на кодировку сайта (добавим строку "return $data" для того чтоб увидеть сайт так как видет его бот), если выводит криво, то указываем кодировку, например:

Код
set data [encoding convertfrom cp1251 $data]


В нашем случае сайт попался не вредный и вот тот участок кода который нам и нужен:



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

Код
if {[regexp -nocase -- {<dl>(.*?)</dl>} $data -> data]} {
....Далее мы будем сюда записывать код....
} {putserv "NOTICE $nick :Ошибка парсинга."}


Добавим строку "return $data" и посмотрим то ли мы взяли:



То что нужно! Теперь надо обработать код и можно выводить результат, но тут есть у нас два варианта: вырезать лишнее либо взять только нужное. Второй вариант будет более прихотлив к коду и чаще будет "ломаться" скрипт. Рассмотрим оба способа, но для итога возьмём первый. И так начнём:

Убираем из кода теги <dt> и </dt>:

Код
regsub -all -- {<dt>|</dt>} $data "" data


Заменяем <dd> и </dd> на пробел и убираем лишние пробелы:

Код
regsub -all -- {<dd>|</dd>} $data " " data
regsub -all -- {\s+} $data " " data


На этом первый способ закончен переходим к рассмотрению второго:

Убираем лишние пробелы:

Код
regsub -all -- {\s+} $data " " data


Добавляем проверку с присвоением переменной нужным нам данным. Первая (.*?) = tdata, вторая (.*?) = sdata и тд:

Код
if {[regexp -nocase -- {<dt>Тем</dt><dd>(.*?)</dd><dt>Сообщений</dt><dd>(.*?)</dd><dt>Пользователи</dt><dd>(.*?)</dd> <dt>Активные участники</dt> <dd>(.*?)</dd>} $data -> tdata sdata pdata adata]} {
....Далее мы будем сюда записывать код....
} {putserv "NOTICE $nick :Ошибка парсинга (2)."}


Соберём в одну переменную то, что у нас получилось:

Код
set data "Тем $tdata Сообщений $sdata Пользователи $pdata Активные участники $adata"


На этом второй способ заканчиваем. Добавим строку "return $data" и посмотрим что у нас получилось:

Цитата
Тем 78,889 Сообщений 3,300,866 Пользователи 31,610 Активные участники 10,144


Замечательно, в обоих случаях у нас один результат. Не забываем убирать после просмотра return $data.

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

Код
putserv "PRIVMSG $chan :[string trim $data]"


Вот что у нас получилось:

Код
bind pub - !статфорум parsing

proc parsing {nick uhost hand chan text} {     
::http::config -useragent "Mozilla/4.0 (compatible; MSIE 4.01; Windows CE; PPC; 240x320)"
set parsing_tok [::http::geturl "http://city.is74.ru/forum/forum.php" -timeout 20000]
set data [regsub -all -- {\n|\r|\t|\v} [::http::data $parsing_tok] ""]
::http::cleanup $parsing_tok

if {[regexp -nocase -- {<dl>(.*?)</dl>} $data -> data]} {     
regsub -all -- {<dt>|</dt>} $data "" data
regsub -all -- {<dd>|</dd>} $data " " data     
regsub -all -- {\s+} $data " " data
putserv "PRIVMSG $chan :[string trim $data]"
} {putserv "NOTICE $nick :Ошибка парсинга."}

}


Проверить можно данный скрипт (немного урезан для того чтоб уместился в строке) прямо на канале:

Цитата
<Vladislav> !tcl ::http::config -useragent "Mozilla/4.0"; set parsing_tok [::http::geturl "http://city.is74.ru/forum/forum.php" -timeout 20000]; set data [regsub -all -- {\n|\r|\t|\v} [::http::data $parsing_tok] ""]; ::http::cleanup $parsing_tok; regexp -nocase -- {<dl>(.*?)</dl>} $data -> data; regsub -all -- {<dt>|</dt>} $data "" data; regsub -all -- {<dd>|</dd>} $data " " data; regsub -all -- {\s+} $data " " data; return $data

<Windrop> [RETURN 1588.153ms] Тем 78,889 Сообщений 3,300,820 Пользователи 31,610 Активные участники 10,144
3636930.jpg (40.2 Kb) · 7250877.jpg (16.4 Kb)
Vladislav 12.07.11 13:20 #3
Давайте рассмотрим несколько примеров регулярных выражений которые помогут нам избавиться от мусора в коде при парсинге:

Данным примером мы вырезаем все теги:

Код
regsub -all -- {<.*?>} $t {} t


Цитата
<Vladislav> !tcl set t {</table><a class="forumBar" href="http://windrop.clan.su/forum/12">Мастерская</a><br>}; regsub -all -- {<.*?>} $t {} t; return $t

<Windrop> [RETURN 0.047ms] Мастерская


А тут мы выносим результат для редактирования:

Код
regsub -all -nocase -- {<.*?>(.*?)</.*?>} $t "\\1" t


Цитата
<Vladislav> !tcl set t {<a class="forumBar" href="http://windrop.clan.su/forum/12">Мастерская</a>}; regsub -all -nocase -- {<.*?>(.*?)</.*?>} $t "~\\1~" t; return $t

<Windrop> [RETURN 0.037ms] ~Мастерская~


Заменяем теги на то, что нам нужно:

Код
regsub -all -nocase -- {<br.*?>} $t { } t
regsub -all -nocase -- {<b>|</b>} $t "\002" t


Цитата
<Vladislav> !tcl set t {Бот<br><b>Мастерская</b><br />Немного о IRC}; regsub -all -nocase -- {<br.*?>} $t { } t; regsub -all -nocase -- {<b>|</b>} $t "\002" t; return $t

<Windrop> [RETURN 0.046ms] Бот Мастерская Немного о IRC


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

Код
regsub -all -nocase -- {&#([0-9]{1,5};);} $t {} t


Цитата
<Vladislav> !tcl set t {&#З9;Мастерская&#З9;}; regsub -all -nocase -- {&#([0-9]{1,5};);} $t {} t; return $t

<Windrop> [RETURN 0.101ms] Мастерская


Пример обрезки в начале и в конце (тоже самое что string trim если целью являются пробелы):

Код
regsub -all {^\s+} $t "" t
regsub -all {\s+$} $t "" t


Цитата
<Vladislav> !tcl set t { Мастерская }; regsub -all {^\s+} $t "" t; regsub -all {\s+$} $t "" t; return $t

<Windrop> [RETURN 0.029ms] Мастерская


Бывает так, что в коде то есть ковычки то их нет:

Код
regsub -all -nocase -- {<div class="?edited"?>(.*?)</div>} $t "\\1" t


Цитата
<Vladislav> !tcl set t {<div class="edited">Мастерская</div>}; regsub -all -nocase -- {<div class="?edited"?>(.*?)</div>} $t "\\1" t; return $t
<Windrop> [RETURN 0.063ms] Мастерская

<Vladislav> !tcl set t {<div class=edited>Мастерская</div>}; regsub -all -nocase -- {<div class="?edited"?>(.*?)</div>} $t "\\1" t; return $t
<Windrop> [RETURN 0.071ms] Мастерская


Ну и здесь же рассмотрим string map (не копировать коды, для отображения их здесь заменены буквы):

Код
set t [string map -nocase {{&mdаsh;} {-} {&quоt;} {"}} $t]


Цитата
<Vladislav> !tcl set t {&quоt;Мастерская &mdаsh; Vladislav&quоt;}; set t [string map -nocase {{&mdаsh;} {-} {&quоt;} {"}} $t]; return $t

<Windrop> [RETURN 0.035ms] "Мастерская - Vladislav"
Vladislav 31.07.11 14:36 #4
Эта процедура поможет избежать многократного переписывания однотипных строк. Загрузите ее отдельным скриптом и обращайтесь к ней:

Код
set data [web2data $url $nick]


В случае каких-либо ошибок процедура вернет 0 и напишет об ошибке указанному нику, если ошибок нет, то вернется HTML код страницы.

Код
proc web2data {url nick} {
# Указываем юзерагент с которым бот будет конектиться к сайту:
::http::config -useragent "Mozilla/4.0 (compatible; MSIE 4.01; Windows CE; PPC; 240x320)"
# Отправляем http запрос, указываем таймаут и используем catch для того, чтобы избежать остановки выполнения процедуры в случае проблем связи с сайтом или ошибок:
if {[catch {set token [::http::geturl $url -timeout 10000]} error]} {putserv "NOTICE $nick :Ошибка: $error"; return 0
# Если указанный адрес не существует:
} elseif {[::http::ncode $token] == "404"} {putserv "NOTICE $nick :Ошибка: [::http::code $token]"
# Проверяем статус запроса, если все хорошо, то в переменной data оказывается код страницы:
} elseif {[::http::status $token] == "ok"} {set data [regsub -all -- {\n|\r|\t|\v} [::http::data $token] ""]
# Если время соединения превышено, то пишем об этом:
} elseif {[::http::status $token] == "timeout"} {putserv "NOTICE $nick :Ошибка: Таймаут соединения."
# Тоже самое с остальными ошибками:
} elseif {[::http::status $token] == "error"} {putserv "NOTICE $nick :Ошибка: [::http::error $token]"}
# И наконец, освобождаем переменные токена для последующих операций:
if {[info exists data]} {::http::cleanup $token; return [regsub -all -- {\s+} $data " "]} else {::http::cleanup $token; return 0}
}
Vladislav 10.01.14 04:15 #5
Максимально короткий пример получения данных с сайта:

Код
!tcl regexp -- {id="info32".*?Version: (.*?). Released: (.*?)</p>.*?<a href="(.*?)"} [::ccs::get_httpdata http://steelseries.com/support/downloads] -> v d u; return "\037[join [lreverse [split $d -]] .]\037-> версия: $v \002@\002 $u"

06.11.2013-> версия: 2.8.0171 @ http://cdn-co.steelseries.com/downloads/drivers/engine/SteelSeriesEngine_2.8.0171.exe


В данном примере мы ещё поработали с датой, изначально она была: 2013-11-06
Форум » Основной раздел » Мастерская » Шаблон для инет-скриптов
  • Страница 1 из 1
  • 1
Поиск: