如何从WebBrowser控件获取XML(RAW/SOURCE)

本文关键字:RAW SOURCE XML 获取 WebBrowser 控件 | 更新日期: 2023-09-27 17:57:47

我在Delphi和.Net C#测试项目中使用WebBrowser控件导航到本地测试XML文件,并尝试在.Net DocumentCompleted事件和Delphi onNavigateComple2事件中将内容保存回XML文件。

问题是,我总是得到HTML,它将被浏览器转换以供查看(检查我的输出:我使用以下代码保存了它)

procedure TForm1.SaveHTMLSourceToFile(const FileName: string;
  WB: TWebBrowser);
var
  PersistStream: IPersistStreamInit;
  FileStream: TFileStream;
  Stream: IStream;
  SaveResult: HRESULT;
begin
  PersistStream := WB.Document as IPersistStreamInit;
  FileStream := TFileStream.Create(FileName, fmCreate);
  try
    Stream := TStreamAdapter.Create(FileStream, soReference) as IStream;
    SaveResult := PersistStream.Save(Stream, True);
    if FAILED(SaveResult) then
      MessageBox(Handle, 'Fail to save source', 'Error', 0);
  finally
    FileStream.Free;
  end;
end;

嗯,我几乎什么都试过了,到处找过,但直到现在都找不到有用的。使用下面的Delphi代码,我设法显示了工作的SOURCE(这意味着源代码在那里),但我不能使用它,因为它会播种一个对话框,并且不容易获得数据并关闭该对话框(在我的测试用例中,我得到了带有xml内容的notepad.exe)

  AWebBrowser.Document.QueryInterface(IOleCommandTarget, CmdTarget) ;
  if CmdTarget <> nil then
  try
    CmdTarget.Exec(PtrGUID, HTMLID_VIEWSOURCE, 0, vaIn, vaOut) ;
  finally
    CmdTarget._Release;
  end;

我还设法用xxx HIDE xxx标志调用了SAVE AS调用,但它缝合了IE 5,将显示另存为对话框(隐藏标志将被忽略)。

我还尝试从Cache(Cacheneneneba API)获取XML数据,但在我的情况下,我什么都得不到。如果在客户机器上禁用了缓存,该怎么办?;-)

InnerText或InnerHTML atc。不能使用,因为它们包含-和+字符,并且不代表原始原始原始数据(SOURCE)

仅供参考:我无法使用WebClient或Indy组件访问xml。我也不能充当代理,因为在客户机器上打开端口(比如8080)的问题对特权用户访问来说很痛苦。

所以我来了,问你是否知道如何解决我的问题?

提前感谢,干杯

输入:

<?xml version="1.0" encoding="UTF-8"?>
<test><data>xxxx</data></test>

输出:

<HTML><HEAD>
<STYLE>BODY{font:x-small 'Verdana';margin-right:1.5em}
.c{cursor:hand}
.b{color:red;font-family:'Courier New';font-weight:bold;text-decoration:none}
.e{margin-left:1em;text-indent:-1em;margin-right:1em}
.k{margin-left:1em;text-indent:-1em;margin-right:1em}
.t{color:#990000}
.xt{color:#990099}
.ns{color:red}
.dt{color:green}
.m{color:blue}
.tx{font-weight:bold}
.db{text-indent:0px;margin-left:1em;margin-top:0px;margin-bottom:0px;padding-left:.3em;border-left:1px solid #CCCCCC;font:small Courier}
.di{font:small Courier}
.d{color:blue}
.pi{color:blue}
.cb{text-indent:0px;margin-left:1em;margin-top:0px;margin-bottom:0px;padding-left:.3em;font:small Courier;color:#888888}
.ci{font:small Courier;color:#888888}
PRE{margin:0px;display:inline}</STYLE>
<SCRIPT><!--
function f(e){
if (e.className=="ci"){if (e.children(0).innerText.indexOf("'n")>0) fix(e,"cb");}
if (e.className=="di"){if (e.children(0).innerText.indexOf("'n")>0) fix(e,"db");}
e.id="";
}
function fix(e,cl){
e.className=cl;
e.style.display="block";
j=e.parentElement.children(0);
j.className="c";
k=j.children(0);
k.style.visibility="visible";
k.href="#";
}
function ch(e){
mark=e.children(0).children(0);
if (mark.innerText=="+"){
mark.innerText="-";
for (var i=1;i<e.children.length;i++)
e.children(i).style.display="block";
}
else if (mark.innerText=="-"){
mark.innerText="+";
for (var i=1;i<e.children.length;i++)
e.children(i).style.display="none";
}}
function ch2(e){
mark=e.children(0).children(0);
contents=e.children(1);
if (mark.innerText=="+"){
mark.innerText="-";
if (contents.className=="db"||contents.className=="cb")
contents.style.display="block";
else contents.style.display="inline";
}
else if (mark.innerText=="-"){
mark.innerText="+";
contents.style.display="none";
}}
function cl(){
e=window.event.srcElement;
if (e.className!="c"){e=e.parentElement;if (e.className!="c"){return;}}
e=e.parentElement;
if (e.className=="e") ch(e);
if (e.className=="k") ch2(e);
}
function ex(){}
function h(){window.status=" ";}
document.onclick=cl;
--></SCRIPT>
</HEAD>
<BODY class="st"><DIV class="e">
<SPAN class="b">&nbsp;</SPAN>
<SPAN class="m">&lt;?</SPAN><SPAN class="pi">xml version="1.0" encoding="UTF-8" </SPAN><SPAN class="m">?&gt;</SPAN>
</DIV>
<DIV class="e">
<DIV class="c" STYLE="margin-left:1em;text-indent:-2em"><A href="#" onclick="return false" onfocus="h()" class="b">-</A>
<SPAN class="m">&lt;</SPAN><SPAN class="t">test</SPAN><SPAN class="m">&gt;</SPAN></DIV>
<DIV><DIV class="e"><DIV STYLE="margin-left:1em;text-indent:-2em">
<SPAN class="b">&nbsp;</SPAN>
<SPAN class="m">&lt;</SPAN><SPAN class="t">data</SPAN><SPAN class="m">&gt;</SPAN><SPAN class="tx">xxxx</SPAN><SPAN class="m">&lt;/</SPAN><SPAN class="t">data</SPAN><SPAN class="m">&gt;</SPAN>
</DIV></DIV>
<DIV><SPAN class="b">&nbsp;</SPAN>
<SPAN class="m">&lt;/</SPAN><SPAN class="t">test</SPAN><SPAN class="m">&gt;</SPAN></DIV>
</DIV></DIV>
</BODY>
</HTML>

如何从WebBrowser控件获取XML(RAW/SOURCE)

我认为你处理这个问题的方式不对。TWebBrowser控件是用于查看的视觉控件。您可能能够从中提取底层数据,但从根本上讲,使用视觉控件下载某些内容(非视觉操作)不是一个好方法。相反,您应该使用专用的API下载该文件。

仅供参考:没有我使用WebClient或Indy的方式组件访问xml。我也无法作为代理播放,因为。。。

你没有这些组件吗?在这种情况下,我建议您使用以下任一方法:

  1. TDownloadURL是一个内置类,可用于简单的文件下载。使用它的一些例子:

    • HTML页面抓取器-显然也适用于XML
    • 如何在下载时显示进度指示器-如果您的文件很小,则可能没有用处
  2. InternetReadFile。这是我个人在自己的代码中使用的——我有一个小线程类来异步下载文件,并在文件完成时通知主线程,使用此函数实现。使用人:

    • 使用InternetOpen初始化互联网功能的使用;它返回一个句柄
    • 使用该句柄使用INTERNET_FLAG_HYPERLINK or INTERNET_FLAG_NO_UI标志获取另一个使用InternetOpenUrl的句柄
    • 然后在向缓冲区写入的循环中,将该句柄与InternetReadFile一起使用,直到文件被读取或线程终止
    • 不要忘记使用InternetCloseHandle关闭手柄

    很抱歉,我不能发布源代码,但它们是简单的函数,你应该觉得写起来很容易。

这些方法将获得一个文件或一个缓冲区,每个缓冲区都包含XML文件的原始内容。

编辑:我看到你解释了为什么不能使用Indy:

"实际情况非常复杂需要在浏览器中进行用户交互在用户完成所有操作之后在浏览器和用户直到最终结果是您没有的XML文件控制is的来源!"

我不确定这是否会阻止您使用Indy:相反,您只需要获得这个XML的位置。你不能控制它在哪里并不重要,你只需要找到它在哪里。如果你只有一个链接(你已经可以从浏览器中获得HTML了——事实上,这是你的问题!),或者看看TWebBrowser文档的最终位置,然后下载它。换句话说,让用户做他们必须做的任何事情来导航到最终的XML文件,但与其试图从web浏览器控件中提取它,不如自己下载它。

您可以在TWebBrowser BeforeNavigate2事件中对文件进行"影子"下载
所谓shadow,我的意思是在TWebBrowser下载文件的同时,使用另一个库中的过程来下载文件。这样,你就可以在不被TWebBrowser修改的情况下获得文件。

我写了一个测试应用程序,我所要做的就是获取文件内容

procedure TForm1.WebBrowserBeforeNavigate2(Sender: TObject;
  const pDisp: IDispatch; var URL, Flags, TargetFrameName, PostData,
  Headers: OleVariant; var Cancel: WordBool);
begin
  HttpGetText(URL,Memo1.Lines);
end;

HttpGetText是Synapse库中的一个阻塞函数http://www.ararat.cz/synapse/doku.php/start

您也可以使用ICS、Indy或TDownLoadURL。注意,TDownLoadURL没有被阻止,我从来没能让它的AfterDownload事件正常工作。