delphi中的webbrowser ,如何获取网站返回状态码

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了delphi中的webbrowser ,如何获取网站返回状态码相关的知识,希望对你有一定的参考价值。

在delphi中使用webbrowser发送一个连接,网站接收后返回一个状态码显示在webbrowser中,如何获取这个状态码?
例如:http://sms.api.bz/fetion.php?username=用户名&password=密码&sendto=用户&message=内容
然后如果用户名或者密码错误,网站就返回‘101’这个状态码
如何获取这个‘101’呢?

继承TWebbrowser类,网上去找 DWebBrowserEvents2 的接口声明。重写Invoke函数,在里面添加对NavigateError事件的处理。。。就能得到这个状态码了。 参考技术A 一般是在BeforeNavigate2事件中对URL进行拦截,比如如果你把你的url提交到服务器的时候,如果出现错误一般会跳转到错误页面,你可以让php开发人员把状态码和跳转页面一起返回,你对返回的url进行字符串解析,截取状态码的值,同时也可以控制你的webbrowser是否跳转到新页面中。回答完毕,谢谢!!! 参考技术B 楼主的这类程序使用IDHTTP比较方便!
建议看一下IDHTTP的相关文章!本回答被提问者采纳

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

【中文标题】如何从 WebBrowser 控件获取 XML (RAW/SOURCE)【英文标题】:How to get XML (RAW/SOURCE) from a WebBrowser Control 【发布时间】:2011-09-02 13:59:52 【问题描述】:

我在我的 Delphi 和 .Net C# 测试项目中使用 WebBrowser 控件导航到本地测试 XML 文件并尝试将内容保存回 .Net DocumentCompleted Event 和 Delphi @987654322 中的 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 上缝合,将显示另存为对话框(隐藏标志将被忽略)。

我还尝试从缓存(缓存 API)中获取 XML 数据,但在我的情况下,我什么也得不到,而且 2. 如果在客户机器上禁用缓存怎么办? ;-)

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

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

所以我在这里问你是否知道如何解决我的问题?

提前致谢, 干杯

输入:

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

输出:

<HTML><HEAD>
<STYLE>BODYfont:x-small 'Verdana';margin-right:1.5em
.ccursor:hand
.bcolor:red;font-family:'Courier New';font-weight:bold;text-decoration:none
.emargin-left:1em;text-indent:-1em;margin-right:1em
.kmargin-left:1em;text-indent:-1em;margin-right:1em
.tcolor:#990000
.xtcolor:#990099
.nscolor:red
.dtcolor:green
.mcolor:blue
.txfont-weight:bold
.dbtext-indent:0px;margin-left:1em;margin-top:0px;margin-bottom:0px;padding-left:.3em;border-left:1px solid #CCCCCC;font:small Courier
.difont:small Courier
.dcolor:blue
.picolor:blue
.cbtext-indent:0px;margin-left:1em;margin-top:0px;margin-bottom:0px;padding-left:.3em;font:small Courier;color:#888888
.cifont:small Courier;color:#888888
PREmargin: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>

【问题讨论】:

等等——为什么你不能直接用 WebClient 或 Indy 下载文件?看起来那些应该比涉及一个巨大的 UI 控件更简单。 嗯,这只是我在这里发布的一个示例。我编写了那个测试 xml/test 应用程序。真实场景非常复杂,需要用户在浏览器中进行交互,在用户完成所有操作后,浏览器和用户之间会发布一些帖子,直到最终结果是一个 XML 文件,您无法控制它的来源!这就是为什么! 【参考方案1】:

我认为您以错误的方式处理此问题。 TWebBrowser 控件是用于查看的可视控件。您也许可以从中提取基础数据,但从根本上说,使用视觉控制来下载某些东西(非视觉动作)并不是一个好方法。相反,您应该使用专用 API 下载文件。

仅供参考:没有 我使用 WebClient 或 Indy 的方式 访问 xml 的组件。我也 不能作为代理玩,因为...

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

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

    An HTML page scraper - 显然也适用于 XML How to show a progress indicator while downloading - 如果您的文件很小,可能没有用处

    InternetReadFile。这是我个人在自己的代码中使用的——我有一个小线程类来异步下载文件并在完成时通知主线程,使用这个函数实现。使用它:

    使用InternetOpen初始化互联网功能的使用;它返回一个句柄; 使用该句柄通过InternetOpenUrl 使用INTERNET_FLAG_HYPERLINK or INTERNET_FLAG_NO_UI 标志获取另一个句柄 然后在循环中使用该句柄和InternetReadFile 写入缓冲区,直到读取文件或终止您的线程。 别忘了使用InternetCloseHandle关闭句柄

    对不起,我不能发布源代码,但它们是简单的函数,你应该会发现它很容易编写。

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

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

“真实的场景非常复杂, 需要在浏览器中进行用户交互 在用户做了所有事情之后 之间有一些帖子 浏览器和用户直到最终结果 是您没有的 XML 文件 控制来自哪里!”

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

【讨论】:

感谢好友的评论并尝试指出另一种方法!我知道您在这里写下的每个调用和方法!我无法知道最终的 URL 是什么!来自服务器的结果(响应)基于用户的输入/操作,所有操作均由登录和身份验证处理,并为主要操作输入 PIN!这意味着用户在 web-From 中输入 PIN(发布到服务器),将根据 PIN 条目生成响应(从不完全相同且准确的响应)。 @Gohlool:你确定“没有办法......知道最终的 URL 是什么”?您无法使用其导航事件之一查看 Web 浏览器导航到的位置?【参考方案2】:

您可以在 TWebBrowser BeforeNavigate2 事件中对文件进行“影子”下载。 通过影子,我的意思是使用另一个库中的过程来下载文件,同时 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 事件工作。

【讨论】:

谢谢!好主意!但是......很好,这适用于我上面的示例,但不适用于与服务器结合的真实应用程序! ;-(但你得到了我的投票!;-) @Gohlool- 我的方法假设 TWebBrowser 显示的页面中有指向 XML 文件的链接,并且用户单击它。根据您的回复,我不得不假设这不是您的情况。所以我的问题是:你怎么知道 XML 文件已经准备好下载了,你又是怎么得到它的地址的?

以上是关于delphi中的webbrowser ,如何获取网站返回状态码的主要内容,如果未能解决你的问题,请参考以下文章

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

DELPHI中的webbrowser如何有效防止内存疏漏

delphi中 WebBrowser如何控制Frame下面的元素

delphi中 已知url='http://163.COM', 如何得到title='网易'。

delphi中WebBrowser控件怎么模拟点击网页框架中的按钮button?

delphi WebBrowser控件上网页验证码图片识别教程