Selenium需要定位页面元素,而DOM 代表了整个 HTML 文档的结构,使用 DOM对象可以访问 DOM 中的节点。 WebDriver甚至可以通过执行任意的返回值为 DOM 对象的 JavaScript 语句来查找元素,所熟悉DOM对于Selenium处理页面元素来说如虎添翼。
DOM是Document Object Model文档对象模型的缩写。根据W3C DOM规范,DOM是一种与浏览器,平台,语言无关的接口,使得你可以访问页面其他的标准组件。DOM是以层次结构组织的节点或信息片断的集合。这个层次结构允许开发人员在树中导航寻找特定信息。分析该结构通常需要加载整个文档和构造层次结构,然后才能做任何工作。由于它是基于信息层次的,因而DOM被认为是基于树或基于对象的。HTML DOM是HTML Document Object Model(文档对象模型)的缩写,HTML DOM则是专门适用与HTML/XHTML的文档对象模型。熟悉软件开发的人员可以将HTML DOM理解为网页的API。它将网页中的各个元素都看作一个个对象,从而使网页中的元素也可以被计算机语言获取或者编辑。 例如JavaScript就可以利用HTMLDOM动态的修改网页。“W3C的文档对象模型(DOM)是中立于平台和语言的接口,它允许程序和脚本动态地访问和更新文档的内容、结构和样式。W3CDOM标准被分为 3 个不同的部分:核心 DOM - 针对任何结构化文档的标准模型;XML DOM - 针对 XML 文档的标准模型;HTML DOM - 针对 HTML 文档的标准模型。 DOM将HTML和XML文档映射成一个由不同节点组成的树型机构。俗称DOM树。每种节点都对应于文档中的信息或标记,节点有自己的属性和方法,并和其他节点存在某种关系,节点之间的关系构成了节点层次。
因为python没有很直观的处理HTML DOM的库,为了便于学习所以我们用javascript来进行解析处理,本部分学习用js代码来完成。HTML DOM 是 W3C 标准(是 HTML 文档对象模型的英文缩写,Document Object Model for HTML)。它定义了用于 HTML 的一系列标准的对象,以及访问和处理 HTML 文档的标准方法。通过 DOM,可以访问所有的 HTML 元素,连同它们所包含的文本和属性。可以对其中的内容进行修改和删除,同时也可以创建新的元素。HTML DOM 独立于平台和编程语言,它可被任何编程语言诸如 Java、JavaScript 和 Python使用。
下面是HTML源码:
HTML DOM学习
DOM构成
DOM树结构:
当浏览器载入HTML文档时,浏览器解释其代码,按照html的载入顺序在内存中创建这些对象,对象创建完毕后浏览器为这些对象提供了专供javascript脚本可用的可选属性,方法和处理程序。通过这些属性,方法,处理程序,web开发人员很好的完成相应功能的实现。
在DOM中,html文档各个节点被视为各种类型的Node对象,每个Node对象都有自己的属性和方法,利用这些属性和方法可以通过遍历整个文档,由于HTML的复杂性,DOM定义了nodeType来表示节点的类型。
在W3C DOM中,每个容器,独立的元素或者文本块都可以被看作是一个节点,其对应的节点存在父子关系,同时该节点树遵循HTML的结构化本质,如元素包括
元素,他们有分别包含了不同的节点。在HTMLdom中有六种不同的节点类型:HTML DOM树中有元素节点,属性节点,文本节点分别介绍:
A. 元素节点
在HTML文档中,各个HTML元素如
- Coffee
- Tea
- Milk
B. 文本节点
在节点树中,元素节点构成了树的枝干,而文本节点则构成了树的树叶,
郭靖知道师父虽然摔下,并不碍事,但欧阳锋若乘势追击,后着可凌厉之极,叫道:“看招!”左腿微屈,右掌划了个圆圈,平推出去,正是降龙十八掌中的“亢龙有悔”。
,在html中文本是包含在元素节点内部的,如上面这段文字就是包含在元素内。
C. 属性节点
HTML文档中袁术都有一些属性,这些属性准确的便于开发人员操作。如:
你好,世界!
,这里class=dom就是属性节点。
从上面的描述可以看出来节点树中的节点彼此拥有层级关系,节点之间的关系可以使用类似人类家族关系的形式描述。如在HTML文档中,可以把html标签看作是body标签的父元素;相对的,body标签也就是html标签的子元素;而做为body标签同级的head标签两都之者的关系为兄弟(姐妹)关系。在dom中父(parent)、子(child)和同胞(sibling)等术语用于描述这些关系。父节点拥有子节点。同级的子节点被称为同胞(兄弟或姐妹)。
在Web自动化测试开发中达到控制页面元素,执行相应操作行为的目的,了解HTMLDOM是很有必要的,我们用JavaScript来用代码操作DOM是因为DOM接口是标准的,另外是因为可以了解更多的代码细节。JavaScript操作DOM一般有以下4种操作;
JavaScript实现的DOM接口一般有:
1. Document属性
A. document.title //设置文档标题等价于HTML的title标签
B. document.bgColor //设置页面背景色
C. document.fgColor //设置前景色(文本颜色)
D. document.linkColor //未点击过的链接颜色
E. document.alinkColor //激活链接(焦点在此链接上)的颜色
F. document.vlinkColor //已点击过的链接颜色
G. document.URL //设置URL属性从而在同一窗口打开另一网页
H. document.fileCreatedDate //文件建立日期,只读属性
I. document.fileModifiedDate //文件修改日期,只读属性
J. document.charset //设置字符集 简体中文:gb2312
K. document.fileSize //文件大小,只读属性
L. document.cookie //设置和读出cookie
2. Document常用对象方法
A. document.write() //动态向页面写入内容
B. document.createElement(Tag) //创建一个html标签对象
C. document.getElementById(ID) //获得指定ID值的对象 /
D. document.getElementsByName(Name) //获得指定Name值的对象
E. document.body.appendChild(oTag)
3. 获取HTML元素
A. getElementByID(id):通过对元素的ID访问,这是DOM访问页面元素的方法.
实例:
dom操作
我是第一个P
我是第二个P
测试
技术解释:如果id在元素中不是唯一的,那么获得的将是第一个ID,window.onload是在DOM文档树加载完和所有文件加载完之后执行一个函数,也就是自己触发该函数。
B. getElementsByName(name):仅用于input ,radio checkbox等元素,返回名字为name的元素数组
实例:
dom操作
我是第一个P
我是第二个P
测试
/>
C. getElementsByTagName(tagname):返回具有tagname的元素列表数组.处理大的DOM结构会用到它,
实例:获取页面所有DIV元素
div 1
div 2
4 .操作DOM 元素
A. document.createElement(eName):创建一个节点
DOM操作
第一段
第二段
B. appendChild(node):向当前对象追加节点
实例:
DOM操作
第一段
第二段
C. removeChild(childreference):移除当前节点的子节点,并返回节点
实例:
dom操作
父亲
儿子
姑娘
D. cloneNode(deepBoolean):复制并返回当前的复制节点,由于复制了原节点的id属性,所以在document树中要改ID属性,以确保ID唯一性.
E. insertBefore(newElment,targetElement) 插入新的节点。在当前节点插入一个新节点,如果targetElement为null,那新节点为最后节点.
实例:
insertBefore()函数
- 复仇者联盟
- 正义联盟
- x战警
- 光照会
5. DOM Element常用属性
A. childeNodes 返回所有子节点对象
实例:
返回节点文本
- 复仇者联盟
- 正义联盟
- x战警
- 光照会
B. innerHTML:这是一个标准,但它并不是DOM
实例:
修改元素
- 复仇者联盟
- 正义联盟
- x战警
- 光照会
C. style:这是一个极其重要的属性,可以获取并修改每个单独的样式.
实例:
设置属性
- 复仇者联盟
- 正义联盟
- x战警
- 光照会
D. 节点
firstChild:返回第一个子节点;lastChild :返回最后一个子节点:parentNode :返回父节点的对象;nextSibling :返回下一个兄弟节点的对象;previousSibling 返回前一个兄弟节点的对象; 元素节点可以用数组元素childNodes[0]来获取,和他等同的功能的属性,且更加语义化,可以用firstChild,lastChild等属性。假设我们需要目标元素节点下的所有子元素中的第一个子元素可以这样做:目标元素节点下的子元素节点数组.firstChild 这句代码等价于目标元素节点下的子元素节点数组[0];目标元素节点.childNodes[0] 这句代码等价于 目标元素节点.firstChild;与此类推当我们需要目标元素节点下的所有子元素节点中的最后一个元素我们可以这样做:目标元素节点下的子元素节点数组.lastChild 这句代码等价于 目标元素节点下的子元素节点数组[目标元素节点下的子元素节点数组.length-1]目标元素节点.childNodes[目标元素节点.childNodes.length-1]=目标元素节点.lastChild;从上面的描述中,发现firstChild属性和lastChild属性更加的语义化,而且代码更加的简洁,方便我们记忆;
E. nodeName 返回节点的HTML标记名称,使用英文的大写字母。
作用:如果我们想改变一个文本节点的值,那就是用DOM提供的nodeValue属性,它是用来得到(和设置)一个文本节点的值;
实例:
hello world!
我们获取的p是一个元素节点,
元素本身的nodeValue值是一个null值,而且最重要的是nodeValue属性是用来获取文本节点的值的。所以输出:null.。这个是一个技术细节,也是一个小知识点.需要注意。正确的获取
标签里面文本的做法是获取
标签下文本节点的节点值。
代码如下: 这里
标签代表一个元素节点
hello world!
XML ( eXtensible Markup Language )语言是一种可扩展的标记语言。其中的可扩展是相对HTML来说的。因为XML标签没有被预定义,需要用户自行定义标签。通过此种标记,计算机之间可以处理包含各种信息的文章等。XML设计用来传送及携带数据信息,不用来表现或展示数据,所以XML用途的焦点是它说明数据是什么,以及携带数据信息。而HTML语言则用来表现数据。下面自定义一个xml文件来存储书信息:
<书架>
<书出版社="浙江出版社">
<名字>诛仙名字>
<作者>萧鼎作者>
<价格>32.00价格>
<出版日期>2007年出版日期>
书>
<书出版社="文艺出版社">
<名字>笑傲江湖名字>
<作者>金庸作者>
<价格>50.00价格>
书>
<书出版社="人邮出版社">
<名字>selenium自动化测试名字>
<作者>威链优创作者>
<价格>50.00价格>
书架>
XML 文档的第一行是一个 XML 声明,这是文件的可选部分,它将文件识别为XML文件,该XML文件表示书架上有三本书,并把每本书标识出出版社,名称,作者,价格。在XML语言中,它允许用户自定义标签。一个标签用于描述一段数据;一个标签可以分为开始标签和结束标签,在开始标签和结束标签之间,又可以使用其他标签描述其他数据,以此来实现数据关系的描述。在上个实例中书名,作者,价格都是自定义标签,如果你喜欢你可以把所有的标签名字都改成英文也可以。
通过前面的知识我们了解DOM是一种树结构,XML文档结构就是类似倒长的树型结构
一个XML文件分为如下6部分内容:文档声明,元素 ,属性,注释 ,CDATA区、特殊字符,处理指令(processing instruction)。
1. XML文档声明
XML声明语句一般是这样,放在XML文档的第一行 ,version 指文档符合XML1.0规范 ;encoding指文档字符编码,比如”GB2312”或者”UTF-8” ;还有参数standalone指文档定义是否独立使用 ,standalone=”no”为默认值。yes代表是独立使用,而no代表不是独立使用
2. XML元素
A. XML文档必须有且只有一个根元素
B. XML元素指的是XML文件中出现的标签,标签都是成对出现分为开始和结束标签
C. (命名规范: XML元素可以包含字母、数字以及其它一些可见字符,但必须遵守以下规范:
3. XML属性
Tom
person >
4. XML-注释
XML的注释类语法:
5. XMLCDATA节
在XML中CDATA被声明不应被解析成标签的文本,其中可以使用特殊字符,包括大于号,小于号和双引号。CDATA段通过来设置,所有在中间的内容都被当做原始字符,而不会进行字符转义。如实际应用中通过XML文件发送图片,就需要用CDATA节来处理。文件本质上是字符串,在底层都是用二进制传输。根据原理通过XML文件将一幅图片的二进制字符串传递过去,然后可以解析成一幅图片。由于字符串就会包含大量的<,>,&或者“等一些特殊的不合法的字符,引擎解析会报错。为了不让图内容用引擎解析执行,而是做为原始内容处理,要用到CDATA节。
语法如下:
......
]]>
6. XML处理指令
处理指令,简称PI(processing instruction)。处理指令用来指示解析引擎如何解析XML文件,看下面一个例子:比如可以使用CSS样式表来修饰XML文件,编写test.css如下:
name{
font-size:60px;
font-weight:bold;
color:red;
}
sex{
font-size:60px;
font-weight:bold;
color:red;
}
age{
font-size:60px;
font-weight:bold;
color:red;
}
我们在xml文件中使用处理指令引入这个CSS文件,如下:
郭靖
男
16
黄蓉
女
21
再用浏览器打开这个xml文件,会发现浏览器解析出一个带样式的视图,而不再是单纯的目录树了。
在python标准库中支持DOM操作的模块是xml.dom,xml文档数据通过xml.dom模块的方法解析为dom树结构后,就可以调用dom规范中定义的方法和属性来访问XML数据。需要注意,这些方法都是DOM规范中规定的,不是xml.dom模块规定的,xml.dom只是实现了这些操作xml数据的接口。
1. XMLDOM接口
A. Document接口:
Document代表整个XML文档,实际上这是XML文档树的根,同时提供了对数据初始访问的入口。
B. Node接口
XML文档的所有组件都可以看作是Node对象。
C. Element接口
D. Text接口
2. XML实例
创建XML文件如下:
郭靖
30
降龙十八掌
黄蓉
20
打狗棒法
A. 获得标签属性
实例:
import xml.dom.minidom
dom = xml.dom.minidom.parse(r" employees.xml") #打开xml文档
root = dom.documentElement #得到xml文档对象
print("nodeName:", root.nodeName) #每一个结点都有它的nodeName,nodeValue,nodeType属性
print("nodeValue:", root.nodeValue) #nodeValue是结点的值,只对文本结点有效
print("nodeType:", root.nodeType)
print("ELEMENT_NODE:", root.ELEMENT_NODE)
技术解释:xml.dom.minidom.parse()得到一个dom对象,它的第一个元素应该是employees,root = dom.documentElement得到文档根元素,也就是得到了employees, 每一个结点都有它的nodeName,nodeValue,nodeType属性。nodeName为结点名字。nodeValue是结点的值,只对文本结点有效。nodeType是结点的类型,现在有以下几种:
B. 获得子标签
实例:
import xml.dom.minidom
dom = xml.dom.minidom.parse(r" employees.xml")
root = dom.documentElement
children = root.getElementsByTagName('employee')
print(len(children))
children_brother = children[1]
print(children_brother.nodeName)
print(children_brother.nodeValue)
技术解释:访问子元素、子结点的方法很多,对于知道元素名字的子元素,可以使用getElementsByTagName方法,如读取empolyee子元素代码是root.getElementsByTagName('employee')
还有getElementsByTagName是返回一个元素列表,该XML文档中有两个empolyee节点,所以children返回的是2个值,然后打印第二个节点的节点名字和节点属性。
C. 获得标签属性值
实例:
dom = xml.dom.minidom.parse(r"employees.xml")
root = dom.documentElement
children= root.getElementsByTagName('employee')
item = children[0]
print(item.getAttribute("id"))
item = children[1]
print(item.getAttribute("id"))
技术解释:一个元素有属性,那么可以使用getAttribute方法,参数是XML节点的属性,在本例中
D. 解析xml,获得每个子节点的值
实例:
import xml.dom.minidom
dom = xml.dom.minidom.parse(r" employees.xml")
root = dom.documentElement
employees = root.getElementsByTagName("employee")
for employee in employees:
print(" ------------------------------------------- ")
print(employee.nodeName)
nameNode = employee.getElementsByTagName("name")[0]
print(nameNode.nodeName + " : " + nameNode.childNodes[0].nodeValue)
sillNode = employee.getElementsByTagName("skill")[0]
print(sillNode.nodeName + " : " + sillNode.childNodes[0].nodeValue)
ageNode = employee.getElementsByTagName("age")[0]
print(ageNode.nodeName + " : " + ageNode.childNodes[0].nodeValue)
print(" ------------------------------------------- ")
运行结果:
-------------------------------------------
employee
name : 郭靖
skill : 降龙十八掌
age : 30
-------------------------------------------
employee
name : 黄蓉
skill : 打狗棒法
age : 20
-------------------------------------------
技术解释:使用parse()或createDocument()返回的为DOM对象,使用DOM的documentElement属性可以获得Root Element,DOM为树形结构,包含许多的nodes,其中element是node的一种,可以包含子elements,textNode也是node的一种,是最终的子节点;每个node都有nodeName,nodeValue,nodeType属性,nodeValue是结点的值,只对textNode有效。
E. 为XML添加节点
实例:
import xml.dom.minidom
dom = xml.dom.minidom.parse(r"C:employees.xml")
root = dom.documentElement
employee = dom.createElement('employee')
employee.setAttribute('id', '003')
root.appendChild(employee)
nameE = dom.createElement('name')
nameT = dom.createTextNode('芮伟 ')
nameE.appendChild(nameT)
employee.appendChild(nameE)
skillE = dom.createElement('skill')
skillT = dom.createTextNode('四照神功')
skillE.appendChild(skillT)
employee.appendChild(skillE)
ageE = dom.createElement('age')
ageT = dom.createTextNode('17')
ageE.appendChild(ageT)
employee.appendChild(ageE)
print(dom.toxml())
技术解释:dom是树结构,包括叶子结点(不包含其它结点的结点,如文本结点)和非叶子结点(包含其它结点的结点,如元素结点)的生成,然后就需要利用结点对象本身的appendChild()或insertBefore()方法将各个结点根据在树中的位置连起来,串成一棵树,其中dom.createElement()生成元素节点,dom.createTextNode生成文本节点,setAttribute设置节点属性。