PDA

Просмотр полной версии : [Помогите!] Бот для Варваров или IdHTTP не переходим по нужной ссылке


DDrim
15.01.2013, 22:23
Здравствуйте! Делаю бота для игра Варвары (на этом форуме есть несколько тем по данной игре).
Бота делаю на компонентах Indy: IdHTTP + TIdCookieManager.
Все вроде бы отлично, бот успешно авторизируется, переходит почти по всем ссылкам.
Но вот проблема: при заходе к конкретному дракону (кто играл, тот поймет), на странице есть ссылка "Встать в очередь". Да к вот эта ссылка почему-то не нажимается (делаю GET-запрос). Т.е. возвращается страница, в которой ссылка "Встать в очередь" просто не нажата. Ответ сервера - 200 ОК.
Никак не могу понять, в чем дело. Ссылка "Встать в очередь" парситься точно правильно...
Вот мини-пример бота, который авторизируется в игре, переходит к дракону и пытается встать в очередь на его убийство.


const
Barbars = '[Ссылки могут видеть только зарегистрированные и активированные пользователи]';

var
Form1: TForm1;

CurrentURL: AnsiString; // Текущая ссылка (где бот сейчас "находится")
Code: AnsiString; // Весь html-код игры, который постоянно меняется

implementation

{$R *.dfm}

function Get2LinkTo1(ALink_1, ALink_2: AnsiString): AnsiString;
var
i: Integer;
begin
Result := '';

if(ALink_1 = '') and (ALink_2 = '') then Exit;

if(ALink_2 = '') then begin
Result := ALink_1;
Exit;
end;

if(ALink_1 = '') then begin
Result := ALink_2;
Exit;
end;

if(Copy(ALink_1, Length(ALink_1), 1) = '/') then
ALink_1 := Copy(ALink_1, 1, Length(ALink_1) - Length('/'));

While(Copy(ALink_2, 1, Length('../')) = '../') do begin
for i:=Length(ALink_1) downto 1 do begin
if(Copy(ALink_1, i, 1) <> '/') then Continue;
ALink_1 := Copy(ALink_1, 1, i - 1);
Break;
end;

Delete(ALink_2, 1, Length('../'));
end;

ALink_1 := ALink_1 + '/';

Result := ALink_1 + ALink_2;
end;

procedure GET_Link(aLink: AnsiString);
var
MS :TMemoryStream;
ResHTML: TStringList;
begin
if(aLink = '') then Exit;

MS := TMemoryStream.Create;
ResHTML := TStringList.Create;

Try
form1.Id[Ссылки могут видеть только зарегистрированные и активированные пользователи](aLink, MS);
CurrentURL := aLink;
MS.Seek(0, 0);
ResHTML.LoadFromStream(MS);
Except
on e : EID[Ссылки могут видеть только зарегистрированные и активированные пользователи] do Begin
if form1.Id[Ссылки могут видеть только зарегистрированные и активированные пользователи] = 302 then begin
try
// получаем новый адрес - адрес перенаправления
CurrentURL := form1.Id[Ссылки могут видеть только зарегистрированные и активированные пользователи]
form1.Id[Ссылки могут видеть только зарегистрированные и активированные пользователи](CurrentURL, MS);

MS.Seek(0, 0);
ResHTML.LoadFromStream(MS);

except
on e:Exception do
// предусматриваем, что исключение может возникнуть и тут
ShowMessage('Ошибка при получении нового адреса.'+e.Message);
end;
end
else
//http 404, 501 и так далее
ShowMessage('Ошибка другого вида, не 302:'+e.Message);
end;

on e:Exception do
ShowMessage('Ошибка: ' + e.Message);
end;

Code := Utf8ToAnsi(ResHTML.Text);
end;

procedure InitBot(aLogin, aPassword: AnsiString);
var
Data: TStringList;
begin
Data := TStringList.Create;

with form1 do begin
Id[Ссылки могут видеть только зарегистрированные и активированные пользователи] := True;
Id[Ссылки могут видеть только зарегистрированные и активированные пользователи] := IdCookieManager1;
Id[Ссылки могут видеть только зарегистрированные и активированные пользователи] := True;

