Поиск по блогу

Показаны сообщения с ярлыком способы применения парсинга. Показать все сообщения
Показаны сообщения с ярлыком способы применения парсинга. Показать все сообщения

среда, 10 марта 2010 г.

Пример парсинга вопросов с labs.wordtracker.com (Synapse, Delphi)

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

Первым делом посмотрела наработки Сергея (либу IngHTTPSend), предложенные им в комментарии к моей первой статье о Synapse. Безусловно, у него в обертку включены очень полезные функции (в том числе уделено большое внимание кодировкам). Но у каждого программиста есть еще ряд функций, которые он таскает с собой в голове и дописывает к любым своим либам :) Например, у меня есть некоторые заморочки по поводу хэдеров запросов. Я обычно создаю несколько функций для формирования заголовков с одинаковым названием, но с разным набором входных параметров. Например, в функцию может передаваться UserAgent, а может и не передаваться (если не передается, то берется случайный из списка возможных). Обработчики кодов ответа (в частности, 3XX) я тоже обычно выношу.

А потом пришла к выводу, что ни для чего "глубокомысленного" я сегодня не готова, глянула в списочек ссылок ресурсов, подходящих для демонстрации написания простейших парсеров, и решила поместить в блоге пример с кодом парсера вопросов с http://labs.wordtracker.com/keyword-questions/.
parsing keyword SEO questions from wordtracker

Ресурс Wordtracker.com я уже брала в качестве "подопытного" для иллюстрирования возможностей cURL.

Вопросы будем добывать с использованием Synapse.

четверг, 24 декабря 2009 г.

Парсинг findarticles.com - part 2

Итак, следуя инструкциям в предыдущем посте, мы получили список ссылок на статьи. Теперь переходим к самому интересному на мой взгляд — к парсингу текста. Это интересно, но вместе с тем и трудоемко. Бывают ресурсы, на которых все легко и просто разбирается. А бывают и такие, на которых нужно быть внимательной и не полениться просмотреть выборку после первого запуска: вылазят некоторые неучтенные детали, которые нужно дополнительно обработать.

Ресурс findarticles.com как раз поможет мне продемонстрировать ход "изысканий" :)

Открываем любую статью и тщательно вглядываемся в код.

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

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

среда, 18 ноября 2009 г.

Парсинг findarticles.com - part 1

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

Для этих ключевиков, допустим, нам понадобится собрать статьи, им соответствующие (хотя бы отдаленно). Какие-нибудь, без разницы. Я покажу как это сделать, например, с ресурса findarticles.com. Это агрегатор, он сам тянет материал из всевозможных источников, так что от него не убудет :)

Ставим себе задачу.
Имеем: список ключевиков.
Требуется: получить набор текстовых статей. Дополнительное требование: чтобы в каждой статье было не менее определенного числа символов. Это требование возникло из-за того, что на данном агрегаторе много всякого "мусора", могущего состоять из одной строчки, например. А такого добра нам не надо, сразу отсечем этот вариант.

Рассмотрим алгоритм. Можно представить его в двух формах. Первый вариант - это вариант-монолит. То есть в цикле проходим по ключевикам, по каждому ключевику проходим по страницам, попутно на каждой странице собирая статьи. Этот вариант для парсинга большого ресурса не подходит из-за того, что требует стабильности связи на большое время. К тому же потребуется организовать несколько дополнительных настроек, чтобы при повторном запуске скрипт начал парсить не с самого начала, а с того места, на котором остановился.

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

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

вторник, 22 сентября 2009 г.

Примеры применения CURL. Парсинг ключевых слов (буржунет)

Приведу пример парсинга на php. С предыдущими темами пост будет связан способом получения содержимого страницы, то бишь получать ее будем с использованием библиотеки CURL.

Сначала о том, что парсить. А будем парсить ключевики. Но не с гугля, нет. Поищем в интернете какой-нибудь сторонний сервис. Первое, что я нашла, это http://freekeywords.wordtracker.com/. Изучаем страницу. На ней форма. Заполняем, отправляем.


Экспериментируем с adult-фильтром.


