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

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

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

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

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

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

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

yarold clicker

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

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

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

четверг, 18 декабря 2008 г.

RSS в виде дерева (TTreeView в Delphi)

Приятно, когда есть обратная связь с блога. Когда уточняют что-либо или задают вопросы. Поэтому в продолжение к статье об отображении XML в виде дерева напишу еще эту — об отображении RSS в TreeView.

Про структуру RSS я уже писала. Задача сводится к малому: пройтись по всем записям, разобрать их элементы и представить в виде дерева "Адрес RSS — Записи".

Для достижения своих целей будем оперировать данными типов IXMLNode и IXMLNodeList.

nd : IXMLNode;
firstTier : IXMLNodeList;


DocumentElement — возвращает корневой объект документа.
childNodes — возвращает список прямых потомков вершины. Далее с дочерними узлами можно работать просто как с элементами списка. Например, узнать имя узла, можно будет firstTier[i].NodeName.

Итак, исследуем код RSS-фида, который генерируется feedburner-ом. Видим, что самый простой способ получить все записи, — это из списка узлов первого уровня выбрать узлы с именем entry, а потом каждый из этих узлов обработать (выделить нужные нам дочерние узлы content, published (дата публикации) и link (у узла link нам понадобится значение атрибута href)).


XMLDocument1.FileName := 'MyRSSFeed.xml';
XMLDocument1.Active := true;

nd := XMLDocument1.DocumentElement;

TreeView1.Items.AddChild(nil,edtRSSURL.Text);
firstTier := nd.childNodes;
for i := 0 to firstTier.Count-1 do
begin
if firstTier[i].NodeName = 'entry' then
begin
nd := firstTier[i];
ProcessItem();
end;
end;


Что касается обработки записей. Все просто со значениями узлов с именами content и published, так как такие узлы встречаются один раз. А вот узлов с именем link встречается несколько.

<link rel="replies" type="application/atom xml" href="http://mama-karlo.blogspot.com/feeds/6599339245902184370/comments/default" title="..." />
<link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=29395559131211965&amp;postID=6599339245902184370" title="..." />
<link rel="edit" type="application/atom xml" href="http://www.blogger.com/feeds/29395559131211965/posts/default/6599339245902184370?v=2" />
<link rel="self" type="application/atom xml" href="http://www.blogger.com/feeds/29395559131211965/posts/default/6599339245902184370?v=2" />
<link rel="alternate" type="text/html" href="http://mama-karlo.blogspot.com/2008/12/blog-post_16.html" title="..." />


Нам нужно выбрать только тот узел, у которого значение атрибута rel равно alternate. В итоге получаем код:

type
PRSSFeedData = ^TRSSFeedData;
TRSSFeedData = record
URL : string;
Description : string;
Date : string;
end;

procedure ProcessItem();
var
rssFeedData : PRSSFeedData;
tn : TTreeNode;
title : string;
j : integer;
begin
New(rssFeedData);

title := nd.ChildNodes.FindNode('title').Text;

with nd.ChildNodes do
begin
rssFeedData.Description := FindNode('content').Text;
rssFeedData.Date := FindNode('published').Text;
end;

for j := 0 to nd.ChildNodes.Count-1 do
if (nd.ChildNodes[j].NodeName = 'link') and (nd.ChildNodes[j].GetAttribute('rel') = 'alternate') then
begin
rssFeedData.URL := nd.ChildNodes[j].GetAttribute('href');
break;
end;

tn := TreeView1.Items.AddChild(TreeView1.Items.GetFirstNode, title);
tn.Data := rssFeedData;
end;


Вот небольшое приложение, на примере которого можно поразбираться, как все работает.
RSS-feed in TreeView, Delphi

Исходники можно скачать здесь.

P.S. Спасибо благодарным читателям, которые шлют на пиво! %D

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

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

понедельник, 8 декабря 2008 г.

Отображение XML в виде дерева (TreeView): Delphi

Во многих программах конфиги хранятся в файлах формата XML. Встала задача — отобразить XML в виде дерева.

Создаем форму, на которой обязательно должны присутствовать кнопка открытия файла (и OpenDialog, соответственно) и TreeView. Остальное — опционально.
delphi xml editor

Подключаем библиотеки XmlDoc, XMLIntf (про XMLIntf, возможно, напишу отдельным постом).

Объявляем класс TNodeRec.

type
TNodeRec = class
TreeNode : TTreeNode;
XMLNode : iXMLNode;
end;


Переменные:

var
XDoc : TXMLDocument;
FName : String;
bkpXml : String;
CurrNode,
ClipboardNode : iXMLNode;


Функции:


function GetPathByNodeIdx (T : TTreeNode) : TStringList;
begin
Result:= TStringList.Create;
if T=nil then exit;
while T.Parent<>nil do
begin
Result.Insert(0,IntToStr(integer(T.Data)));
T:=T.Parent;
end;
Result.Insert(0,IntToStr(integer(T.Data)));
end;