Id[Ссылки могут видеть только зарегистрированные и активированные пользователи] := 'barbars.ru';
Id[Ссылки могут видеть только зарегистрированные и активированные пользователи] := 'Opera/9.80 (Windows NT 6.1; U; ru) Presto/2.10.229 Version/11.61';
Id[Ссылки могут видеть только зарегистрированные и активированные пользователи] := 'application/x-[Ссылки могут видеть только зарегистрированные и активированные пользователи]';
Id[Ссылки могут видеть только зарегистрированные и активированные пользователи] := 'text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/webp, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1';
Id[Ссылки могут видеть только зарегистрированные и активированные пользователи] := 'ru-RU,ru;q=0.9,en;q=0.8';
Id[Ссылки могут видеть только зарегистрированные и активированные пользователи] := 'windows-1251,utf-8;q=0.7,*;q=0.7';
Id[Ссылки могут видеть только зарегистрированные и активированные пользователи] := Barbars;
CurrentURL := Barbars;
end;

Data.Add('id1_hf_0');
Data.Add('login=' + aLogin);
Data.Add('password=' + aPassword);

Try // Авторизируюсь:
// Если логин или пароль не подходят:
if(AnsiPos('Неверный ник или пароль', Utf8ToAnsi(Form1.Id[Ссылки могут видеть только зарегистрированные и активированные пользователи]('[Ссылки могут видеть только зарегистрированные и активированные пользователи]', Data))) > 0) then begin
// raise Exception.Create('Ошибка! Логин или пароль не подходят!' + #10#13 + 'Бот может работать не корректно!');
end;

CurrentURL := '[Ссылки могут видеть только зарегистрированные и активированные пользователи]';
Except
on e : EID[Ссылки могут видеть только зарегистрированные и активированные пользователи] do Begin
if e.ReplyErrorCode = 302 then begin
try
// получаем новый адрес - адрес перенаправления
CurrentURL := form1.Id[Ссылки могут видеть только зарегистрированные и активированные пользователи]
form1.Id[Ссылки могут видеть только зарегистрированные и активированные пользователи](CurrentURL);
except
on e:Exception do
// предусматриваем, что исключение может возникнуть и тут
ShowMessage('Ошибка при получении нового адреса.'+e.Message);
end;
end
else
//http 404, 501 и так далее
ShowMessage('Ошибка другого вида, не 302:'+e.Message);
end;

on e:Exception do
ShowMessage('Ошибка: ' + e.Message);
end;

Data.Free;
end;

function ParsLinks(aNameLink: AnsiString; aHTMLCode: AnsiString): AnsiString;
var
PosLink: Integer;
i: Integer;
begin
Result := '';
if(aNameLink = '') or (aHTMLCode = '') then Exit;

if(aNameLink = 'Пещерный стражник') then
with tstringlist.Create do free;

PosLink := AnsiPos(aNameLink, aHTMLCode);
if(PosLink <= 0) then Exit;

i := PosLink - 1;
while(Copy(aHTMLCode, i, Length('="')) <> '="') do dec(i); // Нахожу индекс знаков =" перед ссылкой

Result := Copy(aHTMLCode, i + Length('="'), PosEx('">', aHTMLCode, i + 1) - i - Length('="'));
end;

procedure CheckGame;
var
BufLinkDragon: AnsiString; // Динамическая ссылка на драконов
begin
GET_Link(Barbars);

BufLinkDragon := ParsLinks('Пещеры и драконы', Code); // Вытаскиваем "вторую часть" ссылки
BufLinkDragon := Get2LinkTo1(CurrentURL, BufLinkDragon); // Получаем полную ссылку на драконов
GET_Link(BufLinkDragon); // Переходим по ссылке на драконов

BufLinkDragon := ParsLinks('Пещерный стражник', Code); // Вытаскиваем "вторую часть" ссылки
BufLinkDragon := Get2LinkTo1(CurrentURL, '../' + BufLinkDragon); // Получаем полную ссылку на нужного дракона
GET_Link(BufLinkDragon); // Переходим по ссылке дракона