Данные передаются GET-запросом, то есть вообще никаких премудростей — просто используем функцию получения контента из предыдущего поста, а потом регуляркой добываем нужные нам данные. Шаблон GET-запроса получаем, введя данные непосредственно в форму на сайте, установив нужное нам значение adult-фильтра и нажав на кнопку. У меня получился следующий шаблон (значение фильтра — по умолчанию):

$url = 'http://freekeywords.wordtracker.com/?seed='.$keyword.'&adult_filter=remove_offensive&suggest=Hit+Me';


(Вместо $keyword будем подставлять ключевик.)

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

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

<?php
function get_web_page( $url )
{
$uagent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)";

$ch = curl_init( $url );
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // возвращает веб-страницу
curl_setopt($ch, CURLOPT_HEADER, 0); // не возвращает заголовки
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); // переходит по редиректам
curl_setopt($ch, CURLOPT_ENCODING, ""); // обрабатывает все кодировки
curl_setopt($ch, CURLOPT_USERAGENT, $uagent); // useragent
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 120); // таймаут соединения
curl_setopt($ch, CURLOPT_TIMEOUT, 120); // таймаут ответа
curl_setopt($ch, CURLOPT_MAXREDIRS, 10); // останавливаться после 10-ого редиректа

$content = curl_exec( $ch );
$err = curl_errno( $ch );
$errmsg = curl_error( $ch );
$header = curl_getinfo( $ch );
curl_close( $ch );

$header['errno'] = $err;
$header['errmsg'] = $errmsg;
$header['content'] = $content;
return $header;
}

// ключевое слово
$keyword = 'finance';
// избавляемся от пробелов, если они есть
$keyword = strtr($keyword, ' ', '+');

$url = 'http://freekeywords.wordtracker.com/?seed='.$keyword.'&adult_filter=remove_offensive&suggest=Hit+Me';

$result = get_web_page( $url );
$err = 0;
if ( $result['errno'] != 0 )
{ //... ошибка: неправильный url, таймаут, зацикливание ... обработать по желанию
$err = 1;
}

if ( $result['http_code'] != 200 )
{ //... ошибка: нет страницы, нет прав ... обработать по желанию
$err = 1;
}

$page = $result['content'];

$a_pattern = '#<a\shref="(\?seed.*?)">(.*?)</a>#sm';
if (preg_match_all($a_pattern, $page,$a_matches, PREG_SET_ORDER))
{
foreach ($a_matches as $a)
echo $a[2].'<br>';
}
else echo 'Ничего не найдено!';
?>


Результат работы скрипта:


Если нам ключевиков надо не сто, а в разы больше, то придется модифицировать алгоритм для рекурсивного прохода по списку ключевиков, полученных на ранних этапах.

Зачем нам нужны эти ключевики? Применение можно найти. Об одном из способов применения расскажу в ближайшем посте.

Если вам понравилась статья, проголосуйте, пожалуйста, за нее на Sloger.net

Чтобы быть в курсе обновлений блога, можно подписаться на RSS.

суббота, 25 июля 2009 г.

Парсинг для начинающих. Практическая работа. Часть II

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

Классы для работы я описала еще в первой части. Небольшие пояснения относительно функций для класса списка компаний (TCompanies).

function IsNewCompany (sLink : string) : boolean;

- проверяет, есть ли уже в списке такая фирма. В качестве параметра — ссылка на информацию о фирме. Листинг:
function TCompanies.IsNewCompany(sLink: string): boolean;
var
i : integer;
tempC : TCompany;
begin
Result := true;
for i := 0 to Count-1 do
begin
tempC := TCompany(Items[i]);
if (tempC.CInfoURL = sLink) then
begin
Result := false;
break;
end;
end;
end;


procedure LoadFromQuery ( Query : TpFIBDataSet );

Листинг:
procedure TCompanies.LoadFromQuery(Query: TpFIBDataSet);
var
tempC : TCompany;
v : Variant;
begin
Query.First;
while (not Query.Eof) do
begin
tempC := TCompany.Create;
v := Query.FieldValues['N'];
tempC.N := Integer(v);
tempC.CName := Query.FieldValues['COMP_NAME'];
tempC.CInfoURL := Query.FieldValues['INFO_URL'];
Add(tempC);
Query.Next;
end;
end;

