ExcelHome技术论坛

标题: 【网页采集教程】【高级篇】第二课-使用VBA解析JSON格式的网页 [打印本页]

作者: liucqa    时间: 2012-11-4 22:07
标题: 【网页采集教程】【高级篇】第二课-使用VBA解析JSON格式的网页
本帖最后由 liucqa 于 2012-11-6 19:20 编辑

第一课:http://club.excelhome.net/thread-893760-1-1.html
第二课:http://club.excelhome.net/thread-894527-1-1.html
第三课:http://club.excelhome.net/thread-896608-1-1.html
第四课:http://club.excelhome.net/thread-897117-1-1.html
第五课:http://club.excelhome.net/thread-899268-1-1.html

高级篇:
第一课:http://club.excelhome.net/thread-902266-1-1.html
第二课:http://club.excelhome.net/thread-939881-1-1.html


前言:

在网页采集的过程中,我们通常会碰到三种格式的网页文件:HTML、XML、JSON
HTML通常通过字符串+数组进行解析,部分网页也可以采用正则。高级的可以用HtmlDocument对象解析。
XML可以通过XMLHTTP的.ResponseXML得到文件,并通过XMLDOM或DomDocument对象进行解析。
JOSN却比较另类,这个格式非常方便JS脚本解析,但如果用VBA的字符串处理语句来解析它,那就是一场噩梦。

本文分别介绍JS脚本和VBA类模块工具的两个方法,说明如何使用VBA代码来解析JOSN格式的文本。

顺便声明,由于是高级教程,本文不提供详细的代码解释,也不提供实用示例。还是老规矩:只指路,不登山!


