2

如何以编程方式单击下载按钮后下载文件,因此不需要知道下载文件的 url。

文件下载后会出现提示并询问您是否要保存文件,按“是”后,另一个提示会询问您要保存文件的位置。因此,文件首先下载,可能会在某个地方的缓冲区中,在初始下载后,会出现提示。

那么,一旦单击按钮,您如何捕获下载流并将其保存为某个文件,而不会出现弹出提示?

(单击按钮的任何方法都可以,以下应该可以。)

procedure TForm1.Button1Click(Sender: TObject);
var
  x: integer;
  ovLinks: OleVariant;
begin
  WebBrowser1.Navigate('The web page');
  //wait for page to down load
  ovLinks := WebBrowser1.OleObject.Document.all.tags('A');
  if ovLinks.Length > 0 then
  begin
    for x := 0 to ovLinks.Length-1 do
      begin
        if Pos('id of button', ovLinks.Item(x).id) > 0 then
        //or if Pos('href of button', ovLinks.Item(x).href) > 0 then
        begin
          ovLinks.Item(x).click;
          Break;
        end;
      end;
  end;
end;

这个问题的原因是:文件的url总是找不到。例如:在这个网站上,我无法以编程方式找到网址,但在按下导出按钮后,使用 IE 将文件下载到“临时 Internet 文件”文件夹中。在 IE 的“临时 Internet 文件”文件夹中,它有一个“Internet 地址”列,其中显示了 url。但在 Chrome 中不存在这样的数据。但是,在这个网站上,我可以通过编程方式找到网址,但是当我下载文件时,按“此处”,该文件不会出现在 IE 的“临时 Internet 文件”文件夹中。对于其他网站,可以在文件夹中找到 url,并以编程方式找到它,但在其他网站上,无论哪种方式都找不到 url。

4

2 回答 2

9

IDownloadManager接口及其Download方法实现到您的 Web 浏览器控件,您可以简单地控制您需要的内容。每当您要下载文件时都会调用该Download方法(仅当弹出另存为对话框时)。

1. 嵌入式网页浏览器

您可以使用Embedded Web Browser已实现此接口并触发与OnFileDownload中相同命名事件不同的控件TWebBrowser。参见例如this thread如何使用它。

2.自己做

另一种选择是您可以TWebBrowser自己实现它。在下面的示例中,我使用 interposed 类只是为了展示原理,但是将其包装为组件非常容易(这就是我OnBeforeFileDownload发布的原因)。

2.1。OnBeforeFileDownload 事件

TWebBrowser这个插入类中的唯一扩展是OnBeforeFileDownload在下载文件时触发的事件(在弹出另存为对话框之前,而不是OnFileDownload事件,而不是在下载文档本身时)。如果您不为其编写事件处理程序,则 Web 浏览器控件将像以前一样运行(显示另存为对话框)。如果您编写事件处理程序并将其声明的参数返回 False Allowed,则文件保存将被取消。如果您将参数返回 True Allowed(默认情况下),将显示另存为对话框。请注意,如果您通过设置Allowed为 False 来取消下载,则需要自己下载文件(正如我在本例中使用 Indy 同步所做的那样)。为此,有FileSource常量参数,包含下载文件的 URL。以下是事件参数概述:

  • Sender (TObject) - 事件发送者
  • FileSource (WideString) - 源文件 URL
  • Allowed (Boolean) - 声明的布尔参数,它决定是否允许文件下载(默认值为 True)

2.2. IDownloadManager 实现

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  StdCtrls, OleServer, OleCtrls, Dialogs, ActiveX, MSHTML, UrlMon, SHDocVw,
  IdHTTP;

const
  IID_IDownloadManager: TGUID = '{988934A4-064B-11D3-BB80-00104B35E7F9}';
  SID_SDownloadManager: TGUID = '{988934A4-064B-11D3-BB80-00104B35E7F9}';

type
  IDownloadManager = interface(IUnknown)
    ['{988934A4-064B-11D3-BB80-00104B35E7F9}']
    function Download(pmk: IMoniker; pbc: IBindCtx; dwBindVerb: DWORD;
      grfBINDF: DWORD; pBindInfo: PBindInfo; pszHeaders: PWideChar;
      pszRedir: PWideChar; uiCP: UINT): HRESULT; stdcall;
  end;
  TBeforeFileDownloadEvent = procedure(Sender: TObject; const FileSource: WideString;
    var Allowed: Boolean) of object;
  TWebBrowser = class(SHDocVw.TWebBrowser, IServiceProvider, IDownloadManager)
  private
    FFileSource: WideString;
    FOnBeforeFileDownload: TBeforeFileDownloadEvent;
    function QueryService(const rsid, iid: TGUID; out Obj): HRESULT; stdcall;
    function Download(pmk: IMoniker; pbc: IBindCtx; dwBindVerb: DWORD;
      grfBINDF: DWORD; pBindInfo: PBindInfo; pszHeaders: PWideChar;
      pszRedir: PWideChar; uiCP: UINT): HRESULT; stdcall;
  protected
    procedure InvokeEvent(ADispID: TDispID; var AParams: TDispParams); override;
  published
    property OnBeforeFileDownload: TBeforeFileDownloadEvent read FOnBeforeFileDownload write FOnBeforeFileDownload;
  end;

type
  TForm1 = class(TForm)
    Button1: TButton;
    WebBrowser1: TWebBrowser;
    FileSourceLabel: TLabel;
    FileSourceEdit: TEdit;
    ShowDialogCheckBox: TCheckBox;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    procedure BeforeFileDownload(Sender: TObject; const FileSource: WideString;
      var Allowed: Boolean);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

{ TWebBrowser }

