1

まず、下手な英語でごめんなさい!

ウェブサイト www.nfe.fazenda.org.br でクエリを実行する必要があります。最高のパフォーマンスを得るには、TIdCookieManager でコンポーネント TIdHTTP を使用しています。

このサイトでは、アクセス制御にキャプチャを使用しています。そのため、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.
4

2 に答える 2

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.
于 2013-08-14T13:24:45.900 に答える
0

サーバーの Cookie を誤って管理しています。 TIdURI.Create()は完全な URL を想定しており、AddServerCookie()パスを処理したり、HTTP と HTTPS の Cookie を区別したりできるように、完全な URL を必要とします。しかしTIdURI、ドメイン名だけを渡すだけでは不十分です。

TIdCookieManagerCookieが に既に存在するのに、なぜ Cookie を に再度追加するのTIdCookieManagerですか? そして、なぜCustomHeaders.Values['Cookie']プロパティを手動で設定するのですか? それらのことをしないでください。プロパティに を割り当て、TIdCookieManagerプロパティが True に設定されてTIdHTTP.CookieManagerいることを確認するだけです。TIdHTTP.AllowCookiesそれでおしまい。 TIdHTTPその後、Cookie の受信、管理、およびTIdCookieManager送信のすべての面倒な作業を行います。複数の HTTP リクエストに同じオブジェクトを使用している限りTIdCookieManager(同じオブジェクトを使用しなくてもTIdHTTP)、Cookie は必要に応じてあるリクエストから次のリクエストまで自動的に保持されます。

同じオブジェクトを再利用する場合、必要に応じて TIdHTTP が内部でオブジェクトを作成し、オブジェクトの存続期間中使用するため、オブジェクトのTIdHTTP作成について心配する必要はまったくありません。TIdCookieManagerTIdHTTP

代わりにこれを試してください:

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) に投稿していますparamshttp://www.nfe.fazenda.gov.br/portal/consultaCompleta.aspx?tipoConteudo=XbSeqxE8pl8=、Web ブラウザーでログイン URL にアクセスして HTML を見ると、実際にはフォームを に投稿する必要があることがわかりますhttp://www.nfe.fazenda.gov.br/consulta.aspx?tipoConsulta=completa&tipoConteudo=XbSeqxE8pl8=。その部分がありませんtipoConsulta=completa

2) HTML から実際の値__VIEWSTATEと値を解析していますが、空白の値と値を送信しています。これらの値は HTML では空白ですが、実際にはクライアント側のスクリプトを介して動的に入力されます。__EVENTVALIDATION__EVENTTARGET__EVENTARGUMENT

3) あなたが投稿していない HTML の他の<input>フィールドがあります。

Web ブラウザーは、値が静的に割り当てられているか動的に割り当てられているかに関係なく、<input>空でない値が割り当てられているすべてのフィールドを投稿します。valueアプリケーションでも同じことを行う必要があります。HTTP サーバーは、これらの値がすべて送信されることを想定している可能性があります。Wireshark や Fiddler などのパケット スニファーを使用して、Web ブラウザーが実際に投稿する内容を確認し、コードで同じ動作を再現します。

于 2013-08-14T04:24:40.350 に答える