- для удобства, загрузка из выборки базы. Допустим, парсим всю информацию не за раз, а за несколько (объемы большие, как никак). После первого запуска напарсенные компании складываем в базу. Через день запускаем парсер снова. И, чтобы не парсить информацию о некоторых предприятиях повторно (выдача в список может меняться, простого указания страницы, с которой начинать, - недостаточно), мы загружаем в список уже присутствующие в базе компании. А потом после парсинга перед добавлением проверяем, есть ли компания в списке по InfoURL (с помощью IsNewCompany). После проведения парсинга записываем в базу только новые компании (их можно выделить по отсутствию у них внутреннего идентификатора). Я все записывала в фаербед, но вы с таким же успехом можете все писать в MySQL.

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

В программе будет две основных процедуры. Первая — обход списка предприятий по страницам и сбор названий предприятий и ссылок на более подробную информацию о них, вторая — сбор информации о каждом предприятии.

Принтскрин примерной формы, которая уменя получилась, я приводила в предыдущей части инструкции. Поясню только, что на форме у меня:

cxSpinEdit1 — с какой страницы начинать (нумерация с нуля)
cxSpinEdit3 — по какую страницу
cxSpinEdit2 — таймаут между запросами, в секундах
mLog - TMemo просто для отладки

procedure TMainF.StartParsingHH;
var
i, j, k : integer;
S,
ReqStr,
StrLink : string;
NeedNextPage : boolean;
v : OleVariant;
Doc : IHTMLDocument2;
DocAll,
DocA : IHTMLElementCollection;
DocElement : IHtmlElement;
idHttp1 : TidHttp;
tmpComp : TCompany;
begin
StatusBar.Panels[0].Text := 'Идет парсинг';
for i := 0 to 10 do
begin
Application.ProcessMessages;
Sleep(10);
end;

// цикл по страницам
i := cxSpinEdit1.Value;
NewVacCnt := 0;
NeedNextPage := true;
vStop := false;
while (NeedNextPage) and (not vStop) do
begin
// загрузка страницы
ReqStr := StringReplace(HHCompanyPageURL,'[PageNum]',IntToStr(i),[rfReplaceAll,rfIgnoreCase]);
sLog('log.txt','[HH] ReqStr = '+ReqStr);
NeedNextPage := true;
try
idHttp1 := TidHttp.Create(nil);
idHttp1.Request.UserAgent := 'Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.0.3) Gecko/2008092417 AdCentriaIM/1.7 Firefox/3.0.3';
idHttp1.Request.AcceptLanguage := 'ru';
idHttp1.Request.Referer := 'http://hh.ru';
idHttp1.ConnectTimeout := 5000;
idHttp1.ReadTimeout := 5000;
idHttp1.Response.KeepAlive := true;
idHttp1.HandleRedirects := true;
try
// опущу проверку EIDHttpProtocolException, хотя по правилам надо сделать
S := idHttp1.Get(ReqStr);
except on e : Exception do
begin
sLog('log.txt','[HH] Не удалось скачать страницу '+ReqStr);
sLog('log.txt','Error: '+e.Message);
vStop := true;
end;
end;
S := UTF8ToAnsi(S); // опытным путем мы заметили, что надо поменять кодировку
finally
idHttp1.Free;
end;
// будем работать с DOM
Doc := coHTMLDocument.Create as IHTMLDocument2;
if Doc = nil then
begin
ShowMessage('Ошибка создания IHTMLDocument2');
exit;
end;
v := VarArrayCreate([0,0],VarVariant);
v[0] := S;
Doc.write(PSafeArray(TVarData(v).VArray));

DocAll := Doc.all;
DocA := DocAll.Tags('A') as IHTMLElementCollection;
for k := 0 to DocA.length-1 do
begin
DocElement := DocA.Item(k, 0) as IHtmlElement;
if Pos('/employer/',LowerCase(DocElement.getAttribute('href',0))) > 0 then
begin
// обрабатываем каждую ссылку, убирая about:blank (я уже писала о такой особенности ссылок в IHTMLDocument2, созданном на основе html-кода)
StrLink := 'http://hh.ru'+StringReplace(LowerCase(DocElement.getAttribute('href',0)),'about:blank','',[rfReplaceAll,rfIgnoreCase]);
mLog.Lines.Add(StrLink);
// обрабатываем таблицу выводов результатов
if Companies.IsNewCompany(StrLink) then
begin
tmpComp := TCompany.Create;
tmpComp.CInfoURL := StrLink;
tmpComp.CName := DocElement.innerText;
ExtractHHCompanyInfo(StrLink, tmpComp);
Companies.Add(tmpComp);

