ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 效率神器,一键搞定繁琐工作
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
让更多数据处理,一键完成 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
楼主: liu-aguang

[原创] 网页数据采集---网页文档解析篇(json/html/xml)

  [复制链接]

TA的精华主题

TA的得分主题

 楼主| 发表于 2016-10-17 10:40 | 显示全部楼层
本帖已被收录到知识树中,索引项:网页交互
本帖最后由 liu-aguang 于 2016-10-18 11:30 编辑

五. XML文档解析

1. XML文档结构


<1>什么是XML?
前面已经知道, json是用来存储和传输数据的. 还有一种与json相同功能的"重量级"文件--XML, 它也是Web中较为常见的数据网页.不过它不用数组或对象来组织数据, 而是用标记来组织. 如:下面是一个用XML格式存储的两本书的相关信息(书名,作者,出版年,价格)的例子.


<?xml version="1.0" encoding="ISO-8859-1"?>  '第一行通常是XML声明xml版本,所用编码.
<bookstore>
<book category="COOKING">
  <title lang="en">水浒传</title>
  <author>(明)施耐庵</author>
  <year>2005</year>
  <price>20.00</price>
</book>
<book category="CHILDREN">
  <title lang="en">红楼梦</title>
  <author>(清)曹雪芹</author>
  <year>2005</year>
  <price>20.00</price>
</book>
</bookstore>

XML 指可扩展标记语言(EXtensible Markup Language),是纯文本.  可以看出,结构上XML与HTML很相似,但它们俩为不同目的而设计:
...XML 被设计为传输和存储数据,其焦点是数据的内容。
...HTML 被设计用来显示数据,其焦点是数据的外观。
...HTML 旨在显示信息,而 XML 旨在传输信息。
...XML标签没有被预定义,您需要自行定义标签; HTML标签是预定义的.
...XML被设计为具有自我描述性。

<2>XML语法特征
...所有 XML 元素都须有关闭标签
如:<book>....</book>
...XML 标签对大小写敏感
如: <Message>这是错误的。</message>
...XML 必须正确地嵌套
如:<b><i>This text is bold and italic</b></i>
在HTML中不会出问题,但在XML中是错误的.
...XML 文档必须有根元素
XML 文档必须有一个元素是所有其他元素的父元素。该元素称为根元素。
<root>
  <child>
    <subchild>.....</subchild>
  </child>
</root>


<3>XML文档的树形结构
在描述HTML树时, 我们用了标签,元素,属性,节点以及表达节点之间关系时的先辈/后代,父/子/同胞等概念.在XML中同样适用. 在解析XML文档时, 首先要转化为XML DOM(XML文档模型(对象)).

根据 DOM,XML 文档中的每个成分都是一个节点
DOM 是这样规定的:
  • 整个文档是一个文档节点
  • 每个 XML 标签是一个元素节点
  • 包含在 XML 元素中的文本是文本节点
  • 每一个 XML 属性是一个属性节点
  • 注释属于注释节点
在上面的 XML 中,根节点是 <bookstore>。文档中的所有其他节点都被包含在 <bookstore> 中。
根节点 <bookstore> 有四个 <book> 节点。
第一个 <book> 节点有四个节点:<title>, <author>, <year> 以及 <price>,其中每个节点都包含一个文本节点,"水浒传", "(明)施耐庵", "2005" 以及 "20"。

文本总是存储在文本节点中在 DOM 处理中一个普遍的错误是,认为元素节点包含文本。
不过,元素节点的文本是存储在文本节点中的。
在这个例子中:<year>2005</year>,元素节点 <year>,拥有一个值为 "2005" 的文本节点。
"2005" 不是 <year> 元素的值!




各节点彼此间有等级关系:
父、子和同级节点用于描述这种关系。父节点拥有子节点,位于相同层级上的子节点称为同级节点(兄弟或姐妹)。
  • 在节点树中,顶端的节点成为根节点
  • 根节点之外的每个节点都有一个父节点
  • 节点可以有任何数量的子节点
  • 叶子是没有子节点的节点
  • 同级节点是拥有相同父节点的节点
下面的图片展示出节点树的一个部分,以及节点间的关系:
捕获.PNG
<4>几个XML实例
(提示: 你可以用Fiddler记录打开以下链接后的会话, 在Fiddler中观察XML的树形结构)
一个XML的目录
http://www.w3school.com.cn/example/xmle/cd_catalog.xml
一个XML的植物目录
http://www.w3school.com.cn/example/xmle/plant_catalog.xml
一个简单的菜单
http://www.w3school.com.cn/example/xmle/simple.xml




