2013-08-13 2 views
1

Во-первых, извините за мой плохой английский!IdHttp + IdCookieManager + ASP.NET WebForm Страница [Закрыть]

Мне нужно выполнить запрос на веб-сайте www.nfe.fazenda.org.br. Для лучшей производительности используйте компонент TIdHTTP с TIdCookieManager.

Этот сайт использует captcha для доступа к управлению. Итак, я пытаюсь получить страницу и код для получения файлов cookie.

Пользователь вводит код и ключ для NFe. Итак, я отправляю на страницу с сообщением.

Но, когда я запускаю сообщение, меня перенаправляют на страницу с ошибкой.

Здесь мой тестовый код и попросите вас помочь мне. Спасибо!

unit Forms.MainForm; 

interface 

uses 
    Winapi.Windows, Winapi.Messages, 
    System.SysUtils, System.Variants, System.Classes, 
    Vcl.Forms, Vcl.Graphics, Vcl.Dialogs, Vcl.Controls, Vcl.ExtCtrls, 
    Vcl.StdCtrls, 
    IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, IdHTTP, 
    IdIOHandler, IdIOHandlerSocket, IdIOHandlerStack, IdSSL, IdSSLOpenSSL, 
    IdCookieManager, IdCookie, IdURI, 
    GIFImg, WinInet; 

type 
    TMainForm = class(TForm) 
    mem: TMemo; 
    IdHttp: TIdHTTP; 
    IdSSLHandlerSocket: TIdSSLIOHandlerSocketOpenSSL; 
    IdCookieManager: TIdCookieManager; 
    panBottom: TPanel; 
    btnGo: TButton; 
    imgCaptcha: TImage; 
    edtKey: TEdit; 
    edtCode: TEdit; 
    lblInit: TLabel; 
    procedure FormShow(Sender: TObject); 
    procedure lblInitClick(Sender: TObject); 
    procedure btnGoClick(Sender: TObject); 
    private 
    Cookies: TIdCookies; 
    viewState, eventValidate: string; 
    procedure GetHiddenFieldValues(html: string); 
    procedure p_Execute; 
    end; 

var 
    MainForm: TMainForm; 

const 
    HOST   = 'http://www.nfe.fazenda.gov.br'; 
    URLIMG  = 'http://www.nfe.fazenda.gov.br/scripts/srf/intercepta/captcha.aspx?opt=image'; 
    URLGET  = 'http://www.nfe.fazenda.gov.br/portal/consulta.aspx?tipoConsulta=completa&tipoConteudo=XbSeqxE8pl8='; 
    URLPOST  = 'http://www.nfe.fazenda.gov.br/portal/consultaCompleta.aspx?tipoConteudo=XbSeqxE8pl8='; 
    CONTENT_TYPE = 'application/x-www-form-urlencoded'; 

implementation 

{$R *.dfm} 

procedure TMainForm.FormShow(Sender: TObject); 
begin 
    lblInitClick(Sender); 
end; 

procedure TMainForm.lblInitClick(Sender: TObject); 
var 
    response: TMemoryStream; 
    gif: TGIFImage; 
    html: string; 
begin 
    response := TMemoryStream.Create; 
    gif := TGIFImage.Create; 
    try 
    html := IdHttp.Get(URLGET); 
    mem.Text := html; 
    GetHiddenFieldValues(html); 

    IdHttp.Get(URLIMG, response); 
    response.Position := 0; 
    gif.LoadFromStream(response); 
    imgCaptcha.Picture.Assign(gif); 

    Cookies := IdCookieManager.CookieCollection; 
    finally 
    gif.Free; 
    response.Free; 
    end; 
end; 

procedure TMainForm.btnGoClick(Sender: TObject); 
begin 
    p_Execute; 
end; 

procedure TMainForm.GetHiddenFieldValues(html: string); 
var 
    nIni, nLen: integer; 
    cVal: string; 
const 
    TAG_VIEWSTATE = '<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="'; 
    TAG_EVENTVALIDATION = '<input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION" value="'; 
begin 
    nIni := Pos(TAG_VIEWSTATE, html); 
    nLen := Length(TAG_VIEWSTATE); 
    cVal := Copy(html,nIni+nLen, Length(html)); 
    cVal := Copy(cVal, 1, Pos('" />', cVal)-1); 
    viewState := cVal; 

    nIni := Pos(TAG_EVENTVALIDATION, html); 
    nLen := Length(TAG_EVENTVALIDATION); 
    cVal := Copy(html,nIni+nLen, Length(html)); 
    cVal := Copy(cVal, 1, Pos('" />', cVal)-1); 
    eventValidate := cVal; 
end; 