*****************************俺是上课的分割线*************************************

    JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。它基于JavaScript(Standard ECMA-262 3rd Edition - December 1999)的一个子集。 JSON采用完全独立于语言的文本格式,但是也使用了类似于C语言家族的习惯(包括C, C++, C#, Java, JavaScript, Perl, Python等)。这些特性使JSON成为理想的数据交换语言。易于人阅读和编写,同时也易于机器解析和生成。
JSON建构有两种结构:
  1. “名称/值”对的集合(A collection of name/value pairs)。不同的语言中,它被理解为对象(object),记录(record),结构(struct),字典(dictionary),哈希表(hash table),有键列表(keyed list),或者关联数组 (associative array)。
  2.值的有序列表(An ordered list of values)。在大部分语言中,它被理解为数组(array)。

    简单地说,JSON 可以将 JavaScript 对象中表示的一组数据转换为字符串,然后就可以在函数之间轻松地传递这个字符串,或者在异步应用程序中将字符串从 Web 客户机传递给服务器端程序。这个字符串看起来有点儿古怪,但是 JavaScript 很容易解释它,而且 JSON 可以表示比"名称 / 值对"更复杂的结构。例如,可以表示数组和复杂的对象,而不仅仅是键和值的简单列表。


1、表示名称 / 值对
  按照最简单的形式,可以用下面这样的 JSON 表示"名称 / 值对":
  { "firstName": "Brett" }
  这个示例非常基本,而且实际上比等效的纯文本"名称 / 值对"占用更多的空间:
  firstName=Brett
  但是,当将多个"名称 / 值对"串在一起时,JSON 就会体现出它的价值了。首先,可以创建包含多个"名称 / 值对"的 记录,比如:
  { "firstName": "Brett", "lastName":"McLaughlin", "email": "aaaa" }
  从语法方面来看,这与"名称 / 值对"相比并没有很大的优势,但是在这种情况下 JSON 更容易使用,而且可读性更好。例如,它明确地表示以上三个值都是同一记录的一部分;花括号使这些值有了某种联系。

2、表示数组
  当需要表示一组值时,JSON 不但能够提高可读性,而且可以减少复杂性。例如,假设您希望表示一个人名列表。在 XML 中,需要许多开始标记和结束标记;如果使用典型的名称 / 值对(就像在本系列前面文章中看到的那种名称 / 值对),那么必须建立一种专有的数据格式,或者将键名称修改为 person1-firstName这样的形式。
  如果使用 JSON,就只需将多个带花括号的记录使用方括号分组在一起:
  { "people": [
  { "firstName": "Brett", "lastName":"McLaughlin", "email": "aaaa" },
  { "firstName": "Jason", "lastName":"Hunter", "email": "bbbb"},
  { "firstName": "Elliotte", "lastName":"Harold", "email": "cccc" }
  ]}
  这不难理解。在这个示例中,只有一个名为 people的变量,值是包含三个条目的数组,每个条目是一个人的记录,其中包含名、姓和电子邮件地址。上面的示例演示如何用括号将记录组合成一个值。
       当然,可以使用相同的语法表示多个值(每个值包含多个记录):
  { "programmers": [
  { "firstName": "Brett", "lastName":"McLaughlin", "email": "aaaa" },
  { "firstName": "Jason", "lastName":"Hunter", "email": "bbbb" },
  { "firstName": "Elliotte", "lastName":"Harold", "email": "cccc" }
  ],
  "authors": [
  { "firstName": "Isaac", "lastName": "Asimov", "genre": "science fiction" },
  { "firstName": "Tad", "lastName": "Williams", "genre": "fantasy" },
  { "firstName": "Frank", "lastName": "Peretti", "genre": "christian fiction" }
  ],
  "musicians": [
  { "firstName": "Eric", "lastName": "Clapton", "instrument": "guitar" },
  { "firstName": "Sergei", "lastName": "Rachmaninoff", "instrument": "piano" }
  ] }
  这里最值得注意的是,能够表示多个值,每个值进而包含多个值。但是还应该注意,在不同的主条目(programmers、authors 和 musicians)之间,记录中实际的名称 / 值对可以不一样。JSON 是完全动态的,允许在 JSON 结构的中间改变表示数据的方式。
  在处理 JSON 格式的数据时,没有需要遵守的预定义的约束。所以,在同样的数据结构中,可以改变表示数据的方式,甚至可以以不同方式表示同一事物。




以上信息来自百度百科



作者: liucqa    时间: 2012-11-4 22:08
本帖最后由 liucqa 于 2012-11-4 22:55 编辑

顺便说一下JSON和XML的比较

  ◆可读性
  JSON和XML的可读性可谓不相上下,一边是简易的语法,一边是规范的标签形式,很难分出胜负。

  ◆可扩展性
  XML天生有很好的扩展性,JSON当然也有,没有什么是XML能扩展,而JSON却不能扩展的。不过JSON在Javascript主场作战,可以存储Javascript复合对象,有着xml不可比拟的优势。

  ◆编码难度
  XML有丰富的编码工具,比如Dom4j、JDom等,JSON也有提供的工具。无工具的情况下,相信熟练的开发人员一样能很快的写出想要的xml文档和JSON字符串,不过,xml文档要多很多结构上的字符。

  ◆解码难度
  XML的解析方式有两种:
  一是通过文档模型解析,也就是通过父标签索引出一组标记。例如:xmlData.getElementsByTagName("tagName"),但是这样是要在预先知道文档结构的情况下使用,无法进行通用的封装。
  另外一种方法是遍历节点(document 以及 childNodes)。这个可以通过递归来实现,不过解析出来的数据仍旧是形式各异,往往也不能满足预先的要求。
  凡是这样可扩展的结构数据解析起来一定都很困难。
  JSON也同样如此。如果预先知道JSON结构的情况下,使用JSON进行数据传递简直是太美妙了,可以写出很实用美观可读性强的代码。如果你是纯粹的前台开发人员,一定会非常喜欢JSON。但是如果你是一个应用开发人员,就不是那么喜欢了,毕竟xml才是真正的结构化标记语言,用于进行数据传递。
  而如果不知道JSON的结构而去解析JSON的话,那简直是噩梦。费时费力不说,代码也会变得冗余拖沓,得到的结果也不尽人意。但是这样也不影响众多前台开发人员选择JSON。因为json.js中的toJSONString()就可以看到JSON的字符串结构。当然不是使用这个字符串,这样仍旧是噩梦。常用JSON的人看到这个字符串之后,就对JSON的结构很明了了,就更容易的操作JSON。
  以上是在Javascript中仅对于数据传递的xml与JSON的解析。在Javascript地盘内,JSON毕竟是主场作战,其优势当然要远远优越于xml。如果JSON中存储Javascript复合对象,而且不知道其结构的话,我相信很多程序员也一样是哭着解析JSON的。

以上信息来自百度百科
作者: liucqa    时间: 2012-11-4 22:09
本帖最后由 liucqa 于 2012-11-4 22:17 编辑

对我们初学者来说,得到JSON数据并不难。然而,要从复杂的数据中,找到需要的数据节点,有时候真的是一场噩梦。

幸好,下面的网站提供的JSON格式化校验器,可以帮助大家方便的解析数据了。
www.bejson.com


下面给大家提供一个JSON文件的参考示例
(, 下载次数: 1606)

诸位可以将此数据粘贴到上面的网站上,看看格式

作者: liucqa    时间: 2012-11-4 22:10
本帖最后由 liucqa 于 2012-11-4 22:41 编辑

JSON是 JavaScript 原生格式,这意味着在 JavaScript 中处理 JSON数据不须要任何特殊的 API 或工具包。

所以,在vba中处理JSON,最简单的方法就是使用ScriptControl对象的javascript脚本语句

  1.     Option Explicit
  2.     Public Const strJOSN As String = "{ ""myname"":""liucqa"", ""myid"":""007"" }"
  3.     Sub test1()
  4.         Dim objSC, strJSON, objJS
  5.         Set objSC = CreateObject("MSScriptControl.ScriptControl")    '调用ScriptControl对象
  6.         strJSON = "var o=" & strJOSN & ";"
  7.         objSC.Language = "javascript"
  8.         objSC.AddCode (strJSON)
  9.         Set objJS = objSC.CodeObject.o
  10.         MsgBox CallByName(objJS, "myname", VbGet) & "=" & CallByName(objJS, "myid", VbGet)
  11.     End Sub

  12.     Sub test2()
  13.         Dim strFunc, objSC, objJSON
  14.         Set objSC = CreateObject("ScriptControl")
  15.         objSC.Language = "JScript"
  16.         strFunc = "function getjson(s) { return eval('(' + s + ')'); }"
  17.         objSC.AddCode strFunc
  18.         Set objJSON = objSC.CodeObject.getjson(strJOSN)
  19.         MsgBox objJSON.myname & "=" & objJSON.myid
  20.     End Sub
复制代码


上面是两个例子,第一个例子使用CallByName来得到对象的属性(或者说是以文本字符为下标的数组数据)。第二个例子直接通过javascript的属性输出。


网络文章参考
http://www.cnblogs.com/worfdream/articles/1956449.html



补充内容 (2013-4-18 15:52):
http://blog.csdn.net/klarclm/article/details/7629880   JS控件的方法和属性
作者: liucqa    时间: 2012-11-4 22:11
本帖最后由 liucqa 于 2012-11-6 19:24 编辑

通过在VBA中使用上面的JS语句,我们可以得到简单的JSON文本数据。
然而,在实际应用中,上述语句会出现许多问题,诸如关键字冲突、JSON数组不能直接使用等问题。

这就需要我们将JS函数和CallByName函数两者结合到一起来使用。

请看下面的例子,来自figfig大神的帖子 http://club.excelhome.net/thread-483942-1-1.html
在这段代码中,就存在关键字冲突。修改如下:
  1. Sub Sample()
  2. Dim aa, x, y As Object, s
  3.     aa = "{ ""people"": [{ ""firstName"": ""Brett"", ""lastName"":""McLaughlin"", ""Email"": ""brett@newInstance.com"" },{ ""firstName"": ""Jason"", ""lastName"":""Hunter"", ""email"": ""jason@servlets.com"" }, { ""firstName"": ""Elliotte"", ""lastName"":""Harold"", ""email"": ""elharo@macfaq.com"" }]}"
  4.     Set x = CreateObject("ScriptControl")
  5.     x.Language = "JScript"

  6.     s = "function j(s) { return eval('(' + s + ').people[1]'); }"
  7.     x.AddCode s
  8.     Set y = x.Run("j", aa)
  9.     MsgBox y.firstName
  10.     'MsgBox y.Email        '由于关键字冲突,在2007下无法执行
  11.     MsgBox CallByName(y, "email", VbGet)
  12. End Sub
复制代码
经过修改之后的代码,可以正常运行了。


另一个例子:
在3楼给出的金宝博JSON格式的数据中,如果你使用JS脚本来读取它,会发现在读取出来的对象中嵌套着许多对象和数组。
VBA中,我们不能把JS出来的带有下标的对象直接当作数组来读取数据(前引用也不行)。


要读取JSON数组里面的数据,就需要我们采用将JS函数和CallByName函数结合到一起的方法。

例子如下(部分代码,仅供参考)

  1.     Dim strFunc1 As String, strFunc2 As String, strFunc3 As String
  2.     Dim objSC As Object      
  3.     Dim objJS1 As Object, objJS2, objJS3

  4.     Set objSC = CreateObject("ScriptControl")
  5.     objSC.Language = "JScript"

  6.     strFunc1 = "function getjson1(s) { return eval('(' + s + ')'); }"
  7.     strFunc2 = "function getjson2(s) { return eval('(' + s + ').d[0].c[0].e[0].o.ah'); }"
  8.     strFunc3 = "function getjson3(s) { return eval('(' + s + ').d[0].c[0].e[0].o'); }"         
  9.     's = "function j(s) { return eval('(' + s + ').people[1]'); }"
  10.     objSC.AddCode strFunc1
  11.     objSC.AddCode strFunc2
  12.     objSC.AddCode strFunc3
  13.     Set objJS1 = objSC.CodeObject.getjson1(strText)
  14.     Set objJS2 = objSC.CodeObject.getjson2(strText)
  15.     Set objJS3 = objSC.CodeObject.getjson3(strText)

  16.     Dim s1, s2
  17.     s1 = CallByName(objJS2, "1", VbGet)      
  18.     s2 = CallByName(objJS3, "1x2", VbGet)   
复制代码
由于在JS脚本中,也存在语法冲突问题,因此,要读取“o.1x2”的数据,我只能采用CallByName方法。(o.ah可以直接读取,无冲突)
如果哪位大神,对JS语法比较熟悉的话,烦请帮助指出直接从JS里面得到"1x2"属性数组的方法。

附图如下,可以供大家参考这个网站的数据结构。
(, 下载次数: 201)


作者: liucqa    时间: 2012-11-4 22:28
本帖最后由 liucqa 于 2014-8-1 21:28 编辑

前面讲了使用JS脚本语言来解析JSON格式文本的例子,那么到底有没有办法直接采用VBA自己的代码来解析JSON呢?

感谢国外的高人们,他们为我们提供了这样一个源代码,通过字典来解析JSON。
代码需要引用Scripting Runtime库和ADO库

链接地址如下:
http://www.ediy.co.nz/vbjson-json-parser-library-in-vb6-xidc55680.html
http://code.google.com/p/vba-json/

在水文工具集中,也提供了一个修改过的类模块(bug未修正),这个版本无须做前引用。
http://www.cnhup.com/index.php/archives/vba-json-class/


还是以金宝博网站为例,部分代码如下
  1. Dim objJSON As New clsJOSN, dicJSON As Object

  2.     Set dicJSON = objJSON.parse(strRespText)
  3.     MsgBox dicJSON("d")(1)("c")(1)("n") & vbCrLf & _
  4.            dicJSON("d")(1)("c")(1)("e")(1)("i")(1) & "-" & dicJSON("d")(1)("c")(1)("e")(1)("i")(2) & vbCrLf & _
  5.            "1x2 " & _
  6.            dicJSON("d")(1)("c")(1)("e")(1)("o")("1x2")(2) & " " & _
  7.            dicJSON("d")(1)("c")(1)("e")(1)("o")("1x2")(4) & " " & _
  8.            dicJSON("d")(1)("c")(1)("e")(1)("o")("1x2")(6) & vbCrLf & _
  9.            "让球 " & _
  10.            dicJSON("d")(1)("c")(1)("e")(1)("o")("ah")(6) & " " & _
  11.            dicJSON("d")(1)("c")(1)("e")(1)("o")("ah")(8) & vbCrLf & _
  12.            "大小盘 " & _
  13.            dicJSON("d")(1)("c")(1)("e")(1)("o")("ou")(6) & " " & _
  14.            dicJSON("d")(1)("c")(1)("e")(1)("o")("ou")(8)
复制代码
采用国外高手提供的类模块解析JSON,其格式与JS的类似,好处是可以得到数组的下界,方便循环语句的使用。
输出见下图

(, 下载次数: 234)



使用VBA解析JSON格式文本的教程就到这里,本人对JSON了解很肤浅,如有错误,欢迎大家不吝指出!谢谢诸位!

备注:
具体JSON格式的描述可以在JSON网站[www.json.org]了解


使用JS获取系统时间戳
Function GetTimestamp()
    GetTimestamp = DateDiff("s", "01/01/1970 00:00:00", Now())
    GetTimestamp = GetTimestamp - 480 * 60                              '东八区
End Function


Sub GetTimestamp()
    Dim objSC, ts$, ts1$
    Set objSC = CreateObject("msscriptcontrol.scriptcontrol")
    objSC.Language = "jscript"
    objSC.addcode "function gt(){return new Date().getTime();}"
    ts = objSC.eval("gt()")

    objSC.addcode "function gt1(a){return new Date().getTime();}"         '传递一个参数
    ts1 = objSC.codeobject.gt1(1)
    MsgBox ts1 & vbCrLf & ts1
End Sub

    Function UnixTime()
        Set objWMIService = _
        GetObject("winmgmts:\\.\root\cimv2")
        Set colItems = objWMIService.ExecQuery _
        ("Select * from Win32_OperatingSystem",,48)
        For Each objItem in colItems
            TimeZone = objItem.CurrentTimeZone
        Next
        UnixTime = DateDiff("s", "01/01/1970 00:00:00", Now())
        UnixTime = UnixTime - TimeZone * 60
    End Function

'提取并执行网页中的js函数
'http://vip.bet007.com/history/odds.aspx?date=2013-4-16
Set objSC = CreateObject("ScriptControl")
objSC.Language = "JScript"

jsFuncode = Split(Split(strRespText, "script>")(1), "window")(0)
objSC.AddCode jsFuncode
decodeUrl = objSC.eval("decoder()")
objSC.Reset


作者: 引子玄    时间: 2012-11-4 23:38
本帖最后由 引子玄 于 2012-11-4 23:42 编辑

这个教材好,实用型的课程。{:soso_e179:}在原来的XmlHttp+InternetExplorer+QueryTables三种对象法抓取的基础上,又多学了一门ScriptControl 对象法抓取
作者: hyy514    时间: 2012-11-5 02:16
还是把高级二字去掉吧,会的人这是普通的数据格式,不会的想看看又被高级二字吓住了。个人见解
作者: 592rmb    时间: 2012-11-5 08:13
好,收藏学习
作者: liucqa    时间: 2012-11-5 09:02
hyy514 发表于 2012-11-5 02:16
还是把高级二字去掉吧,会的人这是普通的数据格式,不会的想看看又被高级二字吓住了。个人见解

你看看能否解决我在5楼提出的问题---直接从JS里面得到"1x2"属性数组的方法。

在VBA里面使用JS代码,对EH的会员来说,都算高级了。
作者: 引子玄    时间: 2012-11-5 09:19
liucqa 发表于 2012-11-5 09:02
你看看能否解决我在5楼提出的问题---直接从JS里面得到"1x2"属性数组的方法。

在VBA里面使用JS代码,对 ...

其他常规对象的抓取,我都会了,惟独这种脚本型网页的抓取还不会,应该是高级的了
作者: 引子玄    时间: 2012-11-5 09:44
本帖最后由 引子玄 于 2012-11-5 10:10 编辑

一点思考:对于脚本型JSON网页的抓取,用XMLHTTP也是可以抓取的,可能复杂麻烦点。
举一个例子:

比如说抓取JSON网页http://1x2.bet007.com/oddslist/760181.htm中的各个公司的很多的走势页面地址中的ID编号,如果你是通过点鼠标右键查看“源文件”,是找不到ID编号的,但是通过IE浏览器按F12,得到的“源文件”,是可以找到各个分页地址的ID编号的。比如第1个分页10BET公司的id=26621160。
还有通过IE浏览器的POST行为,在服务器上也可以找到JS脚本文件,里面就有各个公司走势分页面的ID链接编号集合,稍用数组一处理就抓到了。
解决了JSON网页的关键DD——URL参数(ID编号),其他问题就迎刃而解了。

关于JSON网页的抓取,俺以前基本上是通过上面提到的这种办法解决的。
JSON网页和常规网页抓取的不同地方,无非就是多了一道SCRIPT脚本文件的处理提取而已。



作者: kangatang    时间: 2012-11-7 18:00
hyy514大师的实例 (仅看14楼和31楼)
http://club.excelhome.net/forum. ... 460&pid=6228407
作者: kangatang    时间: 2012-11-7 18:02
再补一个

当然用java处理JSON非常方便。
但用VBA处理,比较麻烦,举个例子实现读取 [{"fuck":"yes"},{"who":"C","detail":{"first":"crl","address":"drs"}}]  中的yes 和crl

同样的功能,
用java(保存成 XXX.JS 文件):
var ss = [{"fuck":"yes"},{"who":"C","detail":{"first":"crl","address":"drs"}}];
WScript.Echo(ss[0].fuck);
WScript.Echo(ss[1].detail.first);

用VBA:
Sub FUCKC2()
   'aa = Cells(1, 1).Value
        aa = "[{""" & "fuck""" & ":""" & "yes""" & "},{""" & "who""" & ":""" & "C""" & ",""" & "detail""" & ":{""" & "first""" & ":""" & "crl""" & ",""" & "address""" & ":""" & "drs""" & "}}]"
        Set objJs = CreateObject("MSScriptControl.ScriptControl")
        objJs.Language = "javascript"

         func = "function j(s,i) {return eval('(' + s + '[' + i + '])');}"
         objJs.AddCode func

         Set x = objJs.CodeObject.j(aa, 0)
          Debug.Print x.fuck
         Set y = objJs.CodeObject.j(aa, 1)
          Debug.Print y.detail.first
End Sub
作者: 引子玄    时间: 2012-11-10 12:28
本帖最后由 引子玄 于 2012-11-10 12:31 编辑
liucqa 发表于 2012-11-4 22:08
顺便说一下JSON和XML的比较

  ◆可读性


"如果JSON中存储Javascript复合对象,而且不知道其结构的话,我相信很多程序员也一样是哭着解析JSON的。"

————由此可见,ScriptControl对象抓取,在所有网抓中,足见是最难的。得好好学习、摸索和实践。

作者: 引子玄    时间: 2012-11-10 12:37
本帖最后由 引子玄 于 2012-11-10 12:47 编辑
kangatang 发表于 2012-11-7 18:02
再补一个

当然用java处理JSON非常方便。


对这种通过WEB生成浏览文件的处理与抓取,kangatang你在这方面是强项,以前就拜读过你在这方面的网抓代码,厉害。

"用java处理JSON非常方便。
但用VBA处理,比较麻烦."

——学习你的好方法,让浏览器自动化为我们网抓分担工作负荷,以突破脚本控制型网页抓取的困难,化难为易。毕竟用这个工具那个工具,又是转码,又是啥的,挺麻烦的。

作者: kangatang    时间: 2012-11-12 11:41
kangatang 发表于 2012-11-7 18:02
再补一个

当然用java处理JSON非常方便。

这个段子有点黄,我承认。
作者: 引子玄    时间: 2012-11-28 17:15
看不懂,不断看,慢慢总会看得懂的
作者: 莫悠悠    时间: 2012-12-1 17:30
日后再说,谢谢分享
作者: kangatang    时间: 2012-12-16 22:43
liucqa 发表于 2012-11-4 22:11
通过在VBA中使用上面的JS语句,我们可以得到简单的JSON文本数据。
然而,在实际应用中,上述语句会出现许多 ...

5楼的那张jason数据结构图用什么工具做的?恳请指点一下。谢谢。
作者: 周秦汉    时间: 2013-1-10 16:10
老师的课程太高端了,先存着。

非常感谢老师无私分享,以后有问题我一定请教您,祝老师一切顺利。

由衷感谢!
作者: yarchen    时间: 2013-5-31 20:51
很努力  看了一遍,一遍 又一遍......,  
很遺憾...   太深了!   這篇 高級第二課 實在是看不懂!

怎地自己程度竟然差那麼多! 真是怨恨呀!   
夏蟲不可以語冰,  就暫且當一回夏蟲吧!

還是十分感謝 各位前輩 先進 的分享!
作者: jiangdong110    时间: 2013-6-6 08:18
真的很高级!
作者: smhf_6    时间: 2013-6-11 07:16
终于全部下载完毕,这下可以系统的学习了,谢谢楼主的分享
与VBA的表格处理、文件处理相比,这个网页处理麻烦的多,涉及到网络,而网络不是由我说了算,网页结构、语言,网络速度、服务器控制等,增加了编写代码的难度和运行的稳定性
而单位里局域网中各种系统多如牛毛,自动化处理是必需的
所以,只有谢谢了,楼主做了一件大好事
作者: hyz85888    时间: 2013-6-11 10:29
做个记号 好好学习
作者: lqh123108    时间: 2013-7-14 17:08
本帖最后由 lqh123108 于 2013-7-14 17:10 编辑
liucqa 发表于 2012-11-4 22:28
前面讲了使用JS脚本语言来解析JSON格式文本的例子,那么到底有没有办法直接采用VBA自己的代码来解析JSON呢? ...


谢谢老师的分亨

这里有个类模块..实在太高深了,,,,不懂..

能不能拿这个类模块,来循环处理一个JSON格式,以得到结构化的数据..
如:http://dict.qq.com/dict?q=word 或者你给的 金宝博网站的JSON数据示例(太多数据,太乱了,很难分析)

如:
人名
    鹏张某 16岁
      住址
        生日
           ...
    李某某 18岁
      住址
        生日
           ...
作者: sum2boy    时间: 2013-11-7 10:50
{:soso_e179:}很不错的介绍,对网页采集很有帮助
作者: alooge    时间: 2014-1-11 12:13
日后再说,谢谢分享
作者: RockedPanda    时间: 2014-8-6 17:39
本帖最后由 RockedPanda 于 2014-8-6 17:41 编辑
liucqa 发表于 2012-11-4 22:11
通过在VBA中使用上面的JS语句,我们可以得到简单的JSON文本数据。
然而,在实际应用中,上述语句会出现许多 ...

"1x2"这种命名在JS中是一个合法属性,但这种属性不能通过"."运算符访问,可以通过"[]"运算符访问.VBA刚开始学,不清楚有没有简单的方法,目前已测试的方法如下:

ss = "function property(obj, key) { return obj[key]; }"   '构造一个辅助的属性访问函数
x.AddCode ss
'利用访问函数获取1x2这种特殊属性,其他可能的形式还包括: 纯数字123,特殊符号@#_等等.
MsgBox x.Run("property", y, "1x2")

完整的例子:
Sub Sample()
    Dim aa, x, y As Object, s, ss
    aa = "{ ""people"": [{ ""firstName"": ""Brett"",""1x2"":""this is 1x2"", ""11"":""this is number 11"", ""@11"":""this is char @"", ""lastName"":""McLaughlin"", ""email"": ""brett@newInstance.com"" },{ ""firstName"": ""Jason"", ""lastName"":""Hunter"", ""email"": ""jason@servlets.com"" }, { ""firstName"": ""Elliotte"", ""lastName"":""Harold"", ""email"": ""elharo@macfaq.com"" }]}"
    Set x = CreateObject("ScriptControl")
    x.Language = "JScript"

    s = "function j(s) { return eval('(' + s + ').people[0]'); }"
    x.AddCode s
    ss = "function property(obj, key) { return obj[key]; }"   '构造一个辅助的属性访问函数
    x.AddCode ss
   
    Set y = x.Run("j", aa)
    MsgBox y.firstName
    MsgBox CallByName(y, "email", VbGet)
    '利用访问函数获取1x2这种特殊属性,其他可能的形式还包括: 纯数字123,特殊符号@#_等等.
    MsgBox x.Run("property", y, "1x2")
    MsgBox x.Run("property", y, "11")
    MsgBox x.Run("property", y, "@11")
End Sub


作者: liucqa    时间: 2014-8-6 20:37
RockedPanda 发表于 2014-8-6 17:39
"1x2"这种命名在JS中是一个合法属性,但这种属性不能通过"."运算符访问,可以通过"[]"运算符访问.VBA刚开始 ...

谢谢帮助        
作者: liucqa    时间: 2014-8-6 20:37
RockedPanda 发表于 2014-8-6 17:39
"1x2"这种命名在JS中是一个合法属性,但这种属性不能通过"."运算符访问,可以通过"[]"运算符访问.VBA刚开始 ...

谢谢帮助        
作者: RockedPanda    时间: 2014-8-6 23:51
liucqa 发表于 2014-8-6 20:37
谢谢帮助

互相协助而已, VBA刚开始接触,还要向您多多学习.
作者: choesehae    时间: 2014-10-6 12:59
留下足迹 备查 感谢分享
作者: VBA万岁    时间: 2014-10-9 11:51
liucqa 发表于 2012-11-4 22:11
通过在VBA中使用上面的JS语句,我们可以得到简单的JSON文本数据。
然而,在实际应用中,上述语句会出现许多 ...

figfig大神的原代码如下(由于红色字体部分均为“email”,所以不存在冲突——想必l是iucqa大师为了说明CallByName函数的作用将原代码稍作了修改):
Sub figjson4()
aa = "{ ""people"": [{ ""firstName"": ""Brett"", ""lastName"":""McLaughlin"", ""email"": ""brett@newInstance.com"" },{ ""firstName"": ""Jason"", ""lastName"":""Hunter"", ""email"": ""jason@servlets.com"" }, { ""firstName"": ""Elliotte"", ""lastName"":""Harold"", ""email"": ""elharo@macfaq.com"" }]}"
Set X = CreateObject("ScriptControl")
        X.Language = "JScript"
      
    s = "function j(s) { return eval('(' + s + ').people[1]'); }"
     X.AddCode s
       Set y = X.Run("j", aa)
      MsgBox y.firstName
      MsgBox y.email


End Sub
作者: VBA万岁    时间: 2014-10-9 12:04
VBA万岁 发表于 2014-10-9 11:51
figfig大神的原代码如下(由于红色字体部分均为“email”,所以不存在冲突——想必l是iucqa大师为了说明C ...

Mark如附件:
(, 下载次数: 128)

作者: liucqa    时间: 2014-10-9 20:06
VBA万岁 发表于 2014-10-9 12:04
Mark如附件:

Sub figjson4()
    Dim aa, x, s, y
    aa = "{ ""people"": [{ ""firstName"": ""Brett"", ""lastName"":""McLaughlin"", ""email"": ""brett@newInstance.com"" },{ ""firstName"": ""Jason"", ""lastName"":""Hunter"", ""email"": ""jason@servlets.com"" }, { ""firstName"": ""Elliotte"", ""lastName"":""Harold"", ""email"": ""elharo@macfaq.com"" }]}"
    Set x = CreateObject("ScriptControl")
    x.Language = "JScript"
    s = "function j(s) { return eval('(' + s + ').people[1]'); }"
    x.AddCode s
    Set y = x.Run("j", aa)
    MsgBox y.firstName
    MsgBox y.Email
End Sub

y.Email不通过
作者: HHAAMM    时间: 2014-10-9 21:36
没细看,只觉的用js的函数方式没下面这样看着直观
  1. Sub figjson()
  2.     aa = "{ ""people"": [{ ""firstName"": ""Brett"", ""lastName"":""McLaughlin"", ""email"": ""brett@newInstance.com"" },{ ""firstName"": ""Jason"", ""lastName"":""Hunter"", ""email"": ""jason@servlets.com"" }, { ""firstName"": ""Elliotte"", ""lastName"":""Harold"", ""email"": ""elharo@macfaq.com"" }]}"
  3.     Set x = CreateObject("ScriptControl")
  4.     x.Language = "javascript"
  5.     x.AddCode "HHAAMM = " & aa
  6.     Debug.Print x.Eval("HHAAMM.people[1].firstName")
  7.     Debug.Print x.Eval("HHAAMM.people[1].lastName")
  8.     Debug.Print x.Eval("HHAAMM.people[1].email")
  9. End Sub
复制代码

作者: HHAAMM    时间: 2014-10-9 21:37
Email email
javascript好像是区分大小写的
作者: VBA万岁    时间: 2014-10-10 09:03
本帖最后由 VBA万岁 于 2014-10-10 09:10 编辑
liucqa 发表于 2014-10-9 20:06
Sub figjson4()
    Dim aa, x, s, y
    aa = "{ ""people"": [{ ""firstName"": ""Brett"", ""lastNa ...


38楼HHAAMM版主说过,javascript好像是区分大小写的,将aa中的emai改为Emai(或者同改为首字母小字如34楼)就可以了。
Sub figjson4()
Dim aa, x, s, y
aa = "{ ""people"": [{ ""firstName"": ""Brett"", ""lastName"":""McLaughlin"", ""Emai"": ""brett@newInstance.com"" },{ ""firstName"": ""Jason"", ""lastName"":""Hunter"", ""Email"": ""jason@servlets.com"" }, { ""firstName"": ""Elliotte"", ""lastName"":""Harold"", ""Email"": ""elharo@macfaq.com"" }]}"
Set x = CreateObject("ScriptControl")
    x.Language = "JScript"
    s = "function j(s) { return eval('(' + s + ').people[1]'); }"
    x.AddCode s
Set y = x.Run("j", aa)
    MsgBox y.firstName
    MsgBox y.Email
End Sub

作者: VBA万岁    时间: 2014-10-10 09:21
本帖最后由 VBA万岁 于 2014-10-10 09:30 编辑
liucqa 发表于 2014-10-9 20:06
Sub figjson4()
    Dim aa, x, s, y
    aa = "{ ""people"": [{ ""firstName"": ""Brett"", ""lastNa ...


当然,此种情况用CallByName函数能解决该冲突问题。但仍需区分大小写。
作者: VBA万岁    时间: 2014-12-16 15:55
liucqa 发表于 2012-11-4 22:11
通过在VBA中使用上面的JS语句,我们可以得到简单的JSON文本数据。
然而,在实际应用中,上述语句会出现许多 ...

不知liucqa大师可否将5楼的第2个例子的完整代码帖出,好让我等测试、学习?
作者: VBA万岁    时间: 2014-12-16 16:00
RockedPanda 发表于 2014-8-6 17:39
"1x2"这种命名在JS中是一个合法属性,但这种属性不能通过"."运算符访问,可以通过"[]"运算符访问.VBA刚开始 ...

学习了,多谢分享!
Mark如附件:
(, 下载次数: 113)

作者: bigestyjoy    时间: 2015-1-6 16:22
本帖最后由 bigestyjoy 于 2015-1-6 16:32 编辑

你好,我想反馈一个问题:
我用水文工具集的类模块处理以下数据,出现问题。
  1. {
  2.   "total": 393,
  3.   "data": [
  4.     {
  5.       "Hospital": {
  6.         "ParentId": "a4f9f5b8-733d-4724-979c-a7a3f664e9ed",
  7.         "Id": "0102",
  8.         "CreateTime": new Date(
  9.           1371480749000
  10.         )
  11.       },
  12.       "HospitalEmployeeNo": "0001",
  13.       "Id": "27563",
  14.       "CreateTime": new Date(
  15.         1376064000000
  16.       ),
  17.       "CreateUser": "ADMIN",
  18.       "UpdateTime": new Date(
  19.         1402286180000
  20.       ),
  21.       "UpdateUser": "admin"
  22.     }
  23.     ]
  24. }
复制代码

经琢磨,发现是上述代码中【new Date】部分的问题。水文工具集的类模块缺少处理这类型Value的部分,当它发现“n"字符后,按照“null”处理,忽略了还可能是“new”的情况。
于是自行添加了部分代码(下面行15-19),避免了错误(忽略new语句方法)
  1. Private Function parseValue(ByRef str As String, ByRef index As Long)

  2.     Call skipChar(str, index)
  3.    
  4.     Select Case Mid(str, index, 1)
  5.     Case "{"
  6.         Set parseValue = parseObject(str, index)
  7.     Case "["
  8.         Set parseValue = parseArray(str, index)
  9.     Case """", "'"
  10.         parseValue = parseString(str, index)
  11.     Case "t", "f"
  12.         parseValue = parseBoolean(str, index)
  13.     Case "n"
  14.         If Mid(str, index + 1, 1) = "u" Then
  15.             parseValue = parseNull(str, index)
  16.         Else
  17.             index = index + InStr(Right(str, Len(str) - index + 1), ")")
  18.         End If
  19.     Case Else
  20.         parseValue = parseNumber(str, index)
  21.     End Select

  22. End Function
复制代码



作者: liucqa    时间: 2015-1-6 17:08
bigestyjoy 发表于 2015-1-6 16:22
你好,我想反馈一个问题:
我用水文工具集的类模块处理以下数据,出现问题。

你可以给老外发邮件,他会修改他的代码。

水文工具集不是最新版
作者: oceanintergy    时间: 2015-3-19 15:38
不知大神们有没有研究用flex编译出来的swf文件嵌入网页的网页抓取技巧??
请教
作者: gideon82    时间: 2015-5-8 00:02
正在爲get與post入不了門發愁, 這裏來了抓取網頁的教程, 天助我.
作者: minren118    时间: 2015-6-17 11:04
liucqa 发表于 2015-1-6 17:08
你可以给老外发邮件,他会修改他的代码。

水文工具集不是最新版

老外那个json不会用啊,能否做个实例看看?
作者: goldowl2011    时间: 2015-9-7 23:29
在VBA里面使用JS代码,真不错!!!
作者: comihuang    时间: 2015-10-25 13:46
你好 楼主,
刚才拜读了你的文章十分受用。
我想请教您一个问题,就是如何用JavaScript 对Json的值进行json_decode解码?

比如我用百度翻译API进行翻译,得出一个结果如下JSON:

  1. {"from":"en","to":"zh","trans_result":[{"src":"today","dst":"\u4eca\u5929"}]}
复制代码


其中dst的值是today这个单词翻译后的结果,只有 json_decode后才会显示 “今天”。

万分感谢!!

作者: liucqa    时间: 2015-10-25 20:45
comihuang 发表于 2015-10-25 13:46
你好 楼主,
刚才拜读了你的文章十分受用。
我想请教您一个问题,就是如何用JavaScript 对Json的值进行js ...

可以用js解码,也可以自己写代码。

百度 /U编码
作者: wingbor    时间: 2016-5-26 16:25
各集已全部看完,非常感谢楼主的无私奉献,期待后续教程。
作者: pmet12345    时间: 2016-6-18 03:30
感谢..........
作者: dodo2029    时间: 2016-7-3 16:11
感谢分享,如同看天书一样
作者: a123235    时间: 2017-2-3 15:59
越到后边越看不懂,还需要加强学习
作者: ebkzxcel    时间: 2017-2-9 11:49
楼主V5,新手报到.留个印待学习用
作者: qinyun    时间: 2017-10-3 10:19
好贴,好好学习,留个脚印
作者: xliutree    时间: 2017-10-5 14:29
收藏学习,抓点有用的知识
作者: hz54321    时间: 2018-3-6 15:40
谢谢大佬。这边正好在找抓取类的资料
作者: kinkon123    时间: 2018-3-15 23:28
感谢分享,占位学习
作者: twowood2008    时间: 2018-3-20 23:08
留存学习,深刻研讨
作者: 哆啦时光    时间: 2018-5-15 11:06

      {
        'sceneType': 1,
        'product': {这里是标准的Json内容},
        'playerVersion': '807',
        'xml': '<?xml version="1.0"?>后面是xml内容',
      };


这样的网页代码,怎么用VBA调取其中的Jsond代码呢?
作者: 朝暮不离    时间: 2018-5-16 20:48
VBA求助! http://club.excelhome.net/thread-1414063-1-1.html (出处: ExcelHome技术论坛)    向大佬求助!
作者: shui0    时间: 2018-9-5 19:09
越到后面越看不 懂,本来后面的难度更高,但是后面基本都是节选代码,更看不懂。。。
作者: hlxue    时间: 2019-6-27 15:57
标记一下,以后慢慢看。
作者: 莫悠悠    时间: 2020-5-4 21:56
liucqa 发表于 2012-11-4 22:11
通过在VBA中使用上面的JS语句,我们可以得到简单的JSON文本数据。
然而,在实际应用中,上述语句会出现许 ...

请教这个网站数据如何抓取?
http://data.eastmoney.com/zjlx/000802.html
个股的资金流向数据怎么抓取?
用EXCEL的导入网站数据不出现选定数据区域,请求高人协助,谢谢
作者: blackttea1    时间: 2022-3-6 20:09
学习再学习
作者: gyth    时间: 2022-10-25 08:31
收藏学习收藏学习
作者: pzhhxr    时间: 2023-5-11 16:16
留个记号留个记号留个记号




欢迎光临 ExcelHome技术论坛 (https://club.excelhome.net/) Powered by Discuz! X3.4