评分

2

查看全部评分

TA的精华主题

TA的得分主题

发表于 2016-10-17 23:17 | 显示全部楼层
高人,麻烦看一下,我这个什么原因,XMLHTTP抓取的网页与实际输入网址不一样
Sub test()
    Dim strRespText$, tt$, i&, DW$
    Dim URL
    Dim URL2
    URL = "http://www.tianyancha.com"         
    URL2 = URL & "/search?key=" & UTF8_URLEncoding("浙江奥特服饰有限公司") & "&checkFrom=searchBox"
    Cells(9, 9) = URL2
    With CreateObject("Microsoft.XMLHTTP")
        .Open "GET", URL2, False
        .send
        tt = .responsetext
        With CreateObject("new:{1C3B4210-F441-11CE-B9EA-00AA006B1A69}")   
            .SetText tt                                                    '因为XMLHTTP默认是UTF-8,不能识别gb2312,会发现数据乱码
            .PutInClipboard                                                '所以不能采用.responsetext对象来得到字符串
        End With
        MsgBox DW
    End With
End Sub

评分

1

查看全部评分

TA的精华主题

TA的得分主题

 楼主| 发表于 2016-10-18 09:25 | 显示全部楼层
草本植物1983 发表于 2016-10-17 23:17
高人,麻烦看一下,我这个什么原因,XMLHTTP抓取的网页与实际输入网址不一样
Sub test()
    Dim strResp ...

Sub testw()  
    URL2 = "http://www.tianyancha.com/search/%E6%B5%99%E6%B1%9F%E5%A5%A5%E7%89%B9%E6%9C%8D%E9%A5%B0%E6%9C%89%E9%99%90%E5%85%AC%E5%8F%B8.json?"
    With CreateObject("Microsoft.XMLHTTP")
        .Open "GET", URL2, False
        .setRequestHeader "loop", "null"
        .send
        tt = .responseText
    End With
End Sub

评分

1

查看全部评分

TA的精华主题

TA的得分主题

发表于 2016-10-18 09:36 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
好文章,现mark收藏下,慢慢品读。

TA的精华主题

TA的得分主题

 楼主| 发表于 2016-10-18 15:26 | 显示全部楼层
2. XML文档的加载


XML DOM 含有遍历 XML 树以及访问、插入、删除节点的方法(函数)。所以,在访问并处理 XML 文档之前,必须把它载入 XML DOM 对象。加载有以下三种方式:

<1>通过微软的 XML 解析器加载 XML.

例2.1:加载一个XML文件(books.xml)

Sub loadXMLb()
    Set xmlDoc = CreateObject("Microsoft.XMLDOM")
    xmlDoc.async = "false"
    xmlDoc.Load ("http://www.w3school.com.cn/example/xdom/books.xml")
End Sub

代码解释:
第一行创建空的微软 XML 文档对象
第二行关闭异步加载,这样可确保在文档完整加载之前,解析器不会继续执行脚本
第三行告知解析器加载名为 "books.xml" 的文档

例2.2 :加载一个XML字符串

Sub loadxmla()
    Text = "<bookstore>"
    Text = Text + "<book>"
    Text = Text + "<title>Harry Potter</title>"
    Text = Text + "<author>J K. Rowling</author>"
    Text = Text + "<year>2005</year>"
    Text = Text + "</book>"
    Text = Text + "</bookstore>"
    Set xmlDoc = CreateObject("Microsoft.XMLDOM")
    xmlDoc.async = "false"
    xmlDoc.loadxml (Text)
End Sub

说明: loadXML() 方法用于加载字符串(文本),而 load() 用于加载文件。

<2>通过Microsoft.XMLHTTP, MSXML2.XMLHTTP等组件加载

例:2.3

Sub loadXMLc()
    Set ohttp = CreateObject("msxml2.xmlhttp")
    ohttp.Open "GET", "http://www.w3school.com.cn/example/xdom/books.xml", False
    ohttp.send
    Set xmlDoc = ohttp.responseXML   'responseXML属性返回XML DOM
End Sub

评分

1

查看全部评分

TA的精华主题

TA的得分主题

发表于 2016-10-18 16:18 | 显示全部楼层
本帖最后由 天之雨露 于 2016-10-18 16:26 编辑
liu-aguang 发表于 2016-10-18 09:25
Sub testw()  
    URL2 = "http://www.tianyancha.com/search/%E6%B5%99%E6%B1%9F%E5%A5%A5%E7%89%B9%E ...

