如何从WebBrowser控件中的onclick事件获取实际的JavaScript值?

14
我正在寻找一种方法来获取在onclick内定义的JavaScript代码。 我使用的是.NET 2.0 C# Visual Studio 2005。 示例:
<span id="foo" onclick+"window.location.href='someURL'>click here</span>

我的目标是获取字符串 "window.location.href='someURL'"

场景:

用户点击WebBrowser控件内的网页元素,例如上面显示的标签。然后被点击的标签引用了HtmlElement对象

在WebBrowser控件中,我调用HtmlElement对象的getAttribute("onclick"),但它只返回"System.__ComObject"

我查找了如何处理它,发现可以将其转换类型然后获取值。

if (tag.GetAttribute("onclick").Equals("System.__ComObject"))
{
    Console.WriteLine("dom elem  >>>>>>>>>>> " + tag.DomElement.ToString());
    mshtml.HTMLSpanElementClass span = (mshtml.HTMLSpanElementClass)tag.DomElement;

    Console.WriteLine("js value ===>" + span.onclick);
}

输出:

dom elem  >>>>>>>>>>> mshtml.HTMLSpanElementClass
js value ===> System.__ComObject

就像显示的那样,span.onclick仍然给了我System.__ComObject,我做错了什么?

为什么HtmlElement的GetAttribute()方法返回“mshtml.HTMLInputElementClass”而不是属性值?中,这位仁兄说他的情况下可以工作,我也按照他的步骤走了,但我的有点不起作用...

更新

调查、调查...

我可以在C#项目中添加对VisualBasic.dll的引用,然后调用该方法来找出这个System.__ComObject到底是谁。

Console.WriteLine(Microsoft.VisualBasic.Information.TypeName(span.onclick));

输出:

JScriptTypeInfo

看起来这是JScript类型... 我怎样才能访问这个对象呢?

更多细节

上述描述基于我的当前项目。该项目旨在创建类似于Selenium IDE的东西,但使用WebBrowser控件代替。

Selenium IDE会创建3种不同的方式来记录网络文档中的元素。

1. actionType
2. xpath
3. value
例如,
type, //input[@id=foo], "hello world"
clickAndWait, //link=login, ""

Selenium IDE 通过识别页面加载来更改 "click""clickAndWait" 之间的 actionType。我的情况比较简单。

如果我点击元素,且它是 anchor tag 或具有类似于 onclick=window.location.href='blah' 的页面加载类型的 JavaScript,则我希望将 actionType 设置为 "clickAndWait"


1
看起来 span.onclick 实际上是 IDipatch。 - Poma
也许我完全走错了方向,但是您不能只添加runat="server"并访问onclick属性吗? - RBaarda
1
@masato-san,你最终是如何解决这个问题的? - dr. evil
@masato-san,你有机会解决了吗?如果你能发帖解答就太好了。 - LCJ
请参见使用getAttribute时返回System.__ComObject。使用attributes("onclick").value.ToString() - Sam Hobbs
显示剩余4条评论
6个回答

9
有多种方法可以实现。
  1. DOM中有一个事件对象,可以提供有关生成此事件的元素的信息。
  2. 您可以在这里看到:http://msdn.microsoft.com/en-us/library/ff975965%28v=VS.85%29.aspx
  3. 这个很好用,你可以轻松使用它,你将获得事件对象作为方法参数,你可以调查参数以找到事件源。http://support.microsoft.com/kb/312777

另一种选择是使用自定义导航URL并对其进行操作

  1. 重写BeforeNavigate事件
  2. 检查导航URL是否包含"mycommand:click"或"mycommand:clickandwait"。如果包含任何一个,则将取消设置为true。(这将停止浏览器导航)。
  3. 然后,您可以从C#代码导航您的webbrowser代码,并传递cancel为true。

另一种替代方法是使用External object, WebBrowser允许您设置一个ObjectForScripting,在Javascript或HTML中可以访问该对象。

.NET 2.0中的ObjectForScripting

[ComVisible(true)]
public class MyClass
{
   // can be called from JavaScript
   public void ShowMessageBox(string msg){
       MessageBox.Show(msg);
   }
}