if vStop then break;

for j := 0 to cxSpinEdit2.Value*100 do
begin
Sleep(10);
Application.ProcessMessages;
end;
end;
end;
end;
// останавливаем, если i >= cxSpinEdit3.Value
inc(i);
if (i > cxSpinEdit3.Value) and (chbTO.Checked) then
vStop := true;
end;
end;


Процедура сбора информации следующая. На входе - URL страницы с подробной информацией и объект класса TCompany, куда надо записать полученную информацию. Все уже поняли, надеюсь, что я описываю процесс парсинга так, как я привыкла его производить :) Может, кто-то привык по-другому.

procedure TMainF.ExtractHHCompanyInfo(InfoLink: string; vComp : TCompany);
var
S : string;
Doc : IHTMLDocument2;
v : OleVariant;
DocAll,
DocDIV : IHTMLElementCollection;
DocElement : IHTMLElement;
i : integer;
idHttp1 : TidHttp;
isError : boolean;
begin
// извлечение информации о компании
try
isError := false;
idHttp1 := TidHttp.Create(nil);
idHttp1.Request.UserAgent := 'Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.0.3) Gecko/2008092417 AdCentriaIM/1.7 Firefox/3.0.3';
idHttp1.Request.Referer := 'http://hh.ru';
idHttp1.Request.AcceptLanguage := 'ru';
idHttp1.Response.KeepAlive := true;
idHttp1.HandleRedirects := true;
try
try
// опущу проверку EIDHttpProtocolException, хотя по правилам надо сделать
S := idHttp1.Get(InfoLink);
except
sLog('log.txt','Не удалось загрузить страницу с адресом'+#13#10+InfoLink);
isError := true;
end;
S := UTF8ToAnsi(S);
finally
idHttp1.Free;
end;
if isError then exit;

Doc := coHTMLDocument.Create as IHTMLDocument2;
if Doc = nil then
begin
ShowMessage('Ошибка создания IHTMLDocument2');
exit;
end;
v := VarArrayCreate([0,0],VarVariant);
v[0] := S;
Doc.write(PSafeArray(TVarData(v).VArray));

DocAll := Doc.all;
DocDIV := DocAll.Tags('DIV') as IHTMLElementCollection;
for i := 0 to DocDIV.length-1 do
begin
DocElement := DocDIV.Item(i, 0) as IHtmlElement;

if (LowerCase(trim(DocElement.className)) = LowerCase('b-employerpage-url')) then
vComp.CURL := DocElement.innerText;

if (LowerCase(trim(DocElement.className)) = LowerCase('g-user-content b-employerpage-desc')) then
begin
vComp.CInfo := DocElement.innerText;
// почистим результат от всяких "левых" символов
vComp.CInfo := StringReplace(vComp.CInfo,'&ndash;','-',[rfReplaceAll,rfIgnoreCase]);
vComp.CInfo := StringReplace(vComp.CInfo,'&laquo;','"',[rfReplaceAll,rfIgnoreCase]);
vComp.CInfo := StringReplace(vComp.CInfo,'&raquo;','"',[rfReplaceAll,rfIgnoreCase]);
vComp.CInfo := StringReplace(vComp.CInfo,'&nbsp;',' ',[rfReplaceAll,rfIgnoreCase]);
vComp.CInfo := StringReplace(vComp.CInfo,'&bull;','-',[rfReplaceAll,rfIgnoreCase]);
end;
end;

except
end;

if not vStop then
for i := 0 to cxSpinEdit2.Value-1 do
begin
Application.ProcessMessages;
Sleep(1000);
end;
end;


Небольшие пояснения. Я здесь использовала DOM. Это быстро и удобно. Тем более, что парсить такую информацию регулярками - совсем неудобно. Ссылку на сайт компании можно легко получить, взяв innerText элемента div класса "b-employerpage-url" (он такой один на всю страницу всем нам на благо). А подробную информацию можно получить, взяв innerText элемента с классом "g-user-content b-employerpage-desc". Чистим результат от символов, встречающихся в результате. Например, заменяем '&ndash;' на '-', '&laquo;' и '&raquo;' на '"' и т.д.. Необходимость этого выявляется уже чисто на практике: пробуем парсить страничку, смотрим результаты и делаем выводы.

Вот, в принципе, и все.

Что касается меня — я вернулась из отпуска, порядком отдохнувшей, загорелой и соскучившейся по интернету :) Скоро вольюсь в привычный ритм работы и придумаю что-нибудь еще ;D