// Нажимаем на ссылку "Встать в очередь":
if(AnsiPos('Встать в очередь', Code) <= 0) then begin
showmessage('дракон мертв!');
exit;
end;

BufLinkDragon := ParsLinks('Встать в очередь', Code);
BufLinkDragon := Get2LinkTo1(CurrentURL, '../' + BufLinkDragon);
GET_Link(BufLinkDragon); // ВОТ ТУТ на ссылку бот почему-то не нажимает (ссылка точно правильная!)
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
InitBot(Edit1.Text, Edit2.Text); // Авторизируемся...
// Перехожу на главную страницу:
GET_Link(Barbars);

CheckGame; // Делаю проверку на драконов, поля и т.д.
end;


ЗЫ логин-пароль для теста не прилагаю, т.к. у меня только один аккаунт (и он основной).
Просто хотел бы понять причину, почему все ссылки нажимаются правильно, а именно ОДНА нет...

Добавлено через 8 минут
Если кто захотел скомпилировать код:
Код выше для Делфи 7.
Для Indy 9-10 (новые версии компонент) надо изменить ReplyErrorCode на ErrorCode и все отлично скомпилируется.

J-Fobos
17.01.2013, 21:39
А проверьте сниффером что отправляет браузер, а что отправляет ваш бот.

DDrim
18.01.2013, 00:16
Да в том то и проблема... Что браузер отправляет тоже самое...
Я грешу на ошибки Indy компонент, особенно в плане кукисов... Но бот и браузер отправляют одни и теже запросы...
Пытаюсь сейчас переделать все под Synapse, только там даже авторизироваться не удается...)

metraz
18.01.2013, 00:34
такого быть не может. Смотри заголовки.

DDrim
18.01.2013, 00:53
Ну реально все тоже самое...
Авторизация же происходит... Переход по всем другим ссылкам тоже. А вот именно на эту ссылку не нажимает...
Там ссылка вида "[Ссылки могут видеть только зарегистрированные и активированные пользователи] inkListener::&amp;action=1358459294756" получается. Вызываем ее через GET, но страница нужная не приходит... Приходит такая же страница, только с новым id в конце ссылки (т.е. action меняется и все)...

J-Fobos
18.01.2013, 11:48
Выкладывайте лог сниффера от браузера и от вашей программы, желательно ХТТПанал.

=PaLeTiZaToR=
18.01.2013, 14:15
Выкладывайте лог сниффера от браузера и от вашей программы, желательно ХТТПанал.

[Ссылки могут видеть только зарегистрированные и активированные пользователи] Не извращайся над моей фантазией :)

DDrim
18.01.2013, 14:29
Выложил в XML.
Правда там разные персонажи (в опере и в моей программе), но факт остается фактом: по ссылке "Встать в очередь" бот не переходит...
Открыть можно любым сниффером, например у меня [Ссылки могут видеть только зарегистрированные и активированные пользователи]

J-Fobos
18.01.2013, 20:12
=^PaLeTiZaToR^=, это уже показывает кто насколько испорчен)) Не я название этой проги придумал))


DDrim, разница есть, я думаю главная причина в этом

GET /?wicket:interface=:4:actionPanel:joinQueueLink::IL inkListener::&amp;action=1358508176435 [Ссылки могут видеть только зарегистрированные и активированные пользователи]
GET /?wicket:interface=:2:actionPanel:joinQueueLink::IL inkListener::&action=1358459665622 [Ссылки могут видеть только зарегистрированные и активированные пользователи]

DDrim
19.01.2013, 01:39
Ну разницу тут я вижу только в добавлении приставки "&amp" в опере...
HTTP 1.0-1.1 в принципе не должно влиять...
Непонятно как-то...

J-Fobos
19.01.2013, 17:13
На что влияет параметр amp? И там еще разница interface=:4 и interface=:2. Да и HTTP 1.0/1.1 также может влиять, на комбатс.ру например была разница.

DDrim
20.01.2013, 04:16
interface=:4 и interface=:2 не как не влияет, т.к. ссылка генерируется игровым сервером и просто в опере было одно, а у меня в боте другое (т.е. там постоянно меняется числа от 1 до 4 вроде). А вот про amp я не знаю... Но и в нем вряд ли мне кажется...