myBrowser.ObjectForScripting = new MyClass(); 
// or you can reuse instance of MyClass

你可以调用以下函数:

window.external.ShowMessageBox("This was called from JavaScript");

感谢提供列表,关于第二点,它只在IE9上可用,但我的环境是.NET Framework 2.0和IE6,所以我不认为我可以依赖第二点。 - Meow
对于第三个问题,我没有使用SHDocVw.dll,而是只使用了mshtml.dll。就像我的事件处理程序只声明为:private void ClickEventHandler(object sender, HtmlElementEventArgs e),所以我认为第三个选项也不是解决方案... - Meow
@Akash Kava:是的,我想我会尝试那种方式。如果成功了,会非常棒! :) - Meow
@Akash:顺便说一下,导航URL中并不包含“mycommand:click”,它只是给出了它指向的URL(即www.msn.com/news等)。 - Meow
1
是的,但您可以创建自己的URL方案,例如您可以放置mycommand:Command1,mycommand:Command2,基于Command1和Command2,您可以控制逻辑,这就是每个软件都使用的方式。导航和BeforeNavigate是相同的事件,我认为一个在WinForm中,另一个在WPF中。您尝试过外部接口访问吗?如果您设置webBrowser.ExteranlObject(我不知道确切的名称)= myClass,myClass应该是Com Visible,您也可以直接从javascript调用其方法。 - Akash Kava
显示剩余6条评论

4

谢谢,但我正在使用System.Windows.Form.HtmlElement,并将其实例转换为mshtml.IHTMLDOMNode是编译错误。 - Meow
我可以使用mshtml.IHTMLDOMNode将elem.DomDocument转换为castedElement,但仍然会得到System.COM_Object。 - Meow
1
IHTMLDOMNode.attributes 返回属性集合的 IDispatch 接口(请注意属性名称末尾的 s)。链接的示例通过 IHTMLAttributeCollection 接口枚举集合,并通过集合中每个项目的 IHTMLDOMAttribute 接口检查属性名称。 - Sheng Jiang 蒋晟
有没有不枚举所有属性(这样非常慢)而直接使用 getAttribute 这样的东西来完成这个操作的方法? - dr. evil
我在IE中发现了这个bug - 这个会失败 <form name="something" action="/test" method="post" ><input type="hidden" name="action"/></form> 但是这个不会 <form name="something" action="/test" method="post" ><input type="hidden" name="actionx"/></form> 所以你不能有一个表单项的名称与你尝试读取的属性名称相同。这对于 GetAttribute("action") 失败,对于 GetAttribute("method") 也将失败 >> <form name="something" action="/test" method="post" ><input type="hidden" name="method"/></form> 。IE团队是否已经知道了这个bug,或者应该向哪里报告MS Connect? - dr. evil

3

根据Sheng Jiang的回复,这里提供一些工作样例:

IHTMLElement element = YourCodeToGetElement();
string onclick = string.Empty;

IHTMLDOMNode domNode = element as IHTMLDOMNode;
IHTMLAttributeCollection attrs = domNode.attributes;

foreach (IHTMLDOMAttribute attr in attrs)
{
    if (attr.nodeName.Equals("onclick"))
    {
        string attrValue = attr.nodeValue as string;
        if (!string.IsNullOrEmpty(attrValue))
        {
            onclick = attr.nodeValue;
            break;
        }
    }
}

2
您可以尝试使用HtmlAgilityPack解析webBrowser1.DocumentText属性,然后使用XPath获取所需结果。

谢谢提供信息。问题是我需要在Web浏览器中单击具有onclick(例如<div onclick ='foo();'>)的元素,然后需要查找onclick中的内容(即foo();)。在我的情况下,我事先不知道xpath。 - Meow

2

如果不一定要使用C#(你可以使用JS并创建Postback),那么你应该看一下这个问题。


2
你可以轻松地自行解析,首先读取obj.outerHtml。这应该为该Obj提供整个HTML,然后在其中搜索值为onclick="????"的部分,并提取其中的 ???? 部分。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接