
09.02.2013, 17:04
|
|
Участник форума
Регистрация: 10.01.2013
Сообщений: 100
Провел на форуме: 18665
Репутация:
27
|
|
Интро
Сейчас актуально писать мелкий говнософт для разных социальных сетей. Обычно начинающие быдлокодеры пишут подобное с помощью процедурного подхода и если проект более-менее сложный начинают захлебываться в глобальных переменных и значениях процедур и функций. Я хочу продемонстрировать ООП подход и его приимущества. В статье будет ценен не код программы (скорее он то только для устрашения), а способ мышления при использовании ООП подхода.
Этап 1
ТЗ: Написать дампер сообщений социальной сети ВКонтакте с возможностью дампить переписку как по SID так и по логину/паролю.
Оговорюсь заранее, что при написании софта, я встретил много подводных камней, которые значительно усиливали запутанность программы. Я не стал вдаваться в безупречную реализацию, тк, пишу для демонстрации объектно ориентированного метода, но все-же я пометил комментариями участки кода, требующие доработки.
Что нам понадобится?
1) Язык поддерживающий ООП (Я пишу на Дэльфи)
2) Сниффер сетевого трафика (работать будем в основном с http поэтому httpAnalyzer вполне устроит).
Этап 2
По ООП есть куча разной литературы. Я попробую максимально доступно объяснить всю суть на конкретном примере. Итак, исходя из ТЗ мне нужно создать класс объекта, который смог бы проделывать определенные операции на сайте. Для начала происнифаем сайт и разберемся в алгоритмах запросов. Об этом я вообще писать не буду. По окончании у нас будет алгоритм примерно такой:
1 - Авторизуемся
2 - парсим корешей
3 - парсим месаги
Создаем новый класс объекта . Коротко немного теории : каждый класс что-то знает и что-то умеет делать. То что класс знает называется полями класса (если угодно переменные), а то что он умеет - называется методами класса (если угодно процедуры и функции)... В самомо начале проэктируется внешний вид класса (что знает умеет), а потом реализация (как он умеет). Чтож, давайте попробуем определиться, что необходимо знать и уметь нашему классу...
Знать: авторизационные данные (логин пароль), SID пользователя, количество друзей пользователя, список ID друзей, и он должен взаимодействовать с сетью по протоколу http, поэтому будет разумно запихнуть в него объект типа TidHTTP. Можно продолжать, но в учебных целях притормозим
Уметь: Авторизоваться, Парсить ID друзей, Парсить сообщения.
Также, каждый объект класса будет инициализирован под средством метода конструктора Create () . В нем удобно создавать объекту все условия для комфортной работы (создавать файлы/ соединяться с БД/ задавать настройки по умолчанию других объектов.)
Код:
//---------------Class for work with Vk.com---------
type
TVKDump = Class
Login, Password : String; // Данные для авторизации
Link : String; // Нужная шняга
SID : String; // Значение remixsid в кукисах
HTTP : TidHTTP; // Для работы с нетом
FriendList : TStringList; // Список ИДшников друзей
FriendCount : Integer; //Количество друзей
function ParseMessage (FriendID : String) : Boolean; //Вытаскиваем сообщения со скритов
function Authorize () : Boolean; //Авторизация
function ParseFriends () : Integer; //Парсим ИД корешей
constructor Create (); // Чето создаем и настраиваем
end;
//-------------------------------------------------
Этап 3
Вот собственно и все! Осталось всего ничего описать реализацию каждой функции . Здесь в подробности я вдаваться не буду, просто выложу свой быдлокод .... Там в основном парсинг и танци с бубном вокруг запросов к ВК.
Код:
//------------function parse messages with a script--------------------------
function TVKDump.ParseMessage (FriendID : String) : Boolean;
var Data, MsgList : TStringList;
Name, Mess, tmp : String;
i, j : Integer;
begin
Result := True;
try
try
HTTP.AllowCookies := False;
HTTP.Request.CustomHeaders.Clear;
HTTP.Request.CustomHeaders.Add('Cookie:remixsid=' + SID);
MsgList := TStringList.Create;
Data := TStringList.Create;
for j := 0 to 5 do
begin
Data.Clear;
Data.Add('act=a_history');
Data.Add('al=1');
// offset - параметр смещения сообщений, можно пробовать подставлять
Data.Add('offset=' + IntTostr(j*50));
Data.Add('peer=' + FriendID);
Data.Add('whole=0');
tmp := HTTP.Post('http://vk.com/al_im.php', Data);
HTTP.AllowCookies := True;
Sleep(200);
for i := 1 to 100 do
begin
Delete(tmp, 1, Pos('class="mem_link" target="_blank">', tmp) + 32);
Name := Copy(tmp, 1, Pos('', tmp) - 1);
Delete(tmp, 1, Pos('', tmp) + 5);
Mess := Copy(tmp,1, Pos('', tmp) - 1);
MsgList.Add(Name + ':' +Mess);
end;
end;
MsgList.SaveToFile(FriendID + '_damp.txt');
except
Result := False;
end;
finally
MsgList.Free;
Data.Free;
end;
end;
//----------------------------------------------------------
//-----------------authorization-----------------------------
function TVKDump.Authorize () : Boolean;
//---------------parse link necessary to request-------------
function ParseLink ( Page : String) : Boolean;
begin
Result := false;
Delete(page,1,Pos('action=',page)+15);
link := Copy(page,1,pos('>',page)-2);
if link <> ''
then
begin
Link := 'http://' + Link;
Result := true;
end;
end;
//--------------------------------------------------------------
var Data:TStringList;
tmp: String;
begin
Result := False;
try
try
Data := TStringList.Create;
Data.Add('email='+Login);
Data.Add('pass='+Password);
//----------- реализация быдлятская, но нет времени делать норм -----------------------
ParseLink(HTTP.Get('http://m.vk.com/login'));
HTTP.HandleRedirects := False;
HTTP.AllowCookies := False;
try
HTTP.Post(Link, Data);
except
try
HTTP.Get(HTTP.Response.Location);
except
tmp := HTTP.Response.RawHeaders.Text;
Delete(tmp, 1, Pos('remixsid=',tmp) + 8);
SID :=Copy( tmp,1 ,Pos('expires=',tmp)-3);
end;
end;
//--------------------------------------------------------------------------------------
HTTP.HandleRedirects := True;
HTTP.AllowCookies := True;
tmp := HTTP.Get(HTTP.Response.Location);
if Pos('logout',tmp) <> 0
then Result := True;
except
Result := False;
end;
finally
Data.Free;
end;
end;
//-------------parsing function friends ID's -----------------------
// парсит вроде первых 20 чтобы парсило всех нужно допиливать
function TVKDump.ParseFriends () : Integer;
var tmp: String;
i:integer;
begin
HTTP.AllowCookies := False;
HTTP.Request.CustomHeaders.Add('Cookie:remixsid=' + SID);
tmp := HTTP.Get('http://m.vk.com/friends');
HTTP.AllowCookies := True;
Delete(tmp,1,Pos(' ',tmp)+4);
FriendCount :=StrToInt(Copy(tmp,1,Pos('',tmp)-1));
for i:=1 to 18 do
begin
Delete(tmp,1,Pos('',tmp)-1));
end;
FriendList.SaveToFile('friends.txt');
end;
//-----------------------------------------------------------
//-------------- Созаём нужные объекты и настраиваем HTTP ----------------
constructor TVKDump.Create ();
begin
FriendList := TStringList.Create;
HTTP := TIdHTTP.Create(nil);
HTTP.HandleRedirects := True;
with HTTP.Request do
begin
UserAgent := 'Mozilla/5.0 (Windows NT 5.1; rv:16.0) Gecko/20100101 Firefox/16.0';
ContentType := 'application/x-www-form-urlencoded';
AcceptLanguage := 'ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3';
end;
end;
Этап 4
На 4 этапе необходимо создать объект нашего класса. Для этого его нужно инициализировать методом Create (). Также описывается поведение объекта и взаимодействие с другими компонентами программы. Дабы немного поизвращаться я не стал делать GUI. Программа получает необходимые данные ввиде параметров командной строки, а результаты пишет в файлы.
Код:
Var
VK : TVKDump;
i : Integer;
begin
VK := TVKDump.Create ();
//-----------если без запущена параметров, тогда выходим -----------------
if ((Paramstr(1) = '') and (Paramstr(2) = '')) then
begin
Exit;
end;
//----------возможность указать SID---------------------------------------
if ((Paramstr(1) = '0') and (Paramstr(2) = '0'))
then
begin
VK.SID := Paramstr(3);
VK.ParseFriends();
for i := 1 to 3 do // можно ставить VK.FriendsCount но нужно допилить функцию парсинга друзей
VK.ParseMessage(VK.FriendList[i]);
end
else //-----------иначе указываем логин и пароль------------------------
begin
VK.Login := Paramstr(1);
VK.Password := Paramstr(2);
VK.Authorize;
VK.ParseFriends();
for i := 1 to 5 do // можно ставить VK.FriendsCount но нужно допилить функцию парсинга друзей
VK.ParseMessage(VK.FriendList[i]);
end;
end.
Чтобы автоизоваться с помощью логина и пароля нужно в консольке набрать
Сообщение от None
D:\Delphi Projects\7\vkdumper\VKDump>VK_Dumper.exe pass login
А если по SID:
Сообщение от None
D:\Delphi Projects\7\vkdumper\VKDump>VK_Dumper.exe 0 0 6dbed7eb6eb7e7d7bd6be76bd 76be76e6db7e6b7e67eb7b
Оутро
Моя программа является еще сырым приложением и используется в качестве наглядности, но если есть необходимость и руки = тру, то и интерфейс можно прикрутить и потоки и функции поправить...
Подобным образом создаются проекты побольше со сложной структурой. Мир ООП очень богат и при разумном использовании очень помогает упростить жизнь разработчику как професионального уровня так и мелкому фрилансеру. Надеюсь кому-то пригодиться. Спасибо за внимание. BlackIce.
Привожу код всего приложения:
Код:
program VK_Dumper;
Uses
IdHttp,IdCookieManager,Dialogs, IdHTTPHeaderInfo, Classes, SysUtils;
//---------------Class for work with Vk.com---------
type
TVKDump = Class
Login, Password : String; // Данные для авторизации
Link : String; // Нужная шняга
SID : String; // Значение remixsid в кукисах
HTTP : TidHTTP; // Для работы с нетом
FriendList : TStringList; // Список ИДшников друзей
FriendCount : Integer; //Количество друзей
function ParseMessage (FriendID : String) : Boolean; //Вытаскиваем сообщения со скритов
function Authorize () : Boolean; //Авторизация
function ParseFriends () : Integer; //Парсим ИД корешей
constructor Create (); // Чето создаем и настраиваем
end;
//-------------------------------------------------
//------------function parse messages with a script--------------------------
function TVKDump.ParseMessage (FriendID : String) : Boolean;
var Data, MsgList : TStringList;
Name, Mess, tmp : String;
i, j : Integer;
begin
Result := True;
try
try
HTTP.AllowCookies := False;
HTTP.Request.CustomHeaders.Clear;
HTTP.Request.CustomHeaders.Add('Cookie:remixsid=' + SID);
MsgList := TStringList.Create;
Data := TStringList.Create;
for j := 0 to 5 do
begin
Data.Clear;
Data.Add('act=a_history');
Data.Add('al=1');
// offset - параметр смещения сообщений, можно пробовать подставлять
Data.Add('offset=' + IntTostr(j*50));
Data.Add('peer=' + FriendID);
Data.Add('whole=0');
tmp := HTTP.Post('http://vk.com/al_im.php', Data);
HTTP.AllowCookies := True;
Sleep(200);
for i := 1 to 100 do
begin
Delete(tmp, 1, Pos('class="mem_link" target="_blank">', tmp) + 32);
Name := Copy(tmp, 1, Pos('', tmp) - 1);
Delete(tmp, 1, Pos('', tmp) + 5);
Mess := Copy(tmp,1, Pos('', tmp) - 1);
MsgList.Add(Name + ':' +Mess);
end;
end;
MsgList.SaveToFile(FriendID + '_damp.txt');
except
Result := False;
end;
finally
MsgList.Free;
Data.Free;
end;
end;
//----------------------------------------------------------
//-----------------authorization-----------------------------
function TVKDump.Authorize () : Boolean;
//---------------parse link necessary to request-------------
function ParseLink ( Page : String) : Boolean;
begin
Result := false;
Delete(page,1,Pos('action=',page)+15);
link := Copy(page,1,pos('>',page)-2);
if link <> ''
then
begin
Link := 'http://' + Link;
Result := true;
end;
end;
//--------------------------------------------------------------
var Data:TStringList;
tmp: String;
begin
Result := False;
try
try
Data := TStringList.Create;
Data.Add('email='+Login);
Data.Add('pass='+Password);
//----------- реализация быдлятская, но нет времени делать норм -----------------------
ParseLink(HTTP.Get('http://m.vk.com/login'));
HTTP.HandleRedirects := False;
HTTP.AllowCookies := False;
try
HTTP.Post(Link, Data);
except
try
HTTP.Get(HTTP.Response.Location);
except
tmp := HTTP.Response.RawHeaders.Text;
Delete(tmp, 1, Pos('remixsid=',tmp) + 8);
SID :=Copy( tmp,1 ,Pos('expires=',tmp)-3);
end;
end;
//--------------------------------------------------------------------------------------
HTTP.HandleRedirects := True;
HTTP.AllowCookies := True;
tmp := HTTP.Get(HTTP.Response.Location);
if Pos('logout',tmp) <> 0
then Result := True;
except
Result := False;
end;
finally
Data.Free;
end;
end;
//-------------parsing function friends ID's -----------------------
// парсит вроде первых 20 чтобы парсило всех нужно допиливать
function TVKDump.ParseFriends () : Integer;
var tmp: String;
i:integer;
begin
HTTP.AllowCookies := False;
HTTP.Request.CustomHeaders.Add('Cookie:remixsid=' + SID);
tmp := HTTP.Get('http://m.vk.com/friends');
HTTP.AllowCookies := True;
Delete(tmp,1,Pos(' ',tmp)+4);
FriendCount :=StrToInt(Copy(tmp,1,Pos('',tmp)-1));
for i:=1 to 18 do
begin
Delete(tmp,1,Pos('',tmp)-1));
end;
FriendList.SaveToFile('friends.txt');
end;
//-----------------------------------------------------------
//-------------- Созаём нужные объекты и настраиваем HTTP ----------------
constructor TVKDump.Create ();
begin
FriendList := TStringList.Create;
HTTP := TIdHTTP.Create(nil);
HTTP.HandleRedirects := True;
with HTTP.Request do
begin
UserAgent := 'Mozilla/5.0 (Windows NT 5.1; rv:16.0) Gecko/20100101 Firefox/16.0';
ContentType := 'application/x-www-form-urlencoded';
AcceptLanguage := 'ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3';
end;
end;
Var
VK : TVKDump;
i : Integer;
begin
VK := TVKDump.Create ();
//-----------если без запущена параметров, тогда выходим -----------------
if ((Paramstr(1) = '') and (Paramstr(2) = '')) then
begin
Exit;
end;
//----------возможность указать SID---------------------------------------
if ((Paramstr(1) = '0') and (Paramstr(2) = '0'))
then
begin
VK.SID := Paramstr(3);
VK.ParseFriends();
for i := 1 to 3 do // можно ставить VK.FriendsCount но нужно допилить функцию парсинга друзей
VK.ParseMessage(VK.FriendList[i]);
end
else //-----------иначе указываем логин и пароль------------------------
begin
VK.Login := Paramstr(1);
VK.Password := Paramstr(2);
VK.Authorize;
VK.ParseFriends();
for i := 1 to 5 do // можно ставить VK.FriendsCount но нужно допилить функцию парсинга друзей
VK.ParseMessage(VK.FriendList[i]);
end;
end.
|
|
|
|
|
Здесь присутствуют: 1 (пользователей: 0 , гостей: 1)
|
|
|
|