procedure TMainForm.p_Execute; 
var 
    params: TStringList; 
    Uri: TIdURI; 
    nI: Integer; 
begin 
    params := TStringList.Create; 
    Uri := TIdURI.Create(Cookies[0].Domain); 
    try 
    for nI := 0 to Pred(Cookies.Count) do 
     begin 
     IdCookieManager.AddServerCookie(Cookies[nI].ClientCookie, Uri); 
     if nI = 0 then 
      IdHttp.Request.CustomHeaders.Values['Cookie'] := Cookies[nI].ClientCookie 
     else 
      IdHttp.Request.CustomHeaders.Values['Cookie'] := IdHttp.Request.CustomHeaders.Values['Cookie'] + '; ' + Cookies[nI].ClientCookie; 
     end; 

    params.Add('__VIEWSTATE=' + viewState); 
    params.Add('__EVENTVALIDATION=' + eventValidate); 

    params.Add('__EVENTTARGET='); 
    params.Add('__EVENTARGUMENT='); 

    params.Add('ctl00$txtPalavraChave='); 

    params.Add('ctl00$ContentPlaceHolder1$txtChaveAcessoCompleta=' + edtKey.Text); 
    params.Add('ctl00$ContentPlaceHolder1$txtCaptcha=' + edtCode.Text); 

    params.Add('ctl00$ContentPlaceHolder1$btnConsultar=Continuar'); 
    params.Add('hiddenInputToUpdateATBuffer_CommonToolkitScripts=1'); 

    IdHttp.Request.ContentType := CONTENT_TYPE; 
    mem.Text := IdHttp.Post(URLPOST, params); 
    finally 
    params.Free; 
    Uri.Free; 
    end; 
end; 

end. 

ответ

0

Вы плохо разбираетесь в файлах cookie сервера. TIdURI.Create() ожидает полного URL-адреса, а AddServerCookie() требует полного URL-адреса, поэтому он может обрабатывать пути, различать HTTP-файлы и HTTPS-файлы cookie и т. Д. Но вы передаете TIdURI только имя домена самостоятельно, чего недостаточно. В этом случае, почему вы повторно добавляете файлы cookie обратно в TIdCookieManager, когда они уже существуют в TIdCookieManager? И почему вы устанавливаете свойство CustomHeaders.Values['Cookie'] вручную? Не делай этого. Все, что вам нужно сделать, это присвоить TIdCookieManager объекту TIdHTTP.CookieManager и убедитесь, что для свойства TIdHTTP.AllowCookies установлено значение True. Вот и все. TIdHTTP и TIdCookieManager будут выполнять всю тяжелую работу по получению, управлению и отправке файлов cookie для вас. Пока вы используете тот же объект TIdCookieManager для нескольких HTTP-запросов (даже если вы не используете тот же объект TIdHTTP), то файлы cookie будут автоматически сохраняться с одного запроса на следующий, если необходимо. В этом случае, если вы повторно используете один и тот же объект TIdHTTP, вам не нужно беспокоиться о создании TIdCookieManager вообще, так как TIdHTTP при необходимости создаст его, и он будет использоваться для жизни объекта TIdHTTP.

Попробуйте вместо этого:

unit Forms.MainForm; 

interface 

uses 
    Winapi.Windows, Winapi.Messages, 
    System.SysUtils, System.Variants, System.Classes, 
    Vcl.Forms, Vcl.Graphics, Vcl.Dialogs, Vcl.Controls, Vcl.ExtCtrls, 
    Vcl.StdCtrls, 
    IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, IdHTTP, 
    IdIOHandler, IdIOHandlerSocket, IdIOHandlerStack, IdSSL, IdSSLOpenSSL, 
    GIFImg; 

type 
    TMainForm = class(TForm) 
    mem: TMemo; 
    IdHttp: TIdHTTP; 
    IdSSLHandlerSocket: TIdSSLIOHandlerSocketOpenSSL; 
    panBottom: TPanel; 
    btnGo: TButton; 
    imgCaptcha: TImage; 
    edtKey: TEdit; 
    edtCode: TEdit; 
    lblInit: TLabel; 
    procedure FormShow(Sender: TObject); 
    procedure lblInitClick(Sender: TObject); 
    procedure btnGoClick(Sender: TObject); 
    private 
    viewState, eventValidate: string; 
    procedure GetHiddenFieldValues(html: string); 
    procedure p_Execute; 
    end; 

var 
    MainForm: TMainForm; 

const 
    HOST   = 'http://www.nfe.fazenda.gov.br'; 
    URLIMG  = HOST+'/scripts/srf/intercepta/captcha.aspx?opt=image'; 
    URLGET  = HOST+'/portal/consulta.aspx?tipoConsulta=completa&tipoConteudo=XbSeqxE8pl8='; 
    URLPOST  = HOST+'/portal/consultaCompleta.aspx?tipoConteudo=XbSeqxE8pl8='; 

