【问题标题】:IdHttp + IdCookieManager + ASP.NET WebForm Page [Close]IdHttp + IdCookieManager + ASP.NET WebForm 页面 [关闭]
【发布时间】:2013-08-13 18:28:42
【问题描述】:

首先,对不起我的英语不好!

我需要在网站 www.nfe.fazenda.org.br 上进行查询。 为了获得最佳性能,我将组件 TIdHTTP 与 TIdCookieManager 一起使用。

本网站使用验证码来控制访问。所以,我正在尝试获取页面和验证码以获取 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.

【问题讨论】:

    标签: delphi captcha indy delphi-xe3 idhttp


    【解决方案1】:

    您对服务器的 cookie 管理不善。 TIdURI.Create() 需要一个完整的 URL,而AddServerCookie() 需要一个完整的 URL,以便它可以处理路径、区分 HTTP 和 HTTPS cookie 等。但是您传递的 TIdURI 本身只是一个域名,这还不够。

    TIdCookieManager 中已经存在 cookie 时,为什么还要将它们重新添加回 TIdCookieManager?为什么要手动设置CustomHeaders.Values['Cookie'] 属性?不要做那些事情。您需要做的就是将TIdCookieManager 分配给TIdHTTP.CookieManager 属性,并确保TIdHTTP.AllowCookies 属性设置为True。就是这样。然后TIdHTTPTIdCookieManager 将为您完成接收、管理和发送cookies 的所有繁重工作。只要您对多个 HTTP 请求使用相同的TIdCookieManager 对象(即使您不使用相同的TIdHTTP 对象),cookie 就会根据需要自动从一个请求持续到下一个请求。

    如果您重复使用相同的 TIdHTTP 对象,那么您根本不必担心创建 TIdCookieManager,因为 TIdHTTP 将在需要时在内部创建一个,并且它将在 @ 的生命周期内使用987654336@对象。

    试试这个:

    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=,但是当我使用 Web 浏览器访问登录 URL 并查看 HTML 时,我发现它实际上希望将表单发布到 http://www.nfe.fazenda.gov.br/consulta.aspx?tipoConsulta=completa&amp;tipoConteudo=XbSeqxE8pl8=。您缺少tipoConsulta=completa 部分。

    2) 您正在从 HTML 中解析出实际的 __VIEWSTATE__EVENTVALIDATION 值,但发送的是空白的 __EVENTTARGET__EVENTARGUMENT 值。这些值在 HTML 中是空白的,但它们实际上是通过客户端脚本动态填充的。

    3) HTML 中还有其他 &lt;input&gt; 字段您未发布。

    网络浏览器发布每个分配有非空value&lt;input&gt; 字段,无论该值是静态分配还是动态分配。您需要在您的应用程序中执行相同的操作。 HTTP 服务器可能希望发送所有这些值。使用数据包嗅探器(例如 Wireshark 或 Fiddler)查看 Web 浏览器实际发布的内容,然后在您的代码中复制相同的行为。

    【讨论】:

      【解决方案2】:

      非常感谢!
      问题解决了!

      根据您的信息和 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.
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-10-10
        • 1970-01-01
        • 1970-01-01
        • 2014-01-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多