首先,抱歉我的英语不好!
我需要在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.
答案 0 :(得分:0)
您错误管理了服务器的Cookie。 TIdURI.Create()
需要一个完整的网址,而AddServerCookie()
需要一个完整的网址,以便它可以处理路径,区分HTTP和HTTPS Cookie等。但是您只传递TIdURI
个域名,这还不够。就此而言,当TIdCookieManager
中已存在Cookie时,为什么要将Cookie重新添加回TIdCookieManager
?为什么要手动设置CustomHeaders.Values['Cookie']
属性?不要做那些事情。您需要做的就是将TIdCookieManager
分配给TIdHTTP.CookieManager
属性,并确保TIdHTTP.AllowCookies
属性设置为True。而已。然后,TIdHTTP
和TIdCookieManager
将为您完成接收,管理和发送Cookie的所有艰苦工作。只要您对多个HTTP请求使用相同的TIdCookieManager
对象(即使您不使用相同的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=
,但是当我使用网络浏览器访问登录网址并查看HTML时,我发现它确实希望将表单发布到{ {1}}而是。您错过了http://www.nfe.fazenda.gov.br/consulta.aspx?tipoConsulta=completa&tipoConteudo=XbSeqxE8pl8%3d
部分。
2)您正在解析HTML中的实际tipoConsulta=completa
和__VIEWSTATE
值,但是会发送空白__EVENTVALIDATION
和__EVENTTARGET
值。这些值在HTML中是空白的,但它们实际上是通过客户端脚本动态填充的。
3)HTML中还有其他__EVENTARGUMENT
字段未发布。
网络浏览器会发布分配给它的非空<input>
的每个<input>
字段,无论该值是静态还是动态分配的。您需要在应用程序中执行相同的操作。 HTTP服务器可能期望发送所有这些值。使用数据包嗅探器(如Wireshark或Fiddler)查看Web浏览器实际发布的内容,然后在代码中复制相同的行为。
答案 1 :(得分: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.