implementation 

{$R *.dfm} 

procedure TMainForm.FormShow(Sender: TObject); 
begin 
    lblInitClick(Sender); 
end; 

procedure TMainForm.lblInitClick(Sender: TObject); 
var 
    response: TMemoryStream; 
    gif: TGIFImage; 
    html: string; 
begin 
    html := IdHttp.Get(URLGET); 
    mem.Text := html; 
    GetHiddenFieldValues(html); 

    gif := TGIFImage.Create; 
    try 
    response := TMemoryStream.Create; 
    try 
     IdHttp.Get(URLIMG, response); 
     response.Position := 0; 
     gif.LoadFromStream(response); 
    finally 
     response.Free; 
    end; 
    imgCaptcha.Picture.Assign(gif); 
    finally 
    gif.Free; 
    end; 
end; 

procedure TMainForm.btnGoClick(Sender: TObject); 
begin 
    p_Execute; 
end; 

procedure TMainForm.GetHiddenFieldValues(html: string); 
var 
    nIni, nLen: integer; 
    cVal: string; 
const 
    TAG_VIEWSTATE = '<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="'; 
    TAG_EVENTVALIDATION = '<input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION" value="'; 
begin 
    nIni := Pos(TAG_VIEWSTATE, html); 
    nLen := Length(TAG_VIEWSTATE); 
    cVal := Copy(html,nIni+nLen, Length(html)); 
    cVal := Copy(cVal, 1, Pos('" />', cVal)-1); 
    viewState := cVal; 

    nIni := Pos(TAG_EVENTVALIDATION, html); 
    nLen := Length(TAG_EVENTVALIDATION); 
    cVal := Copy(html,nIni+nLen, Length(html)); 
    cVal := Copy(cVal, 1, Pos('" />', cVal)-1); 
    eventValidate := cVal; 
end; 

procedure TMainForm.p_Execute; 
var 
    params: TStringList; 
begin 
    params := TStringList.Create; 
    try  
    params.Add('__VIEWSTATE=' + viewState); 
    params.Add('__EVENTVALIDATION=' + eventValidate); 

    params.Add('__EVENTTARGET='); 
    params.Add('__EVENTARGUMENT='); 

    params.Add('ctl00$txtPalavraChave='); 

    params.Add('ctl00$ContentPlaceHolder1$txtChaveAcessoCompleta=' + edtKey.Text); 
    params.Add('ctl00$ContentPlaceHolder1$txtCaptcha=' + edtCode.Text); 

    params.Add('ctl00$ContentPlaceHolder1$btnConsultar=Continuar'); 
    params.Add('hiddenInputToUpdateATBuffer_CommonToolkitScripts=1'); 

    mem.Text := IdHttp.Post(URLPOST, params); 
    finally 
    params.Free; 
    end; 
end; 

end. 

Теперь, с учетом сказанного, есть и другие проблемы:

1) Вы отправляете ваш params в http://www.nfe.fazenda.gov.br/portal/consultaCompleta.aspx?tipoConteudo=XbSeqxE8pl8=, но когда я иду к авторизации URL с веб-браузер и посмотреть на HTML, я вижу, что он действительно хочет, чтобы форма была отправлена ​​на http://www.nfe.fazenda.gov.br/consulta.aspx?tipoConsulta=completa&amp;tipoConteudo=XbSeqxE8pl8%3d. Вам не хватает части tipoConsulta=completa.

2) Вы разбор из фактических __VIEWSTATE и __EVENTVALIDATION значения из HTML, но отправка пустых __EVENTTARGET и __EVENTARGUMENT значения. Эти значения пустые в HTML, но они фактически заполняются динамически через клиентские скрипты.

3) есть другие поля <input> в HTML, которые вы не публикуете.

Веб-браузер публикует каждое поле <input>, которому присвоено не пустое value, независимо от того, назначено ли это значение статически или динамически. Вы должны сделать то же самое в своем приложении. Вероятно, HTTP-сервер ожидает, что все эти значения будут отправлены.Используйте сниффер пакетов, например Wireshark или Fiddler, чтобы увидеть, что на самом деле публикует веб-браузер, а затем повторите то же поведение в коде.

+0

спасибо! Проблема решена! –

0

спасибо!
Проблема решена!

С вашей информацией и Wireshark я понял, что мне нужен новый «GET». Решенный!

unit Forms.MainForm; 

interface 