Кстааати! Чтобы быть в курсе обновлений блога, можно подписаться на RSS. :)

понедельник, 6 июля 2009 г.

Парсинг для начинающих. Практическая работа. Часть I

До начала второй части отпуска осталось 4 дня. Использую это время с пользой — напишу статью на блог. :)

Итак, долой теорию, переходим к практике парсинга. Соберем с какого-нибудь сайта структурированную информацию. Исходя из того, что для примера структура должна быть простой, я выбрала обредший небывалую популярность во время кризиса сайт по поиску работы hh.ru. Еще мой выбор обоснован тем, что с этим сайтом я довольно-таки давно и тесно "работаю" :D. Парсить в этот раз мы будем не вакансии, а информацию о предприятиях.

По ссылке http://hh.ru/employersList.do можно увидеть список компаний, имеющих на данный момент открытые вакансии. Отметив чекбокс "Показать компании, у которых нет открытых вакансий" и нажав на кнопку "Найти" получаем список всех предприятий (на момент написания статьи — 76 101). База немаленькая. Если парсить в один поток и делать перерыв между загрузками 2 секунды, то процесс займет около двух суток.

Рассмотрим структуру выдачи. Get-запрос будет следующим:

http://hh.ru/employersList.do?letter=&employerName=&areaId=113&companyWithoutVacancy=on&page=[PageNum]


[PageNum] — номер страницы. Нумерация начинается с нуля.

Необходимая нам информация о предприятии:
- название;
- ссылка на сайт;
- описание предприятия;
- ссылка на источник информации.

Последний пункт — URL страницы, с которой берется информация (ссылка вида http://hh.ru/employer/[ID]). Мы будем парсить постранично список с предприятиями, потом заходить по каждой ссылке и брать подробную информацию. "Почему такой способ, а не перебор всех ID по порядку в ссылке http://hh.ru/employer/[ID]?" — спросите вы. Отвечу: "Да потому, что это менее затратно". Идентификаторов гораздо больше, чем "действующих" ссылок (например, наберите http://hh.ru/employer/4 — увидите своими глазами, что предприятия с таким ID не существует).

Итак, алгоритм:
1) скачиваем первую страницу списка фирм;
2) находим все ссылки на предприятия;
3) если ссылки есть - заходим по каждой ссылке и получаем детальную информацию, записываем; если ссылок нет — заканчиваем работу;
4) загружаем следующую по счету страницу;
5) повторяем пункты 2 — 4.

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

Как находить ссылки на предприятия? Способов тоже несколько:
1) в содержимом страницы по регулярному выражению;
2) просмотреть весь массив ссылок, найденный через DOM, и отобрать ссылки, начинающиеся с "/employer/".

По каждой найденной ссылке зайти и найти информацию о компании + адрес сайта. Полученные результаты сохранить. Тут уж кто как привык. Можно сразу в базу. Мне, допустим, удобней и привычней записать сначала все в List, а потом уже с ним делать все, что угодно.

Для компаний я создала класс TCompany:

type
TCompany = class
N : integer;
CName,
CURL,
CInfoURL,
CInfo : string;
end;

TCompanies = class (TList)
function IsNewCompany (sLink : string) : boolean;
procedure LoadFromQuery ( Query : TpFIBDataSet );
destructor Destroy; override;
end;


TCompanies — класс для работы со списком предприятий.

