c# – .NET WebBrowser – FireBug樣式檢查HTML元素
是否可以使用.NET 3.5 / 4.0檢查WinForm Web瀏覽器中的HTML元素?
可能使用IHighlightRenderingServices介面或Html敏捷包?
我希望應用程式的功能像FireBug:
只需用滑鼠懸停要檢查的元素,然後單擊它.在1.7之前的Firebug版本中,它自動切換到HTML面板,並在節點檢視中選擇適當的元素.
編輯:
哇,我剛剛碰到了ofollow,noindex" target="_blank">http://www.selectorgadget.com/ 這正是我想要做的.在Javascript中,在過去2個小時內檢視原始碼後,我仍然沒有一個線索如何將其併入我的程式…
從我可以告訴它使用DOM元素的標記和遞迴分析來計算CSS選擇器路徑:http://www.selectorgadget.com/stable/lib/dom.js .
編輯:好的我已經將selectorgadget載入到我的應用程式.它允許您選擇與Firebug完全相同的HTML元素!甚至建立Xpath查詢.
但是,我正在使用AxWebBrowser,我堅持使用HtmlAgilityPack …
private void xpathQuery_Click(object sender, EventArgs e) { // Load Browser HtmlWindow window = axWebBrowser1.Document.Window; // <---- 'object' does not contain a definition for 'Window' string str = window.Document.Body.OuterHtml; // Load HTML HtmlAgilityPack.HtmlDocument HtmlDoc = new HtmlAgilityPack.HtmlDocument(); HtmlDoc.LoadHtml(str); //Process Xpath Query HtmlAgilityPack.HtmlNodeCollection Nodes = HtmlDoc.DocumentNode.SelectNodes(xpathText.Text); //Print in Text box foreach (HtmlAgilityPack.HtmlNode Node in Nodes) { richTextBox1.Text += Node.OuterHtml + "\r\n"; } }
編輯:
我不能讓AxWebBrowser與HtmlAgilityPack一起工作,所以我只是使用WebClient類載入URL,然後用HtmlAgilityPack解析它.
我剛剛完成了Web Scraper.它的功能與Visual Web Ripper和所有其他價格為$1,000的其他功能類似.
我以前做過這樣的事情.您必須將文件轉換為IExpando,那麼您可以對其進行反射呼叫以獲取成員.我實際上建立了一個DynamicNode類,它允許您使用dynamic關鍵字與文件進行互動.
您可能想要使用mshtml COM物件,而不是:Reusing MSHTML
>在COM參考列表中新增對mshtml的引用
>建立一個var document = new mshtml.HTMLDocument()的例項;
>轉換為IExpando:var window =(IExpando)document.parentWindow;
>建立動態物件包裝器(見下文)
>使用動態關鍵字與文件互動.
例如這裡是我的動態節點:
class DynamicNode : DynamicObject, IExpando, IEnumerable { private IExpando value; public DynamicNode(IExpando value) { this.value = value; } public override bool TryUnaryOperation(UnaryOperationBinder binder, out object result) { switch (binder.Operation) { case System.Linq.Expressions.ExpressionType.Convert: case System.Linq.Expressions.ExpressionType.ConvertChecked: result = this.value; return true; } return base.TryUnaryOperation(binder, out result); } public override IEnumerable<string> GetDynamicMemberNames() { return this.value .GetMembers(BindingFlags.Instance | BindingFlags.Public) .Select(m => m.Name) .Distinct() .ToArray(); } public override bool TryConvert(ConvertBinder binder, out object result) { result = this.value; return true; } public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result) { if (indexes.Length == 1) { var memberName = indexes[0].ToString(); result = ReflectionHelpers.GetValue(this.value, memberName); result = DynamicNode.Wrap(result); return true; } return base.TryGetIndex(binder, indexes, out result); } public override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value) { if (indexes.Length == 1) { var memberName = indexes[0].ToString(); value = DynamicNode.Unwrap(value); ReflectionHelpers.SetValue(this.value, memberName, value); return true; } return base.TrySetIndex(binder, indexes, value); } public override bool TryGetMember(GetMemberBinder binder, out object result) { if (base.TryGetMember(binder, out result)) return true; result = ReflectionHelpers.GetValue(this.value, binder.Name); result = DynamicNode.Wrap(result); return true; } public override bool TrySetMember(SetMemberBinder binder, object value) { ReflectionHelpers.SetValue(this.value, binder.Name, value); return true; } public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) { if (binder.Name == "New") { var constructorArgs = new object[args.Length - 1]; Array.ConstrainedCopy(args, 1, constructorArgs, 0, constructorArgs.Length); result = ReflectionHelpers.New(this.value, (string)args[0], constructorArgs); } else { result = ReflectionHelpers.Invoke(this.value, binder.Name, args); } result = DynamicNode.Wrap(result); return true; } public override bool TryInvoke(InvokeBinder binder, object[] args, out object result) { IExpando self = this.value; object[] constructorArgs = new object[0]; if (args.Length > 0) { self = (IExpando)DynamicNode.Unwrap(args[0]); constructorArgs = new object[args.Length - 1]; Array.ConstrainedCopy(args, 1, constructorArgs, 0, constructorArgs.Length); } result = ReflectionHelpers.Call(this.value, self, constructorArgs); result = DynamicNode.Wrap(result); return true; } private static object Wrap(object value) { if (value != null && Marshal.IsComObject(value)) value = new DynamicNode((IExpando)value); return value; } public static object Unwrap(object value) { DynamicNode node = value as DynamicNode; if (node != null) return node.value; return value; } public IEnumerator GetEnumerator() { var members = this.value.GetProperties(BindingFlags.Public | BindingFlags.Instance); var indexProperties = new List<Tuple<int, PropertyInfo>>(); var isArray = true; foreach (var member in members) { int value = 0; if (!int.TryParse(member.Name, out value)) { isArray = false; break; } var propertyMember = member as PropertyInfo; if (propertyMember != null) indexProperties.Add(Tuple.Create(value, propertyMember)); } if (isArray) { indexProperties.Sort((left, right) => left.Item1.CompareTo(right.Item1)); foreach (var prop in indexProperties) yield return prop.Item2.GetValue(this.value, null); } else { foreach (var member in members) yield return member.Name; } } #region IExpando FieldInfo IExpando.AddField(string name) { return this.value.AddField(name); } MethodInfo IExpando.AddMethod(string name, Delegate method) { return this.value.AddMethod(name, method); } PropertyInfo IExpando.AddProperty(string name) { return this.value.AddProperty(name); } void IExpando.RemoveMember(MemberInfo m) { this.value.RemoveMember(m); } FieldInfo IReflect.GetField(string name, BindingFlags bindingAttr) { return this.value.GetField(name, bindingAttr); } FieldInfo[] IReflect.GetFields(BindingFlags bindingAttr) { return this.value.GetFields(bindingAttr); } MemberInfo[] IReflect.GetMember(string name, BindingFlags bindingAttr) { return this.value.GetMember(name, bindingAttr); } MemberInfo[] IReflect.GetMembers(BindingFlags bindingAttr) { return this.value.GetMembers(bindingAttr); } MethodInfo IReflect.GetMethod(string name, BindingFlags bindingAttr) { return this.value.GetMethod(name, bindingAttr); } MethodInfo IReflect.GetMethod(string name, BindingFlags bindingAttr, Binder binder, Type[] types, ParameterModifier[] modifiers) { return this.value.GetMethod(name, bindingAttr, binder, types, modifiers); } MethodInfo[] IReflect.GetMethods(BindingFlags bindingAttr) { return this.value.GetMethods(bindingAttr); } PropertyInfo[] IReflect.GetProperties(BindingFlags bindingAttr) { return this.value.GetProperties(bindingAttr); } PropertyInfo IReflect.GetProperty(string name, BindingFlags bindingAttr, Binder binder, Type returnType, Type[] types, ParameterModifier[] modifiers) { return this.value.GetProperty(name, bindingAttr, binder, returnType, types, modifiers); } PropertyInfo IReflect.GetProperty(string name, BindingFlags bindingAttr) { return this.value.GetProperty(name, bindingAttr); } object IReflect.InvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target, object[] args, ParameterModifier[] modifiers, System.Globalization.CultureInfo culture, string[] namedParameters) { return this.value.InvokeMember(name, invokeAttr, binder, target, args, modifiers, culture, namedParameters); } Type IReflect.UnderlyingSystemType { get { return this.value.UnderlyingSystemType; } } #endregion } [ComVisible(true)] public class ScriptObject : IReflect, IExpando { private readonly Type type; private dynamic _constructor; private dynamic _prototype; public ScriptObject() { type = this.GetType(); } [DispId(0)] protected virtual object Invoke(object[] args) { return "ClrObject"; } public dynamic constructor { get { return _constructor; } set { this._constructor = value; } } public dynamic prototype { get { return _prototype; } set { this._prototype = value; } } public string toString() { return "ClrObject"; } #region IReflect Members MethodInfo IReflect.GetMethod(string name, BindingFlags bindingAttr, Binder binder, Type[] types, ParameterModifier[] modifiers) { return type.GetMethod(name, bindingAttr, binder, types, modifiers); } MethodInfo IReflect.GetMethod(string name, BindingFlags bindingAttr) { return type.GetMethod(name, bindingAttr); } protected virtual MethodInfo[] GetMethods(BindingFlags bindingAttr) { return type.GetMethods(bindingAttr); } MethodInfo[] IReflect.GetMethods(BindingFlags bindingAttr) { return GetMethods(bindingAttr); } FieldInfo IReflect.GetField(string name, BindingFlags bindingAttr) { return type.GetField(name, bindingAttr); } FieldInfo[] IReflect.GetFields(BindingFlags bindingAttr) { return new FieldInfo[0]; // type.GetFields(bindingAttr); } PropertyInfo IReflect.GetProperty(string name, BindingFlags bindingAttr) { return type.GetProperty(name, bindingAttr); } PropertyInfo IReflect.GetProperty(string name, BindingFlags bindingAttr, Binder binder, Type returnType, Type[] types, ParameterModifier[] modifiers) { return type.GetProperty(name, bindingAttr, binder, returnType, types, modifiers); } protected virtual PropertyInfo[] GetProperties(BindingFlags bindingAttr) { return type.GetProperties(bindingAttr); } PropertyInfo[] IReflect.GetProperties(BindingFlags bindingAttr) { return GetProperties(bindingAttr); } MemberInfo[] IReflect.GetMember(string name, BindingFlags bindingAttr) { return type.GetMember(name, bindingAttr); } MemberInfo[] IReflect.GetMembers(BindingFlags bindingAttr) { return type.GetMembers(bindingAttr); } protected virtual object InvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target, object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] namedParameters) { if (name == "[DISPID=0]") { return this.Invoke(args); } return type.InvokeMember(name, invokeAttr, binder, target, args, modifiers, culture, namedParameters); } object IReflect.InvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target, object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] namedParameters) { return this.InvokeMember(name, invokeAttr, binder, target, args, modifiers, culture, namedParameters); } Type IReflect.UnderlyingSystemType { get { return type.UnderlyingSystemType; } } #endregion #region IExpando Members public FieldInfo AddField(string name) { throw new NotImplementedException(); } public MethodInfo AddMethod(string name, Delegate method) { throw new NotImplementedException(); } public PropertyInfo AddProperty(string name) { throw new NotImplementedException(); } public void RemoveMember(MemberInfo m) { throw new NotImplementedException(); } #endregion } public static class ReflectionHelpers { private const BindingFlags DefaultFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static; public static object New(this IExpando scope, string functionName, params object[] args) { var constructor = (IExpando)scope.GetValue(functionName); var proto = constructor.GetValue("prototype"); var obj = (IExpando)scope.GetValue("Object"); var instance = (IExpando)obj.Invoke("create", new object[] { proto }); Call(constructor, instance, args); return instance; } public static object Call(this IExpando function, IExpando scope, params object[] args) { object[] callArgs = new object[args.Length + 1]; callArgs[0] = scope; Array.Copy(args, 0, callArgs, 1, args.Length); return Invoke(function, "call", callArgs); } public static void SetValue(this IExpando instance, string propertyName, object value) { if (instance == null) throw new ArgumentNullException("instance"); if (string.IsNullOrEmpty(propertyName)) throw new ArgumentException("Must specify a value.", "propertyName"); Invoke(instance, propertyName, InvokeFlags.DISPATCH_PROPERTYPUT, new object[] { value }); } public static object GetValue(this IExpando instance, string propertyName) { return Invoke(instance, propertyName, InvokeFlags.DISPATCH_PROPERTYGET, new object[0]); } public static object Invoke(this IExpando instance, string functionName, object[] args) { if (instance == null) throw new ArgumentNullException("instance"); if (string.IsNullOrEmpty(functionName)) throw new ArgumentException("Must specify a value.", "functionName"); return Invoke(instance, functionName, InvokeFlags.DISPATCH_METHOD, args); } private static object Invoke(IExpando instance, string functionName, InvokeFlags flags, object[] args) { try { args = args.Select(arg => DynamicNode.Unwrap(arg)).ToArray(); switch (flags) { case InvokeFlags.DISPATCH_METHOD: var method = instance.GetMethod(functionName, DefaultFlags); return method.Invoke(instance, args); case InvokeFlags.DISPATCH_PROPERTYGET: var getProp = instance.GetProperty(functionName, DefaultFlags); return getProp.GetValue(instance, null); case InvokeFlags.DISPATCH_PROPERTYPUT: case InvokeFlags.DISPATCH_PROPERTYPUTREF: var setProp = instance.GetProperty(functionName, DefaultFlags); if (setProp == null) setProp = instance.AddProperty(functionName); setProp.SetValue(instance, args[0], null); return null; default: throw new NotSupportedException(); } } catch (COMException comex) { switch ((uint)comex.ErrorCode) { // Unexpected script error. This will be handled by the IProcess.UnhandledException event case 0x80020101: return null; default: throw; } } } private enum InvokeFlags { DISPATCH_METHOD = 1, DISPATCH_PROPERTYGET = 2, DISPATCH_PROPERTYPUT = 4, DISPATCH_PROPERTYPUTREF = 8, } }
實際上,您可以將.net物件以這種方式貼上到文件中,或者從.net中提取物件並與其進行互動.您也可以將eval作為字串,並將其呼叫為.net函式.以下是一些用法的程式碼片段:
獲取和設定一個js物件的成員:
this.host.Window.eval(@" Foo = { }; "); var foo = this.host.Window.Foo; foo.B = 7.11; Assert.Equal(7.11, foo.B);
從C#呼叫js函式:
this.host.eval("function add(x, y) { return x + y; }"); var z = (int)this.host.Window.add(7, 11); Assert.Equal(7 + 11, z);
將.net物件插入文件並從js呼叫其成員:
this.host.Window.Custom2 = new Custom2(); this.host.Window.eval(@" function test() { return Custom2.Test().Value; }"); bool success = this.host.Window.test(); Assert.True(success);
您只能將繼承自ScriptObject的物件貼上到文件(但是在上面的程式碼塊中定義).好吧,我想你可以把任何東西放在那裡,但是如果不實施IReflect,你會得到奇怪的行為.
http://stackoverflow.com/questions/9502968/net-webbrowser-firebug-style-inspect-html-element