function SetXmlPosByPathIdx (aSL: TStringList; aXmlDocument : TXMLDocument) : IXMLNode;
var
i : integer;
iNODE : IXMLNode;
begin
iNode:=nil;
if aSL.Count=0 then exit;
try
iNODE:=XDoc.ChildNodes.Nodes [StrToInt(aSL[0])];
for i:=1 to aSL.Count -1 do
iNode:=iNODE.ChildNodes[StrToInt(aSL[i])];
Result:=iNODE;
except
end;
end;


На OnCreate формы вешаем:


procedure TfrmMain.FormCreate(Sender: TObject);
begin
XDocNodesList:=TList.Create;
XDoc:=TXMLDocument.Create(Self);
XDoc.Active:=true;
OpenDialog.InitialDir:=ExtractFilePath(ParamStr(0));
end;


На OnDestroy:
procedure TfrmMain.FormDestroy(Sender: TObject);
begin
ClearNodeList;
XDocNodesList.Free;
XDoc.Free;
end;


Обработчик нажатия на кнопку "Загрузить XML":
procedure TfrmMain.acLoadExecute(Sender: TObject);
var
i : integer;
tmpNode : IXMLNode;
begin
if OpenDialog.Execute then
begin
FName:=OpenDialog.FileName;
SaveDialog.FileName:=FName;
XDoc.LoadFromFile(FName);

for i:=0 to XDoc.ChildNodes.Count - 1 do
begin
tmpNode:=XDoc.ChildNodes[i];
TreeView.Items.AddChildObject(TreeView.TopItem,tmpNode.NodeName,
pointer(i));
if tmpNode.HasChildNodes then TreeView.TopItem.HasChildren:=true;
end;
end;
acRefresh.Execute;
bkpXml:=XDoc.XML.Text;
end;


После этого мы уже можем в первый раз опробовать работу программы: в TreeView загрузится XML, но нам будет видно только рутовую вершину (как на 1-ом рисунке). Чтобы можно было разворачивать узлы и просматривать их текст и атрибуты — надо написать еще несколько обработчиков.

procedure TfrmMain.acRefreshExecute(Sender: TObject);
var
i : integer;
tmpNode : IXMLNode;
begin
RebuildTree;
acRefreshMemBody.execute;
end;

procedure TfrmMain.RebuildTree;
var
i : integer;
XNodeItem : iXmlNode;
PNodeItem,
SelectedTrNode,
TrNodeItem,
TrNodeChild : TTreeNode;
NodeRec,
ChildNodeRec : TNodeRec;
Index : integer;
SL : TStringList;
begin
SL:=GetPathByNodeIdx (TreeView.Selected);
CurrNode:=SetXmlPosByPathIdx (SL, XDoc);
SL.Free;

Index :=0;
TreeView.Items.Clear;
ClearNodeList;
NodeRec:=TNodeRec.Create;
TrNodeItem:=TreeView.TopItem;
NodeRec.TreeNode:=TrNodeItem;
XNodeItem:=XDoc.Node;
NodeRec.XMLNode:=XNodeItem;
XDocNodesList.Add(NodeRec);

while XDocNodesList.Count > Index do
begin
NodeRec:=TNodeRec(XDocNodesList[Index]);
XNodeItem:=NodeRec.XMLNode;
TrNodeItem:=NodeRec.TreeNode;
if XNodeItem=CurrNode then SelectedTrNode:=TrNodeItem;
for i:=0 to XNodeItem.ChildNodes.Count -1 do
begin
if XNodeItem.ChildNodes[i].NodeName<>'#text' then
TrNodeChild:=
TreeView.Items.AddChildObject(
TrNodeItem,
XNodeItem.ChildNodes[i].NodeName,
pointer(i));

ChildNodeRec:=TNodeRec.Create;
ChildNodeRec.TreeNode:=TrNodeChild;
ChildNodeRec.XMLNode:=XNodeItem.ChildNodes[i];
XDocNodesList.Add(ChildNodeRec);
end;
inc(Index);
end;

if SelectedTrNode<>nil then SelectedTrNode.Selected:=true;
TreeView.Select(SelectedTrNode,[]);
end;


Сейчас при перемещении по узлам уже наблюдаем более-менее приемлемый результат:

xml editor delphi

редактирование XML (Delphi)

Дальше остается решить вопросы редактирования и добавления узлов и атрибутов.) Это будет домашним заданием.
___

Редакция от 13.01.2010
Продолжение цикла статей:
Добавление и удаление узлов (вершин) в XML в Delphi (с использованием компонента TTreeView). Там же вы найдете ссылку для скачивания исходников.

Поделиться