我也看了42楼求助
你的URl2会失效,现在无效了.貌似不是普通网页

在浏览器上tianyancha主页搜索 浙江奥特服饰有限公司
马上使用你给的网址会返回正确数据.
但1,2次后很快会失效.显示
{"state":"ok","message":"","data":[{"id":null,"name":"浙江奥特服饰有限公司","type":1}]}

我用火狐 web开发者跟踪一下.
原始搜索页和你给的   url2=%E6%B5%9.json?这个网址 消息头中cookie 有8个参数,改变过,有不同的.
我想问
(1)是哪里,什么,怎样让 url2  %e6..B8.json?失效.
(2)如何模拟让url2一直有效,可以得到正确的返回值.
以上2个问题能详细讲一下吗,谢谢

TA的精华主题

TA的得分主题

 楼主| 发表于 2016-10-18 16:18 | 显示全部楼层
本帖最后由 liu-aguang 于 2016-10-20 13:12 编辑

3.利用XML DOM的属性和方法访问元素的文本内容或属性

在介绍HTML文档解析方法的时候, 我们是利用HTML DOM的方法或属性来访问HTML元素的; 这里利用XML DOM来访问XML文档元素与前面谈到的方式法几乎完全一样.


<1>利用XML DOM的方法选择XML元素


(下面假设x是一个节点对象)
x.getElementsByTagName(name) - 获取带有指定标签名称的所有元素
x.getElementByID(id) - 获取带有指定id的节点
x.getElementsByName(name) - 获取带有指定名称的所有节点

<2>利用XML DOM的属性访问元素的文本内容或属性

一些典型的 DOM 属性:
x.nodeName - x 的名称
x.nodeValue - x 的值
x.parentNode - x 的父节点
x.childNodes - x 的子节点
x.attributes - x 的属性节点
x.text - x的文本
x.length - x包含的元素个数


nodeValue 属性
nodeValue 属性规定节点的值。
----元素节点的 nodeValue 是 undefined 或 null
----文本节点的 nodeValue 是文本本身
----属性节点的 nodeValue 是属性值

<3>访问元素文本内容和属性的两个实例

Sub loadxmla1()
    Text = "<bookstore>"
    Text = Text + "<book>"
    Text = Text + "<title>Harry Potter</title>"
    Text = Text + "<author>J K. Rowling</author>"
    Text = Text + "<year>2005</year>"
    Text = Text + "</book>"
    Text = Text + "</bookstore>"
    Set xmlDoc = CreateObject("Microsoft.XMLDOM")
    xmlDoc.async = "false"
    xmlDoc.loadxml (Text)
    MsgBox xmlDoc.getElementsByTagName("title")(0).ChildNodes(0).nodevalue
    MsgBox xmlDoc.getElementsByTagName("title")(0).ChildNodes(0).Text
    MsgBox xmlDoc.getElementsByTagName("title")(0).Text
End Sub

解释:
xmlDoc - 由解析器创建的 XML DOM
getElementsByTagName("title")[0] - 第一个 <title> 元素
childNodes[0] - <title> 元素的第一个子节点 (文本节点)
nodeValue - 节点的值 (文本自身)
在上面的例子中,getElementsByTagName 是方法,而 childNodes , nodeValue和text 是属性。

Sub loadXMLb()
    Set xmlDoc = CreateObject("Microsoft.XMLDOM")
    xmlDoc.async = "false"
    xmlDoc.Load ("http://www.w3school.com.cn/example/xdom/books.xml")
    Set x = xmlDoc.getElementsByTagName("book")
    '下面三个等价方式
    MsgBox x(0).attributes(0).Text
    MsgBox x(0).attributes(0).nodevalue
    MsgBox x(0).attributes.getNamedItem("category").nodevalue
End Sub

该实例的部分XML文档:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!--  Copyright w3school.com.cn -->
<!-- W3School.com.cn bookstore example -->
<bookstore>
<book category="children">
<title lang="en">Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
<book category="cooking">
<title lang="en">Everyday Italian</title>
<author>Giada De Laurentiis</author>
<year>2005</year>
<price>30.00</price>
</book>
........................................




评分

2

查看全部评分

TA的精华主题

TA的得分主题

发表于 2016-10-18 16:42 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
本帖最后由 天之雨露 于 2016-10-18 16:44 编辑

我也看了42楼求助
你的URl2会失效,现在无效了.貌似不是一般普通网页

