在 C# 中获取 JavaScript/HTML 变量的值

Posted

技术标签:

【中文标题】在 C# 中获取 JavaScript/HTML 变量的值【英文标题】:Getting the value of JavaScript/HTML variables in C# 【发布时间】:2018-07-04 00:21:46 【问题描述】:

我正在尝试从中提取数据的网页。通过查看页面 Source 中的 html,我可以在 script 标签中找到我感兴趣的数据。 如下所示:

<html>
<script type="text/javascript">

window.gon = ;
gon.default_profile_mode = false; 
gon.user = null;  
gon.product = "shoes";
gon.books_jsonarray = [

    "title": "Little Sun",
    "authors": [
        "John Smith"
    ],
    edition: 2,
    year: 2009
,

    "title": "Little Prairie",
    "authors": [
        "John Smith"
    ],
    edition: 3,
    year: 2009
,

    "title": "Little World",
    "authors": [
        "John Smith",
        "Mary Neil",
        "Carla Brummer"
    ],
    edition: 3,
    year: 2014

];

</script>
</html>

我想要实现的是,通过使用其 url 调用网页,然后从 JavaScript 中检索“gon”变量并将其存储在 C# 变量中。换句话说,在 C# 中,我想要一个数据结构(例如字典)来保存 'gon' 的值。

我曾尝试研究如何通过 C# WebBrowser 获取在 JavaScript 中定义的变量,这就是我发现的:

using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Net;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using mshtml;

namespace Mynamespace


  public partial class Form1 : Form
  
    public WebBrowser WebBrowser1 = new WebBrowser();

    private void Form1_Load(object sender, EventArgs e)
    
        string myurl = "http://somewebsite.com"; //Using WebBrowser control to load web page   
        this.WebBrowser1.Navigate(myurl);
        


    private void btnGetValueFromJs_Click(object sender, EventArgs e)
    
        var mydoc = this.WebBrowser1.Document;
        IHTMLDocument2 vDocument = mydoc.DomDocument as IHTMLDocument2;
        IHTMLWindow2 vWindow = (IHTMLWindow2)vDocument.parentWindow;
        Type vWindowType = vWindow.GetType();
        object strfromJS = vWindowType.InvokeMember("mystr",
                            BindingFlags.GetProperty, null, vWindow, new object[]  ); 
//Here, I am able to see the string "Hello Sir"

        object gonfromJS = vWindowType.InvokeMember("gon",
                            BindingFlags.GetProperty, null, vWindow, new object[]  ); 
//Here, I am able to see the object gonfromJS as a 'System.__ComObject'

        object gonbooksfromJS = vWindowType.InvokeMember("gon.books_jsonarray",
                            BindingFlags.GetProperty, null, vWindow, new object[]  ); 
//This error is thrown: 'An unhandled exception of type 'System.Runtime.InteropServices.COMException' occurred in mscorlib.dll; (Exception from HRESULT: 0x80020006 (DISP_E_UNKNOWNNAME))'

    

  

我能够检索字符串或数字变量的值,例如:

var mystr = "Hello Sir";
var mynbr = 8;

但是,即使我能够看到“gon”变量作为“System.__ComObject”传递,我也不知道如何解析它以查看其子组件的值.如果我可以解析它会很好,但如果不是,我想要的是一个 C# 数据结构,其中包含键/值,其中包含 gon 变量的所有子信息,尤其是能够查看变量“gon.books_jsonarray”。

非常感谢任何有关如何实现这一目标的帮助。请注意,无论如何我都无法更改源 html/javascript,因此,我需要一个可以实现目标的 C# 代码。

【问题讨论】:

gon 是否会具有确定性值?您确定它不会从其他变量、用户输入或 AJAX 请求中填充其成员吗? 对 C# Webbrowser 了解不多,但如果您可以调用 javascript JSON.stringify(gon) 可能会有所帮助,然后解析 json 字符串 @charleifl :我假设您的意思是将行 var Myjson = JSON.stringify(gon) 添加到 javascript?不幸的是,我根本无法编辑源 html/javascript。 @AI.G. : 在这种情况下,给定一个特定的 url,'gon' 的值不应该改变 你试过this问题的答案中给出的技术吗? 【参考方案1】:

您可以将 InvokeMember() 的结果强制转换为动态并直接在 C# 代码中使用属性名称。数组索引很棘手,但可以通过 InvokeScript() 的另一种用法来完成,请参见我的示例:

private void btnGetValueFromJs_Click(object sender, EventArgs e)

    var mydoc = this.WebBrowser1.Document;
    IHTMLDocument2 vDocument = mydoc.DomDocument as IHTMLDocument2;
    IHTMLWindow2 vWindow = (IHTMLWindow2)vDocument.parentWindow;
    Type vWindowType = vWindow.GetType();

    var gonfromJS = (dynamic)vWindowType.InvokeMember("gon",
                        BindingFlags.GetProperty, null, vWindow, new object[]  );

    var length = gonfromJS.books_jsonarray.length;

    for (var i = 0; i < length; ++i)
    
        var book = (dynamic) mydoc.InvokeScript("eval", new object[]  "gon.books_jsonarray[" + i + "]" );
        Console.WriteLine(book.title);
        /* prints:
            * Little Sun
            * Little Prairie
            * Little World
            */
    

【讨论】:

【参考方案2】:

    您需要使用JSON.stringify 将您的gon.books_jsonarray 变量转换为JSON 字符串

    在您可以使用下一个C# 代码检索 JSON 之后:

    var gonFromJS = mydoc.InvokeScript("eval", new object[] "JSON.stringify(gon.books_jsonarray)" ).ToString();

    在您可以使用 Newtonsoft.Json 将 JSON 反序列化为对象之后

我的完整代码在这里:

using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Windows.Forms;

namespace WindowsFormsApp1

    public partial class Form1 : Form
    
        public Form1()
        
            InitializeComponent();
        

        private void Form1_Load(object sender, EventArgs e)
        
            var webBrowser = new WebBrowser();

            webBrowser.DocumentCompleted += (s, ea) =>
            
                var mydoc = webBrowser.Document;
                var gonFromJS = mydoc.InvokeScript("eval", new object[]  "JSON.stringify(gon.books_jsonarray)" ).ToString();
                var gonObject = JsonConvert.DeserializeObject<List<Books>>(gonFromJS);
            ;

            var myurl = "http://localhost/test.html";
            webBrowser.Navigate(myurl);
        

        private class Books
        
            public string Title  get; set; 
            public List<string> Authors  get; set; 
            public int Edition  get; set; 
            public int Year  get; set; 
        
    

您还可以在屏幕截图上看到输出:

编辑

JSON.stringify 方法也有问题。

可以返回null

在这种情况下,您可以查看 SO 主题:here 和 here。

如果 JSON.stringify 方法返回 null 然后尝试将下一个代码添加到您的 HTML 页面:

<head>
<meta http-equiv='X-UA-Compatible' content='IE=edge' >
</head>

【讨论】:

以上是关于在 C# 中获取 JavaScript/HTML 变量的值的主要内容,如果未能解决你的问题,请参考以下文章

使用 Twitter Bootstrap、C#、asp.net 和 javascript 上传文件

有没有办法使用 Javascript/HTML5 从 USB 设备获取 GPS 位置?

Javascript--HTML DOM基础知识

[javascript/html] HTML中Location对象详解

在c#中获取时区列表[重复]

在 C# 中获取网络利用率