shadowrun
22.01.2012, 02:36
.:INTRO:.
У новичков часто возникают вопросы относительно написания всяких мелких регеров, чекеров, гулялок и тд. Собственно решил поделиться опытом и осветить моменты, которые, на мой взгляд, вызывают больше всего трудностей. Статейка будет полезна только новичкам, изучающим работу с инетом средствами Делфи. Шарящим можно идти мимо, критиковать, троллить и делать все, что в голову взбредет . Взаимодействовать с окаянным будем используя библиотеку indy. Итак, начинаем!
.:Организация работы:.
Есть один интересный сайт http://sprashivay.ru. Сайтег довольно быстро набирает обороты и представляет собой задавалку анонимных вопросов. Одна знакомая барышня ныла по поводу того, что как бы было классно, если бы сайт выдавал оповещение, когда тебе задают новый вопрос... Ну корочь решил я помочь бабенке воплотить ее грязную фантазию в жизнь . Решил накатать софтину, которая сидела бы на страничке, выжидала, когда зададут вопрос и информировала бы нас об этом. Вот собственно фотка этой красотки:
http://s018.radikal.ru/i506/1201/68/c93071fda741.jpg Глаголить она будет через сообщения в System_Tray, вот как-то так:
http://s017.radikal.ru/i436/1201/32/733c67d2e9bf.jpg
Чтобы начать колдовать, нам необходимы следующие ингредиенты:
- Delphi 7
- HttpAnalyzer (или другой сниффер)
- Минимальные знания строения http запросов
В процессе колдовства будут затронуты следующие аспекты проведения черной мессы:
- Работа со снифером
- Отправка данных методами GET и POST.
- Парсинг страницы
- Работа с куками
Нужна новая учетка для экспериментов. Идем на сайт, регимся. Я создал учетную запись, с такими авторизационными данными: логин - owning@insorg-mail.info, пароль - antichat. Наша прога должна также уметь проходить регистрацию. Сейчас попытаемся научить ее это делать.
.:Кодинг:.
Включаем снифер, проходим авторизацию на сайте. Видим, что авторизационные данные отправляются скрипту http://sprashivay.ru/login методом POST.
http://s61.radikal.ru/i173/1201/be/aaed9f9b0253.jpg
Нужно, чтобы прога делала все в точности также. Создаём новый проект... Добавим на форму Два поля ввода Edit1 и Edit2 (для ввода логина и пароля соответственно), Одну кнопку, которая будет отвечать за регистрацию. Объявляем глобальные переменные:
var
Form1: TForm1;
HTTP: TidHTTP;
PData: TStringList; // Список, который будет использоваться для отправки параметров запроса
Page: String; // Переменная будет содержать код страницы
С помощью сниффера просматриваем содержание заголовка запроса браузера и формируем такой же для программы (В целях уменьшения кода я сформирую пакет, который содержит не все параметры, но их достаточно, чтобы чтобы сайт подумал, что наша программа - обычный браузер):
http://s018.radikal.ru/i516/1201/5b/3468d36da1f5.jpg
В обработчик TForm1.Button1Click добавим следующий код:
begin
HTTP := TIdHTTP.Create(Self); // Создаем наш компонент для работы с вебом
PData := TStringList.Create; // Создаем строковый список для хранения параметров
with HTTP.Request do //Устанавливаем заголовок
begin
Host := 'sprashivay.ru';
Referer := 'http://sprashivai.ru';
UserAgent := 'Opera/9.80 (Windows NT 6.1; U; Edition Ukraine Local; ru) Presto/2.10.229 Version/11.60';
ContentType := 'application/x-www-form-urlencoded';
end;
HTTP.AllowCookies := False; //Отключаем автоматическую работу с кукисами
HTTP.HandleRedirects := True; // Разрешаем переадресацию
Теперь обратим внимание на то, как были переданы серверу наши авторизационные данные:
http://s51.radikal.ru/i133/1201/4a/1e77138fae6c.jpg
Мыло передается в нормальном человеческом виде, а вот с паролем явно что-то не то. Вместо слова antichat мы видим какуе-то х??ню. Я предположил, что цыферки эти не что иное как наш antichat, только в зашифрованном виде. Шифрование происходит по алгоритму MD5. Полностью я в этом убедился, когда сходил на http://www.c0llision.net/ и расшифровал хэш. Из этого исходит, что наш софт также должен уметь шифровать данные для отправки. Пишем код:
// Добавляем в описание переменных
MD5: TIdHashMessageDigest;
Hash: String;
............
MD5 := TIdHashMessageDigest5.Create; // Создадим компонент для шифрования данных
Hash := MD5.AsHex(MD5.HashValue(Edit2.Text)); // С помощью его методов преобразуем значение Edit2.Text в хэш 16ричного формата алгоритма MD5
Скажу откровенно, что в этом месте я поимел немало секса, т.к. не учел, что хеш получается из ЗАГЛАВНЫХ букв, а сервер принимает только строчные... Но в итоге проблема была решена с помощью всего одной функции:
//Добавляем авторизационные параметры
PData.Add('email='+Edit1.Text); // С мылом проблем нет. Тупо указываем параметр, как в сниффере и его значение
PData.Add('pass='+LowerCase(Hash)); // При передаче пароля используем ф-цию LowerCase для преобразования заглавных букв в строчные
Пробуем отправить наши данные, авторизоваться и сообщить результат авторизации. Вот ответ сервера при успешной авторизации :http://s001.radikal.ru/i193/1201/cc/1dbaccbaaa1e.jpg
//Добавим переменную S, в которой будут содержаться ответы сервера...
var
S: String;
.................
try
Page := HTTP.Post('http://sprashivai.ru/login',PData);
S := HTTP.Response.RawHeaders.GetText;
except
ShowMessage('error');
exit;
end;
if Pos('error',Page) <> 0 // Проверяем данные на валидность
then begin
Label1.Caption := 'Invalid Pass or login';
Exit; // Если данные некорректны - сообщаем об этом
end
else
begin // Если же все ок, парсим с ответа имя учетки и выводим его на форму
Delete(Page,1,Pos('"username":',Page));
Login := Copy(Page,Pos('"username":',Page)+12,Length(Page)-13);
Label1.Caption := Login;
end;
При каждом новом обращении к сайту, мы должны дать ему понять, что мы являемся авторизированным пользователем. Как это делается? С помощью кукисов. Когда юзер удачного проходит авторизацию, скрипт пихает ему кукисы для того, чтобы отличать его от остальной массы народа. Посмотрим на сниффер после удачно пройенной авторизации, нас интересуют кукисы:
http://s018.radikal.ru/i508/1201/62/057717f10a25.jpg
По скрину видим, что браузер пихнул нам кук с именем usersession и значением состоящим из 28 букв и цифр. Делфи имеет некоторые стандартные компоненты для работы с кукисами, но мне по нраву выставлять их вручную... В приведенном ниже коде, я спаршу значение кукисов из ответа сервера используя регулярные выражения. Об этом я рассказывать не буду (мб когда нить допишу), просто приведу код. Добавим на форму таймер. он нужен, чтобы прога периодически парсила наш страницу на наличие новых вопросов.
// Добавляем к переменным
Reg: TregExp;
mc: MatchCollection;
m: Match;
................
Reg := TRegExp.Create(self);
reg.Pattern:='[0-9A-Z]{28}';
mc := Reg.Execute(s) as MatchCollection;
M := mc[0] as Match; //Парсим кукисы с помощью регулярок
HTTP.Request.CustomHeaders.Add('Cookie: usersession='+M.Value+';SERV=STEALTH117;_ym_visorc =w'); // Добавляем в заголовок запроса
Timer1.Interval := 20000;
Следующий кусок кода пишем уже в обработчике таймера.
Page := UTF8ToAnsi(HTTP.Get('http://sprashivai.ru/questions/new')); //Делаем гет запрос и сохраняем код страницу в переменную
QCount := Copy(Page,Pos('sprashivai.newquestions =',Page) + 26,1); //Парсим на наличие текста
If Pos('0',QCount) = 0 then CoolTrayIcon1.ShowBalloonHint('Новый вопрос',bitInfo,BITSPIXEL); // Выводим уведомление о новом сообщении
На этом все. Ритуал окончен
.:ЭПИЛОГ:.
Весь подобный софт пишется по данной схеме:
Авторизация
Прием/передача кукисов
Парсинг страниц
Используя мой пример вам не составит труда разобраться в написании подобного рода программ. Я постарался максимально комментировать код и рассказать более подробно о ключевых ситуациях . Если что не учел, добавлю в ближайшее время.
Исходники приведу в товарный вид и выложу...
Линк на прогу: http://slil.ru/32550864
У новичков часто возникают вопросы относительно написания всяких мелких регеров, чекеров, гулялок и тд. Собственно решил поделиться опытом и осветить моменты, которые, на мой взгляд, вызывают больше всего трудностей. Статейка будет полезна только новичкам, изучающим работу с инетом средствами Делфи. Шарящим можно идти мимо, критиковать, троллить и делать все, что в голову взбредет . Взаимодействовать с окаянным будем используя библиотеку indy. Итак, начинаем!
.:Организация работы:.
Есть один интересный сайт http://sprashivay.ru. Сайтег довольно быстро набирает обороты и представляет собой задавалку анонимных вопросов. Одна знакомая барышня ныла по поводу того, что как бы было классно, если бы сайт выдавал оповещение, когда тебе задают новый вопрос... Ну корочь решил я помочь бабенке воплотить ее грязную фантазию в жизнь . Решил накатать софтину, которая сидела бы на страничке, выжидала, когда зададут вопрос и информировала бы нас об этом. Вот собственно фотка этой красотки:
http://s018.radikal.ru/i506/1201/68/c93071fda741.jpg Глаголить она будет через сообщения в System_Tray, вот как-то так:
http://s017.radikal.ru/i436/1201/32/733c67d2e9bf.jpg
Чтобы начать колдовать, нам необходимы следующие ингредиенты:
- Delphi 7
- HttpAnalyzer (или другой сниффер)
- Минимальные знания строения http запросов
В процессе колдовства будут затронуты следующие аспекты проведения черной мессы:
- Работа со снифером
- Отправка данных методами GET и POST.
- Парсинг страницы
- Работа с куками
Нужна новая учетка для экспериментов. Идем на сайт, регимся. Я создал учетную запись, с такими авторизационными данными: логин - owning@insorg-mail.info, пароль - antichat. Наша прога должна также уметь проходить регистрацию. Сейчас попытаемся научить ее это делать.
.:Кодинг:.
Включаем снифер, проходим авторизацию на сайте. Видим, что авторизационные данные отправляются скрипту http://sprashivay.ru/login методом POST.
http://s61.radikal.ru/i173/1201/be/aaed9f9b0253.jpg
Нужно, чтобы прога делала все в точности также. Создаём новый проект... Добавим на форму Два поля ввода Edit1 и Edit2 (для ввода логина и пароля соответственно), Одну кнопку, которая будет отвечать за регистрацию. Объявляем глобальные переменные:
var
Form1: TForm1;
HTTP: TidHTTP;
PData: TStringList; // Список, который будет использоваться для отправки параметров запроса
Page: String; // Переменная будет содержать код страницы
С помощью сниффера просматриваем содержание заголовка запроса браузера и формируем такой же для программы (В целях уменьшения кода я сформирую пакет, который содержит не все параметры, но их достаточно, чтобы чтобы сайт подумал, что наша программа - обычный браузер):
http://s018.radikal.ru/i516/1201/5b/3468d36da1f5.jpg
В обработчик TForm1.Button1Click добавим следующий код:
begin
HTTP := TIdHTTP.Create(Self); // Создаем наш компонент для работы с вебом
PData := TStringList.Create; // Создаем строковый список для хранения параметров
with HTTP.Request do //Устанавливаем заголовок
begin
Host := 'sprashivay.ru';
Referer := 'http://sprashivai.ru';
UserAgent := 'Opera/9.80 (Windows NT 6.1; U; Edition Ukraine Local; ru) Presto/2.10.229 Version/11.60';
ContentType := 'application/x-www-form-urlencoded';
end;
HTTP.AllowCookies := False; //Отключаем автоматическую работу с кукисами
HTTP.HandleRedirects := True; // Разрешаем переадресацию
Теперь обратим внимание на то, как были переданы серверу наши авторизационные данные:
http://s51.radikal.ru/i133/1201/4a/1e77138fae6c.jpg
Мыло передается в нормальном человеческом виде, а вот с паролем явно что-то не то. Вместо слова antichat мы видим какуе-то х??ню. Я предположил, что цыферки эти не что иное как наш antichat, только в зашифрованном виде. Шифрование происходит по алгоритму MD5. Полностью я в этом убедился, когда сходил на http://www.c0llision.net/ и расшифровал хэш. Из этого исходит, что наш софт также должен уметь шифровать данные для отправки. Пишем код:
// Добавляем в описание переменных
MD5: TIdHashMessageDigest;
Hash: String;
............
MD5 := TIdHashMessageDigest5.Create; // Создадим компонент для шифрования данных
Hash := MD5.AsHex(MD5.HashValue(Edit2.Text)); // С помощью его методов преобразуем значение Edit2.Text в хэш 16ричного формата алгоритма MD5
Скажу откровенно, что в этом месте я поимел немало секса, т.к. не учел, что хеш получается из ЗАГЛАВНЫХ букв, а сервер принимает только строчные... Но в итоге проблема была решена с помощью всего одной функции:
//Добавляем авторизационные параметры
PData.Add('email='+Edit1.Text); // С мылом проблем нет. Тупо указываем параметр, как в сниффере и его значение
PData.Add('pass='+LowerCase(Hash)); // При передаче пароля используем ф-цию LowerCase для преобразования заглавных букв в строчные
Пробуем отправить наши данные, авторизоваться и сообщить результат авторизации. Вот ответ сервера при успешной авторизации :http://s001.radikal.ru/i193/1201/cc/1dbaccbaaa1e.jpg
//Добавим переменную S, в которой будут содержаться ответы сервера...
var
S: String;
.................
try
Page := HTTP.Post('http://sprashivai.ru/login',PData);
S := HTTP.Response.RawHeaders.GetText;
except
ShowMessage('error');
exit;
end;
if Pos('error',Page) <> 0 // Проверяем данные на валидность
then begin
Label1.Caption := 'Invalid Pass or login';
Exit; // Если данные некорректны - сообщаем об этом
end
else
begin // Если же все ок, парсим с ответа имя учетки и выводим его на форму
Delete(Page,1,Pos('"username":',Page));
Login := Copy(Page,Pos('"username":',Page)+12,Length(Page)-13);
Label1.Caption := Login;
end;
При каждом новом обращении к сайту, мы должны дать ему понять, что мы являемся авторизированным пользователем. Как это делается? С помощью кукисов. Когда юзер удачного проходит авторизацию, скрипт пихает ему кукисы для того, чтобы отличать его от остальной массы народа. Посмотрим на сниффер после удачно пройенной авторизации, нас интересуют кукисы:
http://s018.radikal.ru/i508/1201/62/057717f10a25.jpg
По скрину видим, что браузер пихнул нам кук с именем usersession и значением состоящим из 28 букв и цифр. Делфи имеет некоторые стандартные компоненты для работы с кукисами, но мне по нраву выставлять их вручную... В приведенном ниже коде, я спаршу значение кукисов из ответа сервера используя регулярные выражения. Об этом я рассказывать не буду (мб когда нить допишу), просто приведу код. Добавим на форму таймер. он нужен, чтобы прога периодически парсила наш страницу на наличие новых вопросов.
// Добавляем к переменным
Reg: TregExp;
mc: MatchCollection;
m: Match;
................
Reg := TRegExp.Create(self);
reg.Pattern:='[0-9A-Z]{28}';
mc := Reg.Execute(s) as MatchCollection;
M := mc[0] as Match; //Парсим кукисы с помощью регулярок
HTTP.Request.CustomHeaders.Add('Cookie: usersession='+M.Value+';SERV=STEALTH117;_ym_visorc =w'); // Добавляем в заголовок запроса
Timer1.Interval := 20000;
Следующий кусок кода пишем уже в обработчике таймера.
Page := UTF8ToAnsi(HTTP.Get('http://sprashivai.ru/questions/new')); //Делаем гет запрос и сохраняем код страницу в переменную
QCount := Copy(Page,Pos('sprashivai.newquestions =',Page) + 26,1); //Парсим на наличие текста
If Pos('0',QCount) = 0 then CoolTrayIcon1.ShowBalloonHint('Новый вопрос',bitInfo,BITSPIXEL); // Выводим уведомление о новом сообщении
На этом все. Ритуал окончен
.:ЭПИЛОГ:.
Весь подобный софт пишется по данной схеме:
Авторизация
Прием/передача кукисов
Парсинг страниц
Используя мой пример вам не составит труда разобраться в написании подобного рода программ. Я постарался максимально комментировать код и рассказать более подробно о ключевых ситуациях . Если что не учел, добавлю в ближайшее время.
Исходники приведу в товарный вид и выложу...
Линк на прогу: http://slil.ru/32550864