2013-08-13 5 views
1

첫 번째로, 나쁜 영어로 유감스럽게 생각합니다!IdHttp + IdCookieManager + ASP.NET 웹 폼 페이지 [닫기]

웹 사이트 www.nfe.fazenda.org.br에서 쿼리를 수행해야합니다. 최고의 성능을 위해 TIdCookieManager와 함께 TIdHTTP 구성 요소를 사용하십시오.

이 사이트는 제어 액세스에 captcha를 사용합니다. 그래서, 나는 쿠키와 쿠키를 얻기위한 captcha를 얻으 려하고있다.

사용자가 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

서버의 쿠키를 잘못 처리했습니다. TIdURI.Create()은 전체 URL이 필요하고 AddServerCookie()은 경로를 처리하고 HTTP 쿠키와 HTTPS 쿠키를 구별 할 수 있도록 전체 URL이 필요합니다. 그러나 도메인 이름 만 TIdURI 만 전달하면 충분하지 않습니다. 그렇다면 TIdCookieManager에 이미있는 TIdCookieManager에 쿠키를 다시 추가하는 이유는 무엇입니까? 그리고 왜 수동으로 CustomHeaders.Values['Cookie'] 속성을 설정하고 있습니까? 그 일을하지 마십시오. 수행 할 작업은 TIdCookieManagerTIdHTTP.CookieManager 속성에 할당하고 TIdHTTP.AllowCookies 속성이 True로 설정되어 있는지 확인하는 것입니다. 그게 전부 야. TIdHTTPTIdCookieManager은 쿠키 수신, 관리 및 전송과 관련된 모든 작업을 수행합니다. 같은 TIdCookieManager 개체를 여러 개의 HTTP 요청에 사용하는 경우 (동일한 TIdHTTP 개체를 사용하지 않더라도) 쿠키는 필요에 따라 한 요청에서 다음 요청으로 자동으로 지속됩니다. 다시 말하면 동일한 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) 나는에 로그인 URL에 갈 때 당신은 당신의 paramshttp://www.nfe.fazenda.gov.br/portal/consultaCompleta.aspx?tipoConteudo=XbSeqxE8pl8=에 게시되지만, 웹 브라우저와 HTML을 보면 실제로 양식이 http://www.nfe.fazenda.gov.br/consulta.aspx?tipoConsulta=completa&amp;tipoConteudo=XbSeqxE8pl8%3d에 게시되기를 원합니다. tipoConsulta=completa 부분이 누락되었습니다.

2) HTML의 실제 __VIEWSTATE__EVENTVALIDATION 값을 구문 분석하지만 공백을 __EVENTTARGET__EVENTARGUMENT 값으로 보냅니다. 이러한 값은 HTML에서는 공백이지만 실제로는 클라이언트 측 스크립트를 통해 동적으로 채워집니다.

3) 게시하지 않는 HTML에는 다른 <input> 필드가 있습니다.

웹 브라우저는 필드에 비어 있지 않은 value이 할당 된 모든 필드를 정적 또는 동적으로 할당하여 게시합니다. 응용 프로그램에서 동일한 작업을 수행해야합니다. HTTP 서버는 모든 값을 전송할 것으로 예상합니다.Wireshark 또는 Fiddler와 같은 패킷 스니퍼를 사용하여 웹 브라우저가 실제로 게시 한 것을보고 해당 코드에서 동일한 동작을 복제하십시오.

+0

대단히 감사합니다. 문제가 해결되었습니다! –

0

대단히 감사합니다.
문제가 해결되었습니다!

귀하의 정보와 Wireshark를 통해 나는 새로운 "획득"이 필요하다는 것을 깨달았습니다. 해결!

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.