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

среда, 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.

Исследую запрос на сайте. Как видно, это обычный GET-запрос, с ним никаких сложностей не будет. Ввожу слово и исследую html-код для составления регулярки. Регулярные выражения я всегда тестирую с использованием самописной утилитки, о которой я уже писала на блоге.
regexp test

Создаю простую форму, на которой Edit1 - для ввода ключевого слова, SG - TStringGrid для вывода результатов.

Листинг кода получается следующий:

procedure TMainF.btnGETClick(Sender: TObject);
var
HTTP : THTTPSend;
Res : boolean;
S : string;
RE : TRegExp;
mc : MatchCollection;
m : Match;
sm : SubMatches;
i : integer;
begin
HTTP := THTTPSend.Create;
HTTP.UserAgent:= GetRandomUseragent;
try
Res := HTTP.HTTPMethod('GET', 'http://labs.wordtracker.com/keyword-questions/questions?seed='+Edit1.Text+'&commit=Search');
if Res then
begin
case HTTP.Resultcode of
200 :
begin
S := StreamToString(HTTP.Document);
RE := TRegExp.Create(nil);
try
RE.Multiline := true;
RE.Global := true;
RE.IgnoreCase := true;

RE.Pattern := '<tr.*?>[\x0D\x0A]+<td.*?>[\x0D\x0A]+\d*[\x0D\x0A]+</td>[\x0D\x0A]+<td>(.*?)</td>[\x0D\x0A]+<td.*?>(\d*)</td>[\x0D\x0A]+</tr>';
mc := RE.Execute(S) as MatchCollection;
if mc.Count > 0 then begin
for i := 0 to mc.Count - 1 do
begin
m := mc[i] as Match;
sm := m.SubMatches as SubMatches;

SG.RowCount:=SG.RowCount+1;
SG.Cells[0,i+1] := VarToStr(sm[0]);
SG.Cells[1,i+1] := VarToStr(sm[1]);
end;
end;
finally
RE.Free;
end;
end;
end;
end
finally
HTTP.Free;
end;
end;


где:
function StreamToString(aStream: TStream): string;
var
SS: TStringStream;
begin
if aStream <> nil then
begin
SS := TStringStream.Create('');
try
aStream.Position := 0;
SS.CopyFrom(aStream, aStream.Size);
Result := SS.DataString;
finally
SS.Free;
end;
end else
begin
Result := '';
end;
end;

parsing results

Результат представляется в виде конечного списка. Я вывела на форму. Вы можете сохранять в файл или куда угодно.
___

Кто бы что ни говорил, а составление регулярных выражений захватывает похлеще разгадываний судоку. :)

___

Продолжаю возвращать должки за упоминание RSSAdder-a (несмотря на то, что в последнее время заняться им все еще не получается). Сегодня благодарю за упоминания о нем авторов блогов Sibilev.net - Мишкины хроники и Maximum Seo.
___

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

Статьи схожей тематики:



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

  1. В вашем методе форма будет подвисать. Надо выносить в отдельный поток

    ОтветитьУдалить
  2. @Анонимный, это понятно. Я для себя не ставила задачи выкладывать на блоге идеальные готовые решения. Это прототип, просто основа для обучающей статьи. У кого будет желание - доработает по вкусу :)

    ОтветитьУдалить
  3. Классно! Я два дня ломал голову - оказалось [\x0D\x0A] - решение.
    Единственно мне во многих местах пришлось "смазывать" сочетаниями ".*?" - иначе не работало.

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

Комментарии модерируются, вопросы не по теме удаляются, троллинг тоже.

К сожалению, у меня нет столько свободного времени, чтобы отвечать на все частные вопросы, так что, может, свой вопрос лучше задать на каком-нибудь форуме?

Поделиться