uses 
    Winapi.Windows, Winapi.Messages, 
    System.SysUtils, System.Variants, System.Classes, 
    Vcl.Forms, Vcl.Graphics, Vcl.Dialogs, Vcl.Controls, Vcl.ExtCtrls, 
    Vcl.StdCtrls, 
    IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, IdHTTP, 
    IdIOHandler, IdIOHandlerSocket, IdIOHandlerStack, IdSSL, IdSSLOpenSSL, 
    IdCookieManager, IdCookie, IdURI, 
    GIFImg; 

type 
    TMainForm = class(TForm) 
    mem: TMemo; 
    IdHttp: TIdHTTP; 
    IdSSLHandlerSocket: TIdSSLIOHandlerSocketOpenSSL; 
    panBottom: TPanel; 
    btnGo: TButton; 
    imgCaptcha: TImage; 
    edtKey: TEdit; 
    edtCode: TEdit; 
    lblInit: TLabel; 
    procedure FormShow(Sender: TObject); 
    procedure lblInitClick(Sender: TObject); 
    procedure btnGoClick(Sender: TObject); 
    private 
    viewState, eventValidate: string; 
    procedure GetHiddenFieldValues(html: string); 
    procedure p_Execute; 
    end; 

var 
    MainForm: TMainForm; 

const 
    HOST   = 'http://www.nfe.fazenda.gov.br'; 
    URLIMG  = HOST + '/scripts/srf/intercepta/captcha.aspx?opt=image'; 
    URLGET  = HOST + '/portal/consulta.aspx?tipoConsulta=completa&tipoConteudo=XbSeqxE8pl8='; 
    URLPOST  = HOST + '/portal/consulta.aspx?tipoConsulta=completa&tipoConteudo=XbSeqxE8pl8%3d'; 
    URLGETRESULT = HOST + '/portal/consultaCompleta.aspx?tipoConteudo=XbSeqxE8pl8='; 
    CONTENT_TYPE = 'application/x-www-form-urlencoded'; 

implementation 

{$R *.dfm} 

procedure TMainForm.FormShow(Sender: TObject); 
begin 
    lblInitClick(Sender); 
end; 

procedure TMainForm.lblInitClick(Sender: TObject); 
var 
    response: TMemoryStream; 
    gif: TGIFImage; 
    html: string; 
begin 
    html := IdHttp.Get(URLGET); 
    mem.Text := html; 
    GetHiddenFieldValues(html); 

    response := TMemoryStream.Create; 
    gif := TGIFImage.Create; 
    try 
    IdHttp.Get(URLIMG, response); 
    response.Position := 0; 
    gif.LoadFromStream(response); 
    imgCaptcha.Picture.Assign(gif); 
    finally 
    gif.Free; 
    response.Free; 
    end; 
end; 

procedure TMainForm.btnGoClick(Sender: TObject); 
begin 
    p_Execute; 
end; 

procedure TMainForm.GetHiddenFieldValues(html: string); 
var 
    nIni, nLen: integer; 
    cVal: string; 
const 
    TAG_VIEWSTATE = '<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="'; 
    TAG_EVENTVALIDATION = '<input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION" value="'; 
begin 
    nIni := Pos(TAG_VIEWSTATE, html); 
    nLen := Length(TAG_VIEWSTATE); 
    cVal := Copy(html,nIni+nLen, Length(html)); 
    cVal := Copy(cVal, 1, Pos('" />', cVal)-1); 
    viewState := cVal; 

    nIni := Pos(TAG_EVENTVALIDATION, html); 
    nLen := Length(TAG_EVENTVALIDATION); 
    cVal := Copy(html,nIni+nLen, Length(html)); 
    cVal := Copy(cVal, 1, Pos('" />', cVal)-1); 
    eventValidate := cVal; 
end; 

procedure TMainForm.p_Execute; 
var 
    params: TStringList; 
begin 
    params := TStringList.Create; 
    try 
    params.Add('__VIEWSTATE=' + viewState); 
    params.Add('__EVENTVALIDATION=' + eventValidate); 

    params.Add('__EVENTTARGET='); 
    params.Add('__EVENTARGUMENT='); 

    params.Add('ctl00$txtPalavraChave='); 

    params.Add('ctl00$ContentPlaceHolder1$txtChaveAcessoCompleta=' + Trim(edtKey.Text)); 

    params.Add('ctl00$ContentPlaceHolder1$txtCaptcha=' + Trim(edtCode.Text)); 

    params.Add('ctl00$ContentPlaceHolder1$btnConsultar=Continuar'); 
    params.Add('hiddenInputToUpdateATBuffer_CommonToolkitScripts=1'); 

    mem.Text := IdHttp.Post(URLPOST, params); 

    mem.Text := IdHttp.Get(URLGETRESULT); 
    finally 
    params.Free; 
    end; 
end; 

end.