J-Fobos
20.01.2013, 18:54
А мне кажется именно в этом загвоздка. Почему в боте одно, а в опере другое?

DDrim
20.01.2013, 23:53
Потому что именно игровой сервер генерирует ссылку и она и в опере тоже каждый раз разная...
Посмотрел, например в Хроме и IE параметра amp нету, но по ссылке переходит. Все остальное тоже самое, что и в боте... Никак понять не могу, прикол какой-то.
Единственное, почему может не переходить по ссылке (ИМХО), это глючные Indy компоненты (причем не последней версии). Очень многие жалуются на глючность этих компонент, вот может в этом все и заключается...
Но переделать пока под WinSock тоже не получается...

Relli
21.01.2013, 08:45
Потому что именно игровой сервер генерирует ссылку и она и в опере тоже каждый раз разная...
Посмотрел, например в Хроме и IE параметра amp нету, но по ссылке переходит. Все остальное тоже самое, что и в боте... Никак понять не могу, прикол какой-то.
Единственное, почему может не переходить по ссылке (ИМХО), это глючные Indy компоненты (причем не последней версии). Очень многие жалуются на глючность этих компонент, вот может в этом все и заключается...
Но переделать пока под WinSock тоже не получается...

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

metraz
21.01.2013, 13:09
Многие привыкли грешить на инди, но прекращайте, перейдя на сокеты или синапс, ваша ситуация не изменится.

J-Fobos
23.01.2013, 20:52
Во первых, не стоит забывать, что инди 10 на стадии бета тестирования, ошибки действительно есть, и не мало. Но они довольно оперативно фиксятся. Если конечно о них сообщить, но для многих проблема зарегится на портале разработчиков :D
Плюс к этому надо обновлять компоненты. Например инди компоненты, которые устанавливаются вместе с ХЕ2 Update 4 HotFix 1 разработчик назвал устаревшими и практически неработоспособными.

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

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

Хотя код в первом посте темы выглядит работоспособным. Может компоненты не обновлены.

DDrim
24.01.2013, 01:09
Компоненты не обновленные точно. Но я надеялся, что проблема не в этом... Ладно, буду пытаться что-то переделать.
Всем спасибо, будут советы - пишите :)
Найду ответ - отпишусь

J-Fobos
26.01.2013, 11:42
Компоненты обновить, первым делом :)

=PaLeTiZaToR=
26.01.2013, 14:39
Не читал всей темы, если было , простите.
Что мешает попробовать синапс ?

