使用 DELPHI 获取网页内容
Fetch the content of a web page with DELPHI
我正在尝试检索此页面的 <table><tbody>
部分:
http://www.mfinante.ro/infocodfiscal.html?captcha=null&cod=18505138
我正在使用 Delphi XE7。
我尝试使用 IXMLHttpRequest
、WinInet(InternetOpenURL()
、InternetReadFile()
)、TRestClient
/TRestRequest
/TRestResponse
、TIdHTTP.Get()
,但他们检索到的只是一些乱码,像这样:
<html><head><meta http-equiv="Pragma" content="no-cache"/>'#$D#$A'<meta http-equiv="Expires" content="-1"/>'#$D#$A'<meta http-equiv="CacheControl" content="no-cache"/>'#$D#$A'<script>'#$D#$A'(function(){p={g:"0119a4477bb90c7a81666ed6496cf13b5aad18374e35ca73f205151217be1217a93610c5877ece5575231e088ff52583c46a8e8807483e7185307ed65e",v:"87696d3d40d846a7c63fa2d10957202e",u:"1",e:"1",d:"1",a:"challenge
etc.
例如看这段代码:
program htttpget;
{$APPTYPE CONSOLE}
{$R *.res}
uses
SysUtils, HTTPApp, IdHTTP, ActiveX;
var
CoResult: Integer;
HTTP: TIdHTTP;
Query: String;
Buffer: String;
begin
try
CoResult := CoInitializeEx(nil, COINIT_MULTITHREADED);
if not((CoResult = S_OK) or (CoResult = S_FALSE)) then
begin
Writeln('Failed to initialize COM library.');
Exit;
end;
HTTP := TIdHTTP.Create;
Query := 'http://www.mfinante.ro/infocodfiscal.html?captcha=null' +
'&cod=18505138';
Buffer := HTTP.Get(Query);
writeln(Buffer);
HTTP.Destroy;
except
end;
end.
这个页面有什么问题?我这辈子没做过多少"get"功能,其他网站return正常回复。有人至少可以向我解释为什么这不起作用吗?
有没有其他方法可以得到这个网页的内容?是否有其他编程语言(Java、脚本等)可以在没有第三方软件的情况下执行此操作(例如使用 Firefox 源代码模拟浏览器,获取页面,而不显示 window,然后复制内容)。
这很正常,您确实正确检索了内容。在您的浏览器中发生的是脚本被执行并且页面被构建在客户端。如果你想在你的代码中复制它,那么你将需要做同样的事情。完全按照浏览器的方式执行脚本。
您在这里真正要找的是所谓的无头浏览器。将其中之一集成到您的程序中。然后让无头浏览器处理请求,包括执行脚本。当它执行完脚本后,读取页面修改后的内容。
您可以为此使用 TWebBrowser。
看到这个post:How can I get HTML source code from TWebBrowser
RRUZ
的答案,您可以在互联网上的许多地方找到,不是您要找的。这为您提供原始 html 来源,IdHttp.Get()
.
但是,Mehmet Fide
的回答将为您提供 DOM 的 HTML 来源, 就是您要找的 .
我在这里提供一个变体。 (它包括当时获得完整 DOCTYPE 所需的一些 hack。不确定是否仍然需要它们...)
function EndStr(const S: String; const Count: Integer): String;
var
I: Integer;
Index: Integer;
begin
Result := '';
for I := 1 to Count do
begin
Index := Length(S)-I+1;
if Index > 0 then
Result := S[Index] + Result;
end;
end;
function GetHTMLDocumentSource(WebBrowser: TWebBrowser; var Charset: String):
String;
var
Element: IHTMLElement;
Node: IHTMLDomNode;
Document: IHTMLDocument2;
I: Integer;
S: String;
begin
Result := '';
Document := WebBrowser.Document as IHTMLDocument2;
For I := 0 to Document.all.length -1 do
begin
Element := Document.all.item(I, 0) as IHTMLElement;
If Element.tagName = '!' Then
begin
Node := Element as IHTMLDomNode;
If (Node <> nil) and (Pos('CTYPE', UpperCase(Node.nodeValue)) > 0) Then
begin
S := VarToStr(Node.nodeValue); { don't change case of result }
if Copy(Uppercase(S), 1, 5) = 'CTYPE' then
S := 'DO' + S;
if Copy(Uppercase(S), 1, 7) = 'DOCTYPE' then
S := '<!' + S;
if Uppercase(S) = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 TRANSITIONAL//E' then
S := S +'N">';
if EndStr(Lowercase(S), 3) = '.dt' then
S := S + 'd"';
if EndStr(Lowercase(S), 5) = '.dtd"' then
S := S + '>';
Result := Result + S;
end;
end
Else
Result := Result + Element.outerHTML;
If Element.tagName = 'HTML' Then
Break;
end;
Charset := Document.charset;
end;
因此调用 WebBrowser.Navigate(URL)
,然后在 OnDocumentComplete
事件中检索 Html 源。
但是,对于 URL,您会看到 OnDocumentComplete 事件触发两次 :(,因此您需要从上次触发中获取 Html。
您可以参考此 post How do I avoid the OnDocumentComplete event for embedded iframe elements? 以获取有关如何获取最终 OnDocumentComplete 事件的信息。但是,我试过了,但它对我不起作用。您可能需要使用其他一些策略来获取最后一个事件。
不确定您的需求,但您也可以通过禁用 WebBrowser 下载图像来优化此过程。我相信这是可能的。
我正在尝试检索此页面的 <table><tbody>
部分:
http://www.mfinante.ro/infocodfiscal.html?captcha=null&cod=18505138
我正在使用 Delphi XE7。
我尝试使用 IXMLHttpRequest
、WinInet(InternetOpenURL()
、InternetReadFile()
)、TRestClient
/TRestRequest
/TRestResponse
、TIdHTTP.Get()
,但他们检索到的只是一些乱码,像这样:
<html><head><meta http-equiv="Pragma" content="no-cache"/>'#$D#$A'<meta http-equiv="Expires" content="-1"/>'#$D#$A'<meta http-equiv="CacheControl" content="no-cache"/>'#$D#$A'<script>'#$D#$A'(function(){p={g:"0119a4477bb90c7a81666ed6496cf13b5aad18374e35ca73f205151217be1217a93610c5877ece5575231e088ff52583c46a8e8807483e7185307ed65e",v:"87696d3d40d846a7c63fa2d10957202e",u:"1",e:"1",d:"1",a:"challenge
etc.
例如看这段代码:
program htttpget;
{$APPTYPE CONSOLE}
{$R *.res}
uses
SysUtils, HTTPApp, IdHTTP, ActiveX;
var
CoResult: Integer;
HTTP: TIdHTTP;
Query: String;
Buffer: String;
begin
try
CoResult := CoInitializeEx(nil, COINIT_MULTITHREADED);
if not((CoResult = S_OK) or (CoResult = S_FALSE)) then
begin
Writeln('Failed to initialize COM library.');
Exit;
end;
HTTP := TIdHTTP.Create;
Query := 'http://www.mfinante.ro/infocodfiscal.html?captcha=null' +
'&cod=18505138';
Buffer := HTTP.Get(Query);
writeln(Buffer);
HTTP.Destroy;
except
end;
end.
这个页面有什么问题?我这辈子没做过多少"get"功能,其他网站return正常回复。有人至少可以向我解释为什么这不起作用吗?
有没有其他方法可以得到这个网页的内容?是否有其他编程语言(Java、脚本等)可以在没有第三方软件的情况下执行此操作(例如使用 Firefox 源代码模拟浏览器,获取页面,而不显示 window,然后复制内容)。
这很正常,您确实正确检索了内容。在您的浏览器中发生的是脚本被执行并且页面被构建在客户端。如果你想在你的代码中复制它,那么你将需要做同样的事情。完全按照浏览器的方式执行脚本。
您在这里真正要找的是所谓的无头浏览器。将其中之一集成到您的程序中。然后让无头浏览器处理请求,包括执行脚本。当它执行完脚本后,读取页面修改后的内容。
您可以为此使用 TWebBrowser。
看到这个post:How can I get HTML source code from TWebBrowser
RRUZ
的答案,您可以在互联网上的许多地方找到,不是您要找的。这为您提供原始 html 来源,IdHttp.Get()
.
但是,Mehmet Fide
的回答将为您提供 DOM 的 HTML 来源, 就是您要找的 .
我在这里提供一个变体。 (它包括当时获得完整 DOCTYPE 所需的一些 hack。不确定是否仍然需要它们...)
function EndStr(const S: String; const Count: Integer): String;
var
I: Integer;
Index: Integer;
begin
Result := '';
for I := 1 to Count do
begin
Index := Length(S)-I+1;
if Index > 0 then
Result := S[Index] + Result;
end;
end;
function GetHTMLDocumentSource(WebBrowser: TWebBrowser; var Charset: String):
String;
var
Element: IHTMLElement;
Node: IHTMLDomNode;
Document: IHTMLDocument2;
I: Integer;
S: String;
begin
Result := '';
Document := WebBrowser.Document as IHTMLDocument2;
For I := 0 to Document.all.length -1 do
begin
Element := Document.all.item(I, 0) as IHTMLElement;
If Element.tagName = '!' Then
begin
Node := Element as IHTMLDomNode;
If (Node <> nil) and (Pos('CTYPE', UpperCase(Node.nodeValue)) > 0) Then
begin
S := VarToStr(Node.nodeValue); { don't change case of result }
if Copy(Uppercase(S), 1, 5) = 'CTYPE' then
S := 'DO' + S;
if Copy(Uppercase(S), 1, 7) = 'DOCTYPE' then
S := '<!' + S;
if Uppercase(S) = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 TRANSITIONAL//E' then
S := S +'N">';
if EndStr(Lowercase(S), 3) = '.dt' then
S := S + 'd"';
if EndStr(Lowercase(S), 5) = '.dtd"' then
S := S + '>';
Result := Result + S;
end;
end
Else
Result := Result + Element.outerHTML;
If Element.tagName = 'HTML' Then
Break;
end;
Charset := Document.charset;
end;
因此调用 WebBrowser.Navigate(URL)
,然后在 OnDocumentComplete
事件中检索 Html 源。
但是,对于 URL,您会看到 OnDocumentComplete 事件触发两次 :(,因此您需要从上次触发中获取 Html。
您可以参考此 post How do I avoid the OnDocumentComplete event for embedded iframe elements? 以获取有关如何获取最终 OnDocumentComplete 事件的信息。但是,我试过了,但它对我不起作用。您可能需要使用其他一些策略来获取最后一个事件。
不确定您的需求,但您也可以通过禁用 WebBrowser 下载图像来优化此过程。我相信这是可能的。