function TWebBrowser.Download(pmk: IMoniker; pbc: IBindCtx; dwBindVerb,
  grfBINDF: DWORD; pBindInfo: PBindInfo; pszHeaders, pszRedir: PWideChar;
  uiCP: UINT): HRESULT;
var
  Allowed: Boolean;
begin
  Result := E_NOTIMPL;
  if Assigned(FOnBeforeFileDownload) then
  begin
    Allowed := True;
    if pszRedir <> '' then
      FFileSource := pszRedir;
    FOnBeforeFileDownload(Self, FFileSource, Allowed);
    if not Allowed then
      Result := S_OK;
  end;
end;

procedure TWebBrowser.InvokeEvent(ADispID: TDispID; var AParams: TDispParams);
begin
  inherited;
  // DispID 250 is the BeforeNavigate2 dispinterface and to the FFileSource here
  // is stored the URL parameter (for cases, when the IDownloadManager::Download
  // won't redirect the URL and pass empty string to the pszRedir)
  if ADispID = 250 then
    FFileSource := OleVariant(AParams.rgvarg^[5]);
end;

function TWebBrowser.QueryService(const rsid, iid: TGUID; out Obj): HRESULT;
begin
  Result := E_NOINTERFACE;
  Pointer(Obj) := nil;
  if Assigned(FOnBeforeFileDownload) and IsEqualCLSID(rsid, SID_SDownloadManager) and
    IsEqualIID(iid, IID_IDownloadManager) then
  begin
    if Succeeded(QueryInterface(IID_IDownloadManager, Obj)) and
      Assigned(Pointer(Obj))
    then
      Result := S_OK;
  end;
end;

{ TForm1 }

procedure TForm1.Button1Click(Sender: TObject);
var
  HTMLWindow: IHTMLWindow2;
  HTMLDocument: IHTMLDocument2;
begin
  WebBrowser1.Navigate('http://financials.morningstar.com/income-statement/is.html?t=AAPL&ops=clear');
  while WebBrowser1.ReadyState <> READYSTATE_COMPLETE do
    Application.ProcessMessages;

  HTMLDocument := WebBrowser1.Document as IHTMLDocument2;
  if not Assigned(HTMLDocument) then
    Exit;
  HTMLWindow := HTMLDocument.parentWindow;
  if Assigned(HTMLWindow) then
  try
    HTMLWindow.execScript('SRT_stocFund.Export()', 'JavaScript');
  except
    on E: Exception do
      ShowMessage(E.Message);
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  ReportMemoryLeaksOnShutdown := True;
  WebBrowser1.OnBeforeFileDownload := BeforeFileDownload;
end;

procedure TForm1.BeforeFileDownload(Sender: TObject; const FileSource: WideString;
  var Allowed: Boolean);
var
  IdHTTP: TIdHTTP;
  FileTarget: string;
  FileStream: TMemoryStream;
begin
  FileSourceEdit.Text := FileSource;
  Allowed := ShowDialogCheckBox.Checked;
  if not Allowed then
  try
    IdHTTP := TIdHTTP.Create(nil);
    try
      FileStream := TMemoryStream.Create;
      try
        IdHTTP.HandleRedirects := True;
        IdHTTP.Get(FileSource, FileStream);
        FileTarget := IdHTTP.URL.Document;
        if FileTarget = '' then
          FileTarget := 'File';
        FileTarget := ExtractFilePath(ParamStr(0)) + FileTarget;
        FileStream.SaveToFile(FileTarget);
      finally
        FileStream.Free;
      end;
    finally
      IdHTTP.Free;
    end;
    ShowMessage('Downloading finished! File has been saved as:' + sLineBreak +
      FileTarget);
  except
    on E: Exception do
      ShowMessage(E.Message);
  end;
end;

end.

2.3. 下载管理器项目

您可以将上述代码(用 Delphi 2009 编写)作为一个完整的项目下载from here

于 2012-11-15T00:08:25.197 回答
0

我不知道这是否会让你到达你需要去的地方,但它似乎很有希望。使用我这里的 TWebBrowser(从“Microsoft Internet Controls 1.1 版”导出),您可以使用 OnBeforeNavigate2 事件来监视 Web 浏览器处理的所有 URL。您从那里遇到的问题是确定您需要做什么,捕获 URL,然后自己处理。这是我在您展示的第一个网站上使用控件的五分钟内的一个简短示例。

procedure TForm1.WebBrowser1BeforeNavigate2(Sender: TObject;
     pDisp: IDispatch; var URL, Flags, TargetFrameName, PostData,
     Headers: OleVariant; var Cancel: WordBool);
  begin
    Edit1.Text := String(URL);
    if Pos('CSV', Edit1.Text) > 0 then
      Cancel := true;
  end;

如您所见,有很多参数,您必须找到文档才能了解它们的含义。但在我的简短示例中,我所做的是将导航 URL 放入 Edit1.Text(如果您真的想观看正在发生的事情,最好使用 TMemo)。鉴于您的示例,实际上没有任何迹象表明它是直接下载的文件,但是使用上面的代码,我可以取消浏览器的操作(显示下载提示等),然后将 URL 放在 Edit1 框中在行动。如果要进一步挖掘,我相信您可以查看有问题的标题并确定该网站是否打算向您发送您应该下载的文件,因为 URL 本身并没有说“CSV文件”(把http://financials.morningstar.com/ajax/ReportProcess4CSV.html?t=AAPL®ion=usa&culture=us_EN&reportType=is&period=12&dataType=A&order=asc&columnYear=5&rounding=3&view=raw&productCode=USA&r=809199&denominatorView=raw&number=3进入网络浏览器下载有问题的 CSV 文件)。

希望这对你来说是一个好的开始。

于 2012-11-14T21:20:04.427 回答