DDrim
26.01.2013, 22:20
Незнание синапса :(
Пытался, просто там даже авторизация нормально не проходит.
Я особо париться не стал, и забил на синапс...

=PaLeTiZaToR=
27.01.2013, 00:47
Незнание синапса :(
Пытался, просто там даже авторизация нормально не проходит.
Я особо париться не стал, и забил на синапс...

Хех а чего там не знать то?
[Ссылки могут видеть только зарегистрированные и активированные пользователи]
[Ссылки могут видеть только зарегистрированные и активированные пользователи]
вот, почитай... тут все предельно легко.
А не авторизовываться может и за того что синапс нужно ручками настраивать... из личного опыта...
Допустим инди сам заголовок подставит а синапсу нужно носом тыкнуть... примерно так
[Ссылки могут видеть только зарегистрированные и активированные пользователи]('Заголовок')

DDrim
27.01.2013, 01:27
Да знаю, что надо самому настраивать, вроде правильно настраивал... Вот примерно так писал:

type
TD[Ссылки могут видеть только зарегистрированные и активированные пользователи]
FCodePage: Cardinal;
FSend: T[Ссылки могут видеть только зарегистрированные и активированные пользователи]

constructor Create;
function GetError: string;
function GetRedirectUrl: string;
function GET(AUrl: string): string;
function POST(AUrl: string; AParams: TStringList): string;
end;

...

procedure GET_Link(aLink: AnsiString);
var
[Ссылки могут видеть только зарегистрированные и активированные пользователи] TD[Ссылки могут видеть только зарегистрированные и активированные пользователи]
begin
if(aLink = '') then Exit;
http := TD[Ссылки могут видеть только зарегистрированные и активированные пользователи]

Try
Code := Utf8ToAnsi([Ссылки могут видеть только зарегистрированные и активированные пользователи](aLink));
CurrentURL := aLink;
Except
showmessage('error: ' + [Ссылки могут видеть только зарегистрированные и активированные пользователи]);
end;

[Ссылки могут видеть только зарегистрированные и активированные пользователи]
end;

constructor TD[Ссылки могут видеть только зарегистрированные и активированные пользователи]
begin
FSend:=T[Ссылки могут видеть только зарегистрированные и активированные пользователи]
FSend.Protocol:='1.1';
// FSend.Protocol:='1.0';

FSend.Timeout:=3000;
FCodePage:=CP_UTF8;
FSend.UserAgent:='Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; Alexa Toolbar; MEGAUPLOAD 1.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET4.0C; .NET4.0E)';

FSend.KeepAlive := True;
FSend.TargetPort := '80';
FSend.TargetHost := 'barbars.ru';

FSend.MimeType :='application/x-[Ссылки могут видеть только зарегистрированные и активированные пользователи]';
end;

function TD[Ссылки могут видеть только зарегистрированные и активированные пользователи] string;
begin
Result:='';
if FSend.ResultCode>0 then
Result:=Result+IntToStr(FSend.ResultCode);
if FSend.ResultString<>'' then
Result:=Result+': '+FSend.ResultString;
end;

function TD[Ссылки могут видеть только зарегистрированные и активированные пользователи] string;
var i: integer;
Line: string;
begin
Result:='';
for i := 0 to FSend.Headers.Count-1 do
begin
Line:=LowerCase(FSend.Headers[i]);
if Pos('location:',Line)>0 then
begin
Result:=Trim(StringReplace(Line,'Location:','',[rfIgnoreCase]));
Exit;
end;
end;
end;

function TD[Ссылки могут видеть только зарегистрированные и активированные пользователи](AUrl: string): string;
var Stream: TStringStream;
RedirectUrl: string;
begin
try
Stream:=TStringStream.Create('');
try
FSend.Headers.Clear;
FSend.Document.Clear;
// if FReferer<>'' then FSend.Headers.Add('Referer: '+FReferer);
if FSend.[Ссылки могут видеть только зарегистрированные и активированные пользователи]('GET', AUrl) then
begin
FSend.Document.SaveToStream(Stream);
Result:=Stream.DataString;
RedirectUrl:=GetRedirectUrl;
if RedirectUrl<>'' then
Result:=GET(RedirectUrl);
end else raise Exception.Create(GetError);
finally
Stream.Free;
end;
except
on E: Exception do
raise Exception.Create('TD[Ссылки могут видеть только зарегистрированные и активированные пользователи]('+AUrl+'): '+E.Message);
end;
end;

function TD[Ссылки могут видеть только зарегистрированные и активированные пользователи](AUrl: string; AParams: TStringList): string;
var Stream: TStringStream;
RedirectUrl: string;
i: integer;

X: tstringlist;
begin
try
Stream:=TStringStream.Create('');
try
FSend.Headers.Clear;
FSend.Document.Clear;

for i := 0 to AParams.Count-1 do
if i=0 then
Stream.WriteString(AParams[i]) else
Stream.WriteString('&'+AParams[i]);
FSend.Document.LoadFromStream(Stream);
if FSend.[Ссылки могут видеть только зарегистрированные и активированные пользователи]('POST',AUrl) then
begin
FSend.Document.SaveToStream(Stream);
Result:=Stream.DataString;
RedirectUrl:=GetRedirectUrl;
if RedirectUrl<>'' then
Result:=GET(RedirectUrl);
end else raise Exception.Create(GetError);
finally
Stream.Free;
end;
except
on E: Exception do
raise Exception.Create('TD[Ссылки могут видеть только зарегистрированные и активированные пользователи]('+AUrl+'): '+E.Message);
end;
end;

...


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