在浏览器上tianyancha主页搜索 浙江奥特服饰有限公司
马上使用你给的网址会返回正确数据.
但1,2次后很快会失效.显示
{"state":"ok","message":"","data":[{"id":null,"name":"浙江奥特服饰有限公司","type":1}]}

发现
原始搜索页和你给的   url2=%E6%B5%9.json?这个网址 cookie 有8个参数,会发生变化.
我想问
(1)是哪里,什么,怎样让 url2  %e6..B8.json?失效.是不是就是cookie引起的
(2)如何模拟让url2一直有效,可以得到正确的返回值.
以上2个问题能详细讲一下吗,谢谢

我刚刚在这帖子里发了一贴,莫名奇妙消失不见了,也没有系统提醒删除,不知道为什么

TA的精华主题

TA的得分主题

 楼主| 发表于 2016-10-18 17:10 | 显示全部楼层
4. 定位XML DOM节点

与定位HTML DOM节点相同:
在 XML DOM 中,节点的关系被定义为节点的属性:
  x.parentNode - x的父节点
  x.childNodes - x的所有子节点
  x.firstChild - x的第一个子节点
  x.lastChild  - x的最后一个子节点
  x.nextSibling - x的下一个同胞节点
  x.previousSibling - x的前一个同胞节点

5. 访问节点总结

您可以通过三种方法来访问节点:
<1>通过使用 getElementsByTagName() 方法
<2>通过循环(遍历)节点树
<3>通过利用节点的关系在节点树中导航

例5.1 使用节点列表中的下标号来访问节点


Sub loadXML()
    Set xmlDoc = CreateObject("Microsoft.XMLDOM")
    xmlDoc.async = "false"
    xmlDoc.Load ("http://www.w3school.com.cn/example/xdom/books.xml")
    Set x = xmlDoc.getElementsByTagName("title")
    MsgBox x(2).ChildNodes(0).nodevalue
End Sub
说明:本例使用 getElementsByTagname() 方法来获得 "books.xml" 中的第三个 <title> 元素。


例5.2 使用length属性来循环节点


Sub 访问2()
    Set xmlDoc = CreateObject("Microsoft.XMLDOM")
    xmlDoc.async = "false"
    xmlDoc.Load ("http://www.w3school.com.cn/example/xdom/books.xml")
    Set x = xmlDoc.getElementsByTagName("title")
    For i = 0 To x.Length - 1
        MsgBox x(i).ChildNodes(0).nodevalue
    Next
End Sub
说明: 本例使用 length 属性来循环 "books.xml" 中的所有 <title> 元素。


例5.3 循环元素节点


Sub 访问2()
    Set xmlDoc = CreateObject("Microsoft.XMLDOM")
    xmlDoc.async = "false"
    xmlDoc.Load ("http://www.w3school.com.cn/example/xdom/books.xml")
    Set x = xmlDoc.DocumentElement.ChildNodes
    For Each k In x
        MsgBox k.nodeName
    Next
End Sub
说明: documentElement 属性可返回文档的根节点。

例5.4 使用节点的关系来循环元素节点


Sub 访问4()
    Set xmlDoc = CreateObject("Microsoft.XMLDOM")
    xmlDoc.async = "false"
    xmlDoc.Load ("http://www.w3school.com.cn/example/xdom/books.xml")
    Set x = xmlDoc.getElementsByTagName("book")(0).ChildNodes
    Set y = xmlDoc.getElementsByTagName("book")(0).FirstChild
    For i = 0 To x.Length - 1
        If y.NodeType = 1 Then
            MsgBox y.nodeName
        End If
        Set y = y.NextSibling
    Next
End Sub


说明: 本例使用 nodeType 属性和 nextSibling 属性来处理 "books.xml" 中的元素节点。
nodeType 属性
nodeType 属性规定节点的类型。
nodeType 是只读的。
最重要的节点类型是:
元素类型 节点类型
元素        1
属性        2
文本        3
注释        8
文档        9


评分

1

查看全部评分

TA的精华主题

TA的得分主题

 楼主| 发表于 2016-10-18 17:35 | 显示全部楼层
天之雨露 发表于 2016-10-18 16:42
我也看了42楼求助
你的URl2会失效,现在无效了.貌似不是一般普通网页

没有发现你说的情况. 该网页请求不需要Cookie也可正确返回json; 你可以用WinHttp.WinHttpRequest.5.1测试.

评分

1

查看全部评分

您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2024-12-22 19:11 , Processed in 0.037530 second(s), 8 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

快速回复 返回顶部 返回列表