【问题标题】:Fetch the content of a web page with DELPHI使用 DELPHI 获取网页内容
【发布时间】:2016-10-06 12:51:02
【问题描述】:

我正在尝试检索此页面的 <table><tbody> 部分:

http://www.mfinante.ro/infocodfiscal.html?captcha=null&cod=18505138

我正在使用 Delphi XE7。

我尝试使用IXMLHttpRequest、WinInet(InternetOpenURL()InternetReadFile())、TRestClient/TRestRequest/TRestResponseTIdHTTP.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

以这段代码为例:

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”功能,但其他网站返回正常响应。有人至少可以向我解释一下为什么这不起作用吗?

还有其他方法可以获取此网页的内容吗?是否有其他编程语言(Java、脚本等)可以在没有第三方软件的情况下执行此操作(例如使用 Firefox 源代码来模拟浏览器,获取页面,而不显示窗口,然后复制内容)。

【问题讨论】:

  • 你所说的胡言乱语看起来像是具有有效 HTML 和 Javascript 的正常响应。是什么让你觉得它有问题?
  • 是的,那里是java脚本,不是乱码,但是如果您使用链接的浏览器和ViewSource访问,则会出现完全不同的代码。
  • 在浏览器中加载页面后看到的可能是运行初始脚本的结果,该脚本可以在加载后修改页面内容。
  • 所以我检索到的是很多函数,代码如下:{var table = "00000000 77073096 EE0E612C 990951BA 076DC419 706AF48F E963A535 9E6495A3 0EDB8832 79DCB8A4 E0D888E 中没有表 tag 但存在。它是一个修改页面的脚本,实际上可能是这样,有没有办法获得在浏览器中看到的页面内容?
  • 您可以使用例如查看相同的原始回复Firefox 或 Chrome 中的开发人员工具(网络)。浏览器运行脚本,然后修改浏览器显示的页面。要在您的程序中实现同样的效果,最简单的方法可能是嵌入(并自动化)浏览器。

标签: delphi http-post indy http-get


【解决方案1】:

您可以为此使用 TWebBrowser。

看到这个帖子:How can I get HTML source code from TWebBrowser

RRUZ 的答案(您可以在 Internet 上的许多地方找到)不是您正在寻找的。这为您提供了原始 html 源代码,IdHttp.Get() 也是如此。

不过,Mehmet Fide 的回答将为您提供 DOM 的 HTML 源代码,正是您正在寻找的。​​p>

我在这里提供一个变体。 (它包括当时获得完整 DOCTYPE 所需的一些技巧。不确定它们是否仍然需要......)

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 Source。

但是,使用您的 URL,您会看到 OnDocumentComplete 事件触发了两次 :(,因此您需要从最后一次触发中获取 Html。

您可以参考这篇文章How do I avoid the OnDocumentComplete event for embedded iframe elements? 了解如何获取最终的 OnDocumentComplete 事件。但是,我尝试了它,但它对我不起作用。您可能需要使用其他策略来获取最后一个事件。

不确定您的需求,但您也可以通过禁用 WebBrowser 下载图像来优化此过程。我相信这是可能的。

【讨论】:

  • 确实,它触发了两次,第二次是正确的结果。
【解决方案2】:

这很正常,您确实检索到了正确的内容。在您的浏览器中发生的是脚本被执行并且页面被构建客户端。如果你想在你的代码中复制它,那么你需要做同样的事情。完全按照浏览器的方式执行脚本。

您在这里真正寻找的是所谓的无头浏览器。将其中之一集成到您的程序中。然后让无头浏览器处理请求,包括执行脚本。当它执行完脚本后,读取页面的修改内容。

【讨论】:

  • 所以,正如我所料,我需要一个解释器,一个知道如何运行该脚本的无头浏览器(例如来自 firefox 源代码)。是否有其他语言可以在没有浏览器的情况下本机执行此操作?
  • 如果我是你,我不会在 Delphi 中这样做。 github.com/dhamaniasad/HeadlessBrowsers
  • 是的。谢谢你。不幸的是,Delphi 是我的应用程序的主要开发代码,我用它碰了很多墙。幸运的是,我知道其他语言,所以我可以用其他语言制作小应用程序,然后从我的 delphi 应用程序中运行它们。在这些 Java、JavaScript 和 C++ 无头浏览器之间,你有最喜欢的吗?
  • 对此没有任何建议。我认为您需要自己对此进行研究,并找出最适合您特定需求的前进方式。
  • 我使用 PhantomJS(无头 webkit,有点像 chrome)来做这样的事情,但不是使用 Delphi。我会用 Karma 做这样的事情。 methodsandtools.com/tools/karma.php
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-12-23
  • 1970-01-01
  • 1970-01-01
  • 2013-07-28
  • 2018-07-13
  • 1970-01-01
  • 2010-11-06
相关资源
最近更新 更多