Интерфейс получился такой:
parsing hh.ru

Продолжение следует.

Чтобы быть в курсе обновлений блога, можно подписаться на RSS.

среда, 4 февраля 2009 г.

Общие слова о парсинге сообщений с форумов

Давно не обновляла блог, так как во всю занимаюсь непосредственно программированием и на писанину лишнего времени нет.

Этот материал я подготовила в рамках ряда статей по теме автоматизации первоначального наполнения форумов. В последнее время на фрилансе часто появляются проекты по наполнению форумов. За один пост предлагают смешные цены — $0,03 - $0,05. Но еще более смешным является то, что исполнители на такие проекты находятся. Уж не знаю, то ли на них как-то по-особому отразился кризис, то ли они готовы на все за отзыв. В любом случае, ручное выполнение такой работы — труд неблагодарный. А вот автоматизировать этот процесс — еще какой благодарный! ;)

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

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

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

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



На следующем этапе парсится содержимое форума и сохраняется в базе. Алгоритм обхода форума интуитивно прост. С главной страницы в базу заносятся все разделы, потом обходим все разделы для сбора тем и сообщений в каждой теме.

После того, как все сообщения оказались у вас в руках, можно приступать к подготовке данных для размещения на ваш форум. Если форум ваш собственный, то регистрируете банду ботов напрямую инсертами в базу (ники, аватары, краткая информация). Если же форум не ваш — все это проделываете вручную. Темы и сообщения изменяются и импортируются в определенном формате в файлы. В отдельный файл импортируются данные о юзерах/паролях, от лица которых будет осуществляться постинг. Сообщения будут появляться на форуме постепенно, по расписанию. Это создаст иллюзию реального общения стабильной аудитории. А если темы будут интересными — новые пользователи не замедлят подтянуться. Еще один важный момент, который я предусматривала при разработке, — как можно более широкие возможности по управлению контентом на стадии подготовки к постингу. Каждое сообщение можно менять вручную (после изменения оно помечается и вы всегда видите, что меняли, а что нет), исходная спарсенная ветка остается в оригинале, а для постинга готовится ее копия, так что можно менять и не бояться :) Так же можно в любое место добавить произвольные сообщения или удалить из списка ненужные.

Подробнее о форматах и механизме постинга напишу потом.
___

Чтобы быть в курсе обновлений блога, можно подписаться на RSS.

вторник, 6 января 2009 г.

Создание карты блога на blogspot.com своими руками

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

Чтобы создать карту блога на blogspot.com (я рассматриваю в качестве примера свой лытдыбровый блог), можно воспользоваться головой и данными из виджета "Архив блога". Изучим код страницы. Виджет оформлен как div с id='ArchiveList'. Внутри дива — ненумерованный список. Элементы UL, группирующие ссылки по месяцам, имеют classname='posts'. Сразу становится понятно, что для создания карты сайта достаточно будет выбрать все элементы LI, находящиеся внутри упомянутых UL. Это делается в два счета при работе с MSHTML.

Обработчик кнопки "Start":

procedure TBlogspotSiteMapF.btnStartClick(Sender: TObject);
var
Doc : IHTMLDocument2;
DocAll,
DocLi : IHTMLElementCollection;
ParentElement,
DocElement : IHtmlElement;

i : integer;
begin
WebBrowser.Navigate(edtURL.Text);
while WebBrowser.ReadyState <> READYSTATE_COMPLETE do
begin
Application.ProcessMessages;
end;

Doc := WebBrowser.Document as IHTMLDocument2;
if Assigned(Doc) then
begin
DocAll := Doc.all;
DocLi := DocAll.Tags('LI') as IHTMLElementCollection;

for i := 0 to DocLi.length-1 do
begin
DocElement := DocLi.Item(i, 0) as IHtmlElement;
ParentElement := DocElement.parentElement;

if ParentElement.className = 'posts' then
Memo.Lines.Add(DocElement.innerHTML);
end;
end;
end;


В результате получаем такую картину:



После парсинга первоначального списка обнаружились некоторые ньюансы. А именно: записи, имеющие слишком длинные названия, обрезаются по количеству символов (на рисунке для примера я обвела красным ссылку и пример заголовка одного из таких сообщений). Но это не страшно и вопрос решается очень просто: надо скачать страницу по ссылке и достать из html-кода полный заголовок (внутри h3 с classname = 'post-title entry-title'). В принципе, я думаю, что данная процедура необязательна, так как карты сайтов используются в основном поисковиками. Тем более, что если записей в блоге очень много — это мероприятие может оказаться затратным :)



Чтобы быть в курсе обновлений блога, можно подписаться на RSS.

вторник, 23 декабря 2008 г.

Программный кликер

Хочу рассказать еще один случай, когда парсинг помог мне в автоматизации. На этот раз — в автоматизации кликинга. Я уже говорила, что когда-то "продвигала" свой город на MyMiniCity.com. Когда я начала искать информацию по поводу "продвижения" в онлайн-играх, нашла несколько кликообменников.

Что из себя представляет кликообменник? Пользователь регистрируется, в своем профиле указывает одну или несколько ссылок, на которые нужно кликать другим. Потом через интерфейс получает доступ к ссылкам других зарегистрированных пользователей. За каждый клик по чужой ссылке тебе начисляются "кредиты", за каждый клик по твоей ссылке "кредиты" списываются со счета. В итоге, чем больше ты кликнешь по чужим ссылкам, тем больше кликнут по твоим. Каждый пользователь по одной ссылке может кликнуть только раз в сутки, но на популярных кликообменниках количество пользователей очень большое, поэтому в день выходило около двух тысяч кликов по моей ссылке — и мой город рос, как на дрожжах. У вас возник вопрос, не заколебалась ли я день напролет кликать? Ответ: не заколебалась, так как после недели кликинга поняла, что надо все автоматизировать, иначе, — как в одной из серий "Саус Парка", — у меня не будет никакой личной жизни :)

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

Такую программу написать достаточно просто. Реализацию всех действий по-отдельности я уже разбирала в этом блоге: заполнение и сабмит формы, получение содержимого страницы, поиск ссылок по шаблону, открытие ссылок с использованием TWebBrowser. Так что при желании трудностей возникнуть не должно. А здесь — просто показала еще одно направление для написания программ web-автоматизации.

yarold clicker

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

———
Напоминаю: чтобы быть в курсе обновлений блога, можно подписаться на RSS.

Напоминаю так же, что принимаю заказы на парсинг и разработку программ по автоматизации различных действий (например, рассылка сообщений и т.д., все обсуждаемо). Варианты обмена ссылками с тематическими блогами/сайтами тоже с удовольствием рассмотрю. :)

среда, 10 декабря 2008 г.

Парсинг на службе у геймера

Парсингу можно найти применение не только для получения контента. Сегодняшний мой рассказ будет связан с автоматизацией "прокачки" объекта в одной браузерной игре.

В последнее время в сети появилось огромное множество браузерных игр разных типов. В конце прошлого года, когда появился портал MyMiniCity, я построила себе там город NewYorg (кто сидит по траффику — лучше не заходить :) ). Суть игры заключается в том, что надо "построить" свой виртуальный город. Подробно расписывать не буду, так как уже писала про эту игру. Поигравшись пару месяцев, вручную заходя в другие города и оставляя на доске приглашения посетить Newyorg, решила все автоматизировать. Тогда и была написана программа, которая посещает города на MyMiniCity.com, заполняет поля, отгадывает капчу и сабмитит форму. Надо было только подсунуть программе файл со списком городов. Таким образом я выводила город достаточно высоко в рейтинге (но потом мне стало лень даже запускать программу :) ).

Вот для создания списка городов я и использовала парсинг. Проанализировав код страницы, нашла, что список части городов, выведенных в рейтинге в правой части, в коде представлен в определенном формате. На каждой странице с городом есть строка типа:

ranking=145,flycity.de|146,ssv-city|147,join|148,seti.germany|149,krokant|150,demonslayers|151,maschboard


Оставалось только распарсить строку, добавить города в список и перейти к последнему (или первому, в зависимости от направления обхода) городу. Список городов можно было представить в формате, который подходит для программы обхода городов MMCVisitor :)

myminicity parser

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

Поделиться