2012-02-29 44 views
15

Có thể sử dụng .NET 3.5/4.0 để kiểm tra các phần tử HTML trong trình duyệt web WinForm không?.NET WebBrowser - Phong cách FireBug Kiểm tra phần tử HTML

Có thể sử dụng IHighlightRenderingServices Interface hoặc Html Agility Pack?

Tôi muốn các ứng dụng để hoạt động như Firebug:

Chỉ cần di chuột các yếu tố mà bạn muốn kiểm tra với chuột và click vào nó. Trong các phiên bản Firebug trước 1.7, điều này sẽ tự động chuyển sang Bảng điều khiển HTML và chọn phần tử thích hợp bên trong Chế độ xem nút.

Inspect Element

EDIT:

Wow, tôi chỉ tình cờ gặp http://www.selectorgadget.com/ đó là chính xác những gì tôi đang cố gắng làm. Đó là trong Javascript và sau khi xem xét các mã nguồn trong 2 giờ qua, tôi vẫn không có một đầu mối làm thế nào để kết hợp nó vào chương trình của tôi ...

Từ những gì tôi có thể nói nó sử dụng mã hóa và phân tích đệ quy của DOM các yếu tố để tìm ra đường dẫn bộ chọn CSS: http://www.selectorgadget.com/stable/lib/dom.js.

EDIT: OK! Tôi đã có selectorgadget được tải vào ứng dụng của tôi. Nó cho phép bạn chọn chính xác các phần tử HTML giống như Firebug! Và thậm chí tạo truy vấn Xpath.

enter image description here

Tuy nhiên, tôi đang sử dụng AxWebBrowser và tôi đang mắc kẹt trên như thế nào để có được nó để làm việc với 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"; 
     }   
    } 

Edit: tôi không thể có được AxWebBrowser để làm việc với HtmlAgilityPack, vì vậy tôi chỉ sử dụng Lớp WebClient để tải URL và sau đó phân tích nó bằng HtmlAgilityPack.

Tôi sắp hoàn tất với Trình duyệt web. Nó hoạt động tương tự như Visual Web Ripper và tất cả những người khác có giá 1.000 đô la +.

enter image description here

+0

bởi bất kỳ cơ hội nào tôi có thể có mẫu mã của bạn? – Amir

Trả lời

0

Tôi không nghĩ bạn có thể làm điều đó với gói HtmlAgillity. Lý do tôi nghĩ như vậy là rất nhiều thứ xảy ra trong bộ nhớ trình duyệt (vì javascript chẳng hạn). Vì vậy, bạn sẽ bỏ lỡ tất cả các yếu tố được kết xuất trong một kết quả của một số JavaScript. Bạn cũng sẽ không thấy các kiểu được áp dụng động qua JS. Hình ảnh tốt nhất của bạn có thể là sử dụng mshtml (tìm kiếm google cho Microsoft HTML, mshtml) và trên sự kiện Document_Loaded đi trước và lặp lại tất cả các phần tử trong tài liệu thêm chuột qua javascript để làm nổi bật chúng.Sau đó bạn có thể nhận được phần tử được đánh dấu hiện tại bằng cách tìm nó trong DOM (nó sẽ có một số loại css "đã chọn" hoặc một số thuộc tính biên giới cụ thể mà bạn đã áp dụng) và lặp lại các thuộc tính của nó để kiểm tra nó.

0

Bạn có thể sử dụng Firebug lite, nó hoạt động rất giống với Firebug gốc.

2

Tôi đã thực sự thực hiện việc này trước đây. Bạn phải truyền tài liệu vào IExpando, sau đó bạn có thể thực hiện các cuộc gọi phản chiếu chống lại nó để có được thành viên. Tôi thực sự đã tạo một lớp học DynamicNode cho phép bạn sử dụng từ khóa động để tương tác với tài liệu.

Bạn có thể muốn sử dụng đối tượng mshtml COM thay vì mặc dù: Reusing MSHTML

  1. Thêm một tham chiếu đến MSHTML trong danh sách COM tham khảo
  2. Tạo một thể hiện của var document = new mshtml.HTMLDocument();
  3. Cast để IExpando: var window = (IExpando)document.parentWindow;
  4. Tạo trình bao bọc đối tượng động (xem bên dưới)
  5. Sử dụng từ khóa động để tương tác với tài liệu.

Ví dụ ở đây là nút năng động của tôi:

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, 
    } 
} 

Bạn thực sự có thể dính .net đối tượng vào tài liệu theo cách này hoặc rút khỏi các đối tượng và tương tác với họ từ .net. Bạn cũng có thể eval js dưới dạng chuỗi và để nó gọi vào các hàm .net. Dưới đây là một số đoạn mã của tập quán:

nhận và các thành viên thiết của một đối tượng js:

this.host.Window.eval(@" Foo = { }; "); 

var foo = this.host.Window.Foo; 
foo.B = 7.11; 
Assert.Equal(7.11, foo.B); 

gọi js chức năng từ C#:

this.host.eval("function add(x, y) { return x + y; }"); 
var z = (int)this.host.Window.add(7, 11); 
Assert.Equal(7 + 11, z); 

chèn .net đối tượng vào tài liệu và gọi nó thành viên từ 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); 

Bạn chỉ có thể gắn các đối tượng kế thừa từ Scrip tObject vào tài liệu mặc dù (được định nghĩa trong codeblock ở trên). Tôi nghĩ bạn có thể đặt bất cứ thứ gì vào đó nhưng bạn sẽ có những hành vi lạ nếu họ không triển khai IReflect.

Các vấn đề liên quan