python中lxml模块的使用,Python 中 xpath 语法 与 lxml 库解析 HTML/XML 和 CSS Selector

lxml是python的一个解析库,支持HTML和XML的解析,支持XPath解析方式,而且解析效率非常高

xml的安装,导入,使用

1.lxml的安装
pip install lxml

2.导入lxml 的 etree 库
 from lxml import etree
 # etree全称:ElementTree 元素树
step3: selector = etree.HTML(网页源代码)
step4: selector.xpath(一段神奇的符号)

3.利用etree.HTML,将字符串转化为Element对象,Element对象具有xpath的方法,返回结果的列表,能够接受bytes类型的数据和str类型的数据。

from lxml import etree
html = etree.HTML(response.text) 
ret_list = html.xpath("xpath字符串")

也可以这样使用:

from lxml import etree
htmlDiv = etree.HTML(response.content.decode())
hrefs = htmlDiv.xpath("//h4//a/@href")

4.把转化后的element对象转化为字符串,返回bytes类型,etree.tostring(element)

假设我们现有如下的html字符换,尝试对他进行操作:

<div> <ul> 
<li class="item-1"><a href="link1.html">first item</a></li> 
<li class="item-1"><a href="link2.html">second item</a></li> 
<li class="item-inactive"><a href="link3.html">third item</a></li> 
<li class="item-1"><a href="link4.html">fourth item</a></li> 
<li class="item-0"><a href="link5.html">fifth item</a> # 注意,此处缺少一个 </li> 闭合标签 
</ul> </div>

5 etree.tostring
handeled_html_str = etree.tostring(html).decode()
print(handeled_html_str)
可以发现,lxml确实能够把确实的标签补充完成,但是请注意lxml是人写的,很多时候由于网页不够规范,或者是lxml的bug。
即使参考url地址对应的响应去提取数据,任然获取不到,这个时候我们需要使用etree.tostring的方法,观察etree到底把html转化成了什么样子,即根据转化后的html字符串去进行数据的提取。


————————————————
版权声明:本文为CSDN博主「埃菲尔没有塔尖」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_38819889/article/details/103551896

python3 lxml用法

python3.5 lxml用法
问题1:有一个XML文件,如何解析 
问题2:解析后,如果查找、定位某个标签 
问题3:定位后如何操作标签,比如访问属性、文本内容等 
开始之前,首先是导入模块,该库常用的XML处理功能都在lxml.etree中
导入模块:from lxml import etree 


Element类

Element是XML处理的核心类,Element对象可以直观的理解为XML的节点,大部分XML节点的处理都是围绕该类进行的。
这部分包括三个内容:节点的操作、节点属性的操作、节点内文本的操作。

节点操作

1、创建Element对象
        直接使用Element方法,参数即节点名称。
        root = etree.Element(‘root’) 
        print(root) 

2、获取节点名称
        使用tag属性,获取节点的名称。
        print(root.tag) 
        root 

3、输出XML内容
        使用tostring方法输出XML内容(后文还会有补充介绍),参数为Element对象。
        print(etree.tostring(root)) 
        b’’ 
4、添加子节点
        使用SubElement方法创建子节点,第一个参数为父节点(Element对象),第二个参数为子节点名称。
        child1 = etree.SubElement(root, ‘child1’) 
        child2 = etree.SubElement(root, ‘child2’) 
        child3 = etree.SubElement(root, ‘child3’) 
5、删除子节点
        使用remove方法删除指定节点,参数为Element对象。clear方法清空所有节点。
        root.remove(child1) # 删除指定子节点 
        print(etree.tostring(root)) 
        b’’ 
        root.clear() # 清除所有子节点 
        print(etree.tostring(root)) 
        b’’ 
6、以列表的方式操作子节点
        可以将Element对象的子节点视为列表进行各种操作:
        child = root[0] # 下标访问 
        print(child.tag) 
        child1
        print(len(root)) # 子节点数量 
        3
        root.index(child2) # 获取索引号 
        1
        for child in root: # 遍历 
        … print(child.tag) 
        child1 
        child2 
        child3
        root.insert(0, etree.Element(‘child0’)) # 插入 
        start = root[:1] # 切片 
        end = root[-1:]
        print(start[0].tag) 
        child0 
        print(end[0].tag) 
        child3
        root.append( etree.Element(‘child4’) ) # 尾部添加 
        print(etree.tostring(root)) 
        b’’ 
        其实前面讲到的删除子节点的两个方法remove和clear也和列表相似。

7、获取父节点
        使用getparent方法可以获取父节点。
        print(child1.getparent().tag) 
        root 


属性操作

属性是以key-value的方式存储的,就像字典一样。

1、创建属性

        可以在创建Element对象时同步创建属性,第二个参数即为属性名和属性值:
        root = etree.Element(‘root’, interesting=’totally’) 
        print(etree.tostring(root)) 
        b’’ 
        也可以使用set方法给已有的Element对象添加属性,两个参数分别为属性名和属性值:

        root.set(‘hello’, ‘Huhu’) 
        print(etree.tostring(root)) 
        b’’
2、获取属性
        属性是以key-value的方式存储的,就像字典一样。直接看例子

        get方法获得某一个属性值
        print(root.get(‘interesting’)) 
        totally
        keys方法获取所有的属性名
        sorted(root.keys()) 
        [‘hello’, ‘interesting’]

        items方法获取所有的键值对
        for name, value in sorted(root.items()): 
            … print(‘%s = %r’ % (name, value)) 
        hello = ‘Huhu’ 
        interesting = ‘totally’ 
        也可以用attrib属性一次拿到所有的属性及属性值存于字典中:
        attributes = root.attrib 
        print(attributes) 
        {‘interesting’: ‘totally’, ‘hello’: ‘Huhu’}

        attributes[‘good’] = ‘Bye’ # 字典的修改影响节点 
        print(root.get(‘good’)) 
        Bye 


文本操作

标签及标签的属性操作介绍完了,最后就剩下标签内的文本了。
可以使用text和tail属性、或XPath的方式来访问文本内容。

1、text 和 tail 属性

        一般情况,可以用Element的text属性访问标签的文本。
        root = etree.Element(‘root’) 
        root.text = ‘Hello, World!’ 
        print(root.text) 
        Hello, World! 
        print(etree.tostring(root)) 
        b’Hello, World!’ 

        Element类提供了tail属性支持单一标签的文本获取。
        html = etree.Element(‘html’) 
        body = etree.SubElement(html, ‘body’) 
        body.text = ‘Text’ 
        print(etree.tostring(html)) 
        b’Text’
        br = etree.SubElement(body, ‘br’) 
        print(etree.tostring(html)) 
        b’Text’
        tail仅在该标签后面追加文本       
        br.tail = ‘Tail’ 
        print(etree.tostring(br)) 
        b’
        Tail’
        print(etree.tostring(html)) 
        b’Text
        Tail’
        tostring方法增加method参数,过滤单一标签,输出全部文本
        print(etree.tostring(html, method=’text’)) 
        b’TextTail’ 
2、XPath方式
        方式一:过滤单一标签,返回文本
        print(html.xpath(‘string()’)) 
        TextTail
        方式二:返回列表,以单一标签为分隔
        print(html.xpath(‘//text()’)) 
        [‘Text’, ‘Tail’] 
        方法二获得的列表,每个元素都会带上它所属节点及文本类型信息,如下:
        texts = html.xpath(‘//text()’))
        print(texts[0]) 
        Text


所属节点
        parent = texts[0].getparent() 
        print(parent.tag) 
        body
        print(texts[1], texts[1].getparent().tag) 
        Tail br

文本类型:是普通文本还是tail文本
        print(texts[0].is_text) 
        True 
        print(texts[1].is_text) 
        False 
        print(texts[1].is_tail) 
        True 


文件 解析 与 输出
回答问题1。

这部分讲述如何将XML文件解析为Element对象,以及如何将Element对象输出为XML文件。

1、文件解析

        文件解析常用的有fromstring、XML 和 HTML 三个方法。接受的参数都是字符串。
        xml_data = ‘data’
        fromstring方法
        root1 = etree.fromstring(xml_data) 
        print(root1.tag) 
        root 
        print(etree.tostring(root1)) 
        b’data’

        XML方法,与fromstring方法基本一样

        root2 = etree.XML(xml_data) 
        print(root2.tag) 
        root 
        print(etree.tostring(root2)) 
        b’data’


        HTML方法,如果没有和标签,会自动补上
        root3 = etree.HTML(xml_data) 
        print(root3.tag) 
        html 
        print(etree.tostring(root3)) 
        b’data’ 
2、输出
        输出其实就是前面一直在用的tostring方法了,这里补充xml_declaration和encoding两个参数,前者是XML声明,后者是指定编码。
        root = etree.XML(‘‘)
        print(etree.tostring(root)) 
        b’’


XML声明
print(etree.tostring(root, xml_declaration=True)) 
b”


指定编码

print(etree.tostring(root, encoding=’iso-8859-1’)) 
b”

查找第一个b标签
print(root.find(‘b’)) 
None 
print(root.find(‘a’).tag) 
a

查找所有b标签,返回Element对象组成的列表

[ b.tag for b in root.findall(‘.//b’) ] 
[‘b’, ‘b’]


根据属性查询
print(root.findall(‘.//a[@x]’)[0].tag) 
a 
print(root.findall(‘.//a[@y]’)) 
[] 
————————————————
版权声明:本文为CSDN博主「「已注销」」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/lyshark_lyshark/article/details/125846734

lxml属性操作

属性是以key-value的方式存储的,就像字典一样。

1、创建属性

        可以在创建Element对象时同步创建属性,第二个参数即为属性名和属性值:
        root = etree.Element(‘root’, interesting=’totally’) 
        print(etree.tostring(root)) 
        b’’ 
        也可以使用set方法给已有的Element对象添加属性,两个参数分别为属性名和属性值:

        root.set(‘hello’, ‘Huhu’) 
        print(etree.tostring(root)) 
        b’’
2、获取属性
        属性是以key-value的方式存储的,就像字典一样。直接看例子

        get方法获得某一个属性值
        print(root.get(‘interesting’)) 
        totally
        keys方法获取所有的属性名
        sorted(root.keys()) 
        [‘hello’, ‘interesting’]

        items方法获取所有的键值对
        for name, value in sorted(root.items()): 
            … print(‘%s = %r’ % (name, value)) 
        hello = ‘Huhu’ 
        interesting = ‘totally’ 
        也可以用attrib属性一次拿到所有的属性及属性值存于字典中:
        attributes = root.attrib 
        print(attributes) 
        {‘interesting’: ‘totally’, ‘hello’: ‘Huhu’}

        attributes[‘good’] = ‘Bye’ # 字典的修改影响节点 
        print(root.get(‘good’)) 
        Bye 


lxml 文本操作

标签及标签的属性操作介绍完了,最后就剩下标签内的文本了。
可以使用text和tail属性、或XPath的方式来访问文本内容。

1、text 和 tail 属性

        一般情况,可以用Element的text属性访问标签的文本。
        root = etree.Element(‘root’) 
        root.text = ‘Hello, World!’ 
        print(root.text) 
        Hello, World! 
        print(etree.tostring(root)) 
        b’Hello, World!’ 

        Element类提供了tail属性支持单一标签的文本获取。
        html = etree.Element(‘html’) 
        body = etree.SubElement(html, ‘body’) 
        body.text = ‘Text’ 
        print(etree.tostring(html)) 
        b’Text’
        br = etree.SubElement(body, ‘br’) 
        print(etree.tostring(html)) 
        b’Text’
        tail仅在该标签后面追加文本       
        br.tail = ‘Tail’ 
        print(etree.tostring(br)) 
        b’
        Tail’
        print(etree.tostring(html)) 
        b’Text
        Tail’
        tostring方法增加method参数,过滤单一标签,输出全部文本
        print(etree.tostring(html, method=’text’)) 
        b’TextTail’ 
2、XPath方式
        方式一:过滤单一标签,返回文本
        print(html.xpath(‘string()’)) 
        TextTail
        方式二:返回列表,以单一标签为分隔
        print(html.xpath(‘//text()’)) 
        [‘Text’, ‘Tail’] 
        方法二获得的列表,每个元素都会带上它所属节点及文本类型信息,如下:
        texts = html.xpath(‘//text()’))
        print(texts[0]) 
        Text
所属节点
        parent = texts[0].getparent() 
        print(parent.tag) 
        body
        print(texts[1], texts[1].getparent().tag) 
        Tail br

文本类型:是普通文本还是tail文本
        print(texts[0].is_text) 
        True 
        print(texts[1].is_text) 
        False 
        print(texts[1].is_tail) 
        True 


文件 解析 与 输出
回答问题1。

这部分讲述如何将XML文件解析为Element对象,以及如何将Element对象输出为XML文件。

1、文件解析

        文件解析常用的有fromstring、XML 和 HTML 三个方法。接受的参数都是字符串。
        xml_data = ‘data’
        fromstring方法
        root1 = etree.fromstring(xml_data) 
        print(root1.tag) 
        root 
        print(etree.tostring(root1)) 
        b’data’

        XML方法,与fromstring方法基本一样

        root2 = etree.XML(xml_data) 
        print(root2.tag) 
        root 
        print(etree.tostring(root2)) 
        b’data’


        HTML方法,如果没有和标签,会自动补上
        root3 = etree.HTML(xml_data) 
        print(root3.tag) 
        html 
        print(etree.tostring(root3)) 
        b’data’ 
2、输出
        输出其实就是前面一直在用的tostring方法了,这里补充xml_declaration和encoding两个参数,前者是XML声明,后者是指定编码。
        root = etree.XML(‘‘)
        print(etree.tostring(root)) 
        b’’

指定编码

print(etree.tostring(root, encoding=’iso-8859-1’)) 
b”

查找第一个b标签
print(root.find(‘b’)) 
None 
print(root.find(‘a’).tag) 
a

查找所有b标签,返回Element对象组成的列表

[ b.tag for b in root.findall(‘.//b’) ] 
[‘b’, ‘b’]


根据属性查询
print(root.findall(‘.//a[@x]’)[0].tag) 
a 
print(root.findall(‘.//a[@y]’)) 
[] 

XPath语法

XPath 是一门在 XML 文档中查找信息的语言。XPath 可用来在 XML 文档中对元素和属性进行遍历。XPath 是 W3C XSLT 标准的主要元素,并且 XQuery 和 XPointer 都构建于 XPath 表达之上。

在 XPath 中,有七种类型的节点:元素、属性、文本、命名空间、处理指令、注释以及文档(根)节点。XML 文档是被作为节点树来对待的。树的根被称为文档节点或者根节点。

根节点在xpath中可以用 “//” 来啊表示

XPath 常用规则

表达式	描述
nodename	选取此节点的所有子节点
/	从当前节点选取直接子节点
//	从当前节点选取子孙节点
.	选取当前节点
..	选取当前节点的父节点
@	选取属性
*	通配符,选择所有元素节点与元素名
@*	选取所有属性
[@attrib]	选取具有给定属性的所有元素
[@attrib='value']	选取给定属性具有给定值的所有元素
[tag]	选取所有具有指定元素的直接子节点
[tag='text']	选取所有具有指定元素并且文本内容是text节点

参考文献

The lxml.etree Tutorial :https://lxml.de/tutorial.html

python3 解析 xml:https://www.cnblogs.com/deadwood-2016/p/8116863.html

微软文档:  XPath 语法 和 XPath 函数
W3school Xpath 教程:http://www.w3school.com.cn/xpath/
Xpath 菜鸟教程:http://www.runoob.com/xpath/xpath-tutorial.html
简书:Xpath高级用法:https://www.jianshu.com/p/1575db75670f
30个示例手把手教你学会Xpath高级用法:https://www.sohu.com/a/211716225_236714
了解XPath常用术语和表达式解析 十分钟轻松入门:http://www.bazhuayu.com/blog/2014091

Python lxml语法

XPath语法
XPath 是一门在 XML 文档中查找信息的语言。XPath 可用来在 XML 文档中对元素和属性进行遍历。XPath 是 W3C XSLT 标准的主要元素,并且 XQuery 和 XPointer 都构建于 XPath 表达之上。

在 XPath 中,有七种类型的节点:元素、属性、文本、命名空间、处理指令、注释以及文档(根)节点。XML 文档是被作为节点树来对待的。树的根被称为文档节点或者根节点。

根节点在xpath中可以用 “//” 来啊表示

XPath 常用规则

表达式	描述
nodename	选取此节点的所有子节点
/	从当前节点选取直接子节点
//	从当前节点选取子孙节点
.	选取当前节点
..	选取当前节点的父节点
@	选取属性
*	通配符,选择所有元素节点与元素名
@*	选取所有属性
[@attrib]	选取具有给定属性的所有元素
[@attrib='value']	选取给定属性具有给定值的所有元素
[tag]	选取所有具有指定元素的直接子节点
[tag='text']	选取所有具有指定元素并且文本内容是text节点
读取 文本 解析节点 ( etree 会修复 HTML 文本节点 )

#!/usr/bin/python3
# -*- coding: utf-8 -*-
# @Author      : 
# @File        : test.py
# @Software    : PyCharm
# @description : XXX
 
 
from lxml import etree
 
text = '''
<div>
    <ul>
         <li class="item-0"><a href="link1.html">第一个</a></li>
         <li class="item-1"><a href="link2.html">second item</a></li>
         <li class="item-0"><a href="link5.html">a属性</a>
     </ul>
 </div>
'''
 
html = etree.HTML(text)  # 初始化生成一个XPath解析对象
result = etree.tostring(html, encoding='utf-8')  # 解析对象输出代码
print(type(html))
print(type(result))
print(result.decode('utf-8'))
 
 
'''
执行结果:
<class 'lxml.etree._Element'>
<class 'bytes'>
<html><body><div>
    <ul>
         <li class="item-0"><a href="link1.html">第一个</a></li>
         <li class="item-1"><a href="link2.html">second item</a></li>
         <li class="item-0"><a href="link5.html">a属性</a>
     </li></ul>
 </div>
</body></html>
'''

读取 HTML文件 进行解析

from lxml import etree
 
html = etree.parse('test.html', etree.HTMLParser())  # 指定解析器HTMLParser会根据文件修复HTML文件中缺失的如声明信息
result = etree.tostring(html)  # 解析成字节
# result=etree.tostringlist(html) #解析成列表
print(type(html))
print(type(result))
print(result)
节点关系
(1)父(Parent)
每个元素以及属性都有一个父。在下面的例子中,book 元素是 title、author、year 以及 price 元素的父:

<book>
  <title>Harry Potter</title>
  <author>J K. Rowling</author>
  <year>2005</year>
  <price>29.99</price>
</book>
(2)子(Children)
元素节点可有零个、一个或多个子。在下面的例子中,title、author、year 以及 price 元素都是 book 元素的子:

<book>
  <title>Harry Potter</title>
  <author>J K. Rowling</author>
  <year>2005</year>
  <price>29.99</price>
</book>
(3)同胞(Sibling)
拥有相同的父的节点。在下面的例子中,title、author、year 以及 price 元素都是同胞:

<book>
  <title>Harry Potter</title>
  <author>J K. Rowling</author>
  <year>2005</year>
  <price>29.99</price>
</book>
(4)先辈(Ancestor)
某节点的父、父的父,等等。在下面的例子中,title 元素的先辈是 book 元素和 bookstore 元素:

<bookstore>
 
<book>
  <title>Harry Potter</title>
  <author>J K. Rowling</author>
  <year>2005</year>
  <price>29.99</price>
</book>
 
</bookstore>
(5)后代(Descendant)
某个节点的子,子的子,等等。在下面的例子中,bookstore 的后代是 book、title、author、year 以及 price 元素:

<bookstore>
 
<book>
  <title>Harry Potter</title>
  <author>J K. Rowling</author>
  <year>2005</year>
  <price>29.99</price>
</book>
 
</bookstore>
选取节点
XPath 使用路径表达式在 XML 文档中选取节点。节点是通过沿着路径或者 step 来选取的。

下面列出了最有用的路径表达式:
表达式	描述
nodename	选取此节点的所有子节点
/	从当前节点选取直接子节点
//	从当前节点选取子孙节点
.	选取当前节点
..	选取当前节点的父节点
@	选取属性
*	通配符,选择所有元素节点与元素名
@*	选取所有属性
[@attrib]	选取具有给定属性的所有元素
[@attrib='value']	选取给定属性具有给定值的所有元素
[tag]	选取所有具有指定元素的直接子节点
[tag='text']	选取所有具有指定元素并且文本内容是text节点
实例

在下面的表格中,我们已列出了一些路径表达式以及表达式的结果:

路径表达式	结果
bookstore	选取 bookstore 元素的所有子节点。
/bookstore	选取根元素 bookstore。注释:假如路径起始于正斜杠( / ),则此路径始终代表到某元素的绝对路径!
bookstore/book	选取属于 bookstore 的子元素的所有 book 元素。
//book	选取所有 book 子元素,而不管它们在文档中的位置。
bookstore//book	选择属于 bookstore 元素的后代的所有 book 元素,而不管它们位于 bookstore 之下的什么位置。
//@lang	选取名为 lang 的所有属性。
谓语(Predicates)
谓语用来查找某个特定的节点或者包含某个指定的值的节点。谓语被嵌在方括号中。

实例

在下面的表格中,我们列出了带有谓语的一些路径表达式,以及表达式的结果:

路径表达式	结果
/bookstore/book[1]	选取属于 bookstore 子元素的第一个 book 元素。
/bookstore/book[last()]	选取属于 bookstore 子元素的最后一个 book 元素。
/bookstore/book[last()-1]	选取属于 bookstore 子元素的倒数第二个 book 元素。
/bookstore/book[position()<3]	选取最前面的两个属于 bookstore 元素的子元素的 book 元素。
//title[@lang]	选取所有拥有名为 lang 的属性的 title 元素。
//title[@lang=’eng’]	选取所有 title 元素,且这些元素拥有值为 eng 的 lang 属性。
/bookstore/book[price>35.00]	选取 bookstore 元素的所有 book 元素,且其中的 price 元素的值须大于 35.00。
/bookstore/book[price>35.00]/title	选取 bookstore 元素中的 book 元素的所有 title 元素,且其中的 price 元素的值须大于 35.00。
选取未知节点
XPath 通配符可用来选取未知的 XML 元素。

通配符	描述
*	匹配任何元素节点。
@*	匹配任何属性节点。
node()	匹配任何类型的节点。
实例

在下面的表格中,我们列出了一些路径表达式,以及这些表达式的结果:

路径表达式	结果
/bookstore/*	选取 bookstore 元素的所有子元素。
//*	选取文档中的所有元素。
//title[@*]	选取所有带有属性的 title 元素。
选取若干路径
通过在路径表达式中使用“|”运算符,您可以选取若干个路径。

实例

在下面的表格中,我们列出了一些路径表达式,以及这些表达式的结果:

路径表达式	结果
//book/title | //book/price	选取 book 元素的所有 title 和 price 元素。
//title | //price	选取文档中的所有 title 和 price 元素。
/bookstore/book/title | //price	选取属于 bookstore 元素的 book 元素的所有 title 元素,以及文档中所有的 price 元素。
XPath 运算符
下面列出了可用在 XPath 表达式中的运算符:( 此表参考来源:http://www.w3school.com.cn/xpath/xpath_operators.asp)

运算符	描述	实例	返回值
|	计算两个节点集	//book | //cd	返回所有拥有 book 和 cd 元素的节点集
+	加法	6 + 4	10
–	减法	6 – 4	2
*	乘法	6 * 4	24
div	除法	8 div 4	2
=	等于	price=9.80	如果 price 是 9.80,则返回 true。如果 price 是 9.90,则返回 false。
!=	不等于	price!=9.80	如果 price 是 9.90,则返回 true。如果 price 是 9.80,则返回 false。
<	小于	price<9.80	如果 price 是 9.00,则返回 true。如果 price 是 9.90,则返回 false。
<=	小于或等于	price<=9.80	如果 price 是 9.00,则返回 true。如果 price 是 9.90,则返回 false。
>	大于	price>9.80	如果 price 是 9.90,则返回 true。如果 price 是 9.80,则返回 false。
>=	大于或等于	price>=9.80	如果 price 是 9.90,则返回 true。如果 price 是 9.70,则返回 false。
or	或	price=9.80 or price=9.70	如果 price 是 9.80,则返回 true。如果 price 是 9.50,则返回 false。
and	与	price>9.00 and price<9.90	如果 price 是 9.80,则返回 true。如果 price 是 8.50,则返回 false。
mod	计算除法的余数	5 mod 2	1
XPath 函数的高级使用示例:
1.使用 contains() 和 and
    //div[starts-with(@id,'res')]//table[1]//tr//td[2]//a//span[contains(.,'_Test') and contains(.,'KPI')] 
    //div[contains(@id,'in')] ,表示选择id中包含有’in’的div节点
2.text():
    由于一个节点的文本值不属于属性,比如“<a class=”baidu“ href=”http://www.baidu.com“>baidu</a>”,
    所以,用text()函数来匹配节点://a[text()='baidu']
    //span[@id='idHeaderTitleCell' and contains(text(),'QuickStart')]
3.last():
    前面已介绍
4. 使用starts-with()
    //div[starts-with(@id,'in')] ,表示选择以’in’开头的id属性的div节点
    //div[starts-with(@id,'res')]//table//tr//td[2]//table//tr//td//a//span[contains(.,'Developer Tutorial')]
5.not()函数,表示否定。not()函数通常与返回值为true or false的函数组合起来用,
    比如contains(),starts-with()等,但有一种特别情况请注意一下:
    我们要匹配出input节点含有id属性的,写法为://input[@id],
    如果我们要匹配出input节点不含用id属性的,则为://input[not(@id)]
    //input[@name=‘identity’ and not(contains(@class,‘a’))] ,表示匹配出name为identity并且class的值中不包含a的input节点。
6.使用descendant
    //div[starts-with(@id,'res')]//table[1]//tr//td[2]//a//span[contains(.,'QuickStart')]/../../../descendant::img
7.使用ancestor
//div[starts-with(@id,'res')]//table[1]//tr//td[2]//a//span[contains(.,'QuickStart')]/ancestor::div[starts-with(@id,'res')]//table[2]//descendant::a[2]

示例代码:

# -*- coding: utf-8 -*-
# @Author  :
# @File    : douban_api.py
# @Software: PyCharm
# @description : XXX
 
 
import re
import json
import datetime
import requests
from lxml import etree
import urllib3
 
 
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
 
 
class DBSpider(object):
 
    def __init__(self):
        self.custom_headers = {
            'Host': 'movie.douban.com',
            'Connection': 'keep-alive',
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 '
                          '(KHTML, like Gecko) Chrome/80.0.3987.87 Safari/537.36',
            'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,'
                      'image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
        },
 
        # self.proxies = {
        #     'http': '127.0.0.1:8080',
        #     'https': '127.0.0.1:8080'
        # }
 
        self.s = requests.session()
        self.s.verify = False
        self.s.headers = self.custom_headers
        # self.s.proxies = self.proxies
 
    def __del__(self):
        pass
 
    def api_artists_info(self, artists_id=None):
        ret_val = None
        if artists_id:
            url = f'https://movie.douban.com/celebrity/{artists_id}/'
            try:
                r = self.s.get(url)
                if 200 == r.status_code:
                    response = etree.HTML(r.text)
 
                    artists_name = response.xpath('//h1/text()')
                    artists_name = artists_name[0] if len(artists_name) else ''
 
                    chinese_name = re.findall(r'([\u4e00-\u9fa5·]+)', artists_name)
                    chinese_name = chinese_name[0] if len(chinese_name) else ''
 
                    english_name = artists_name.replace(chinese_name, '').strip()
 
                    pic = response.xpath('//div[@id="headline"]//div[@class="pic"]//img/@src')
                    pic = pic[0] if len(pic) else ''
 
                    sex = response.xpath('//div[@class="info"]//span[contains(text(), "性别")]/../text()')
                    sex = ''.join(sex).replace('\n', '').replace(':', '').strip() if len(sex) else ''
 
                    constellation = response.xpath('//div[@class="info"]//span[contains(text(), "星座")]/../text()')
                    constellation = ''.join(constellation).replace('\n', '').replace(':', '').strip() if len(constellation) else ''
 
                    birthday = response.xpath('//div[@class="info"]//span[contains(text(), "日期")]/../text()')
                    birthday = ''.join(birthday).replace('\n', '').replace(':', '').strip() if len(birthday) else ''
 
                    place = response.xpath('//div[@class="info"]//span[contains(text(), "出生地")]/../text()')
                    place = ''.join(place).replace('\n', '').replace(':', '').strip() if len(place) else ''
 
                    occupation = response.xpath('//div[@class="info"]//span[contains(text(), "职业")]/../text()')
                    occupation = ''.join(occupation).replace('\n', '').replace(':', '').strip() if len(occupation) else ''
 
                    desc = ''.join([x for x in response.xpath('//span[@class="all hidden"]/text()')])
 
                    artists_info = dict(
                        artistsId=artists_id,
                        homePage=f'https://movie.douban.com/celebrity/{artists_id}',
                        sex=sex,
                        constellation=constellation,
                        chineseName=chinese_name,
                        foreignName=english_name,
                        posterAddre=pic,
                        # posterAddreOSS=Images.imgages_data(pic, 'movie/douban'),
                        birthDate=birthday,
                        birthAddre=place,
                        desc=desc,
                        occupation=occupation,
                        showCount='',
                        fetchTime=str(datetime.datetime.now()),
                    )
                    # print(json.dumps(artists_info, ensure_ascii=False, indent=4))
                    ret_val = artists_info
                else:
                    print(f'status code : {r.status_code}')
            except BaseException as e:
                print(e)
        return ret_val
 
    def test(self):
        pass
 
 
if __name__ == '__main__':
    douban = DBSpider()
    # temp_uid = '1044707'
    # temp_uid = '1386515'
    # temp_uid = '1052358'
    temp_uid = '1052357'
    user_info = douban.api_artists_info(temp_uid)
    print(json.dumps(user_info, ensure_ascii=False, indent=4))
    pass

Xpath 高级用法
scrapy实战2,使用内置的xpath,re 和 css 提取值:https://www.cnblogs.com/regit/p/9629263.html

span 标签 class 属性包含  selectable 字符串://span[contains(@class, 'selectable')]

匹配猫眼 座位数//div[@class='seats-wrapper']/div/span[contains(@class,'seat') and not(contains(@class,'empty'))]
    等价于//div[@class='seats-wrapper']/div//span[not(contains(//span[contains(@class, 'seat')]/@class, 'empty'))]

./@data-val
//div[contains(@class, "show-list") and @data-index="{0}"]
.//div[@class="show-date"]//span[contains(@class, "date-item")]/text()
.//div[contains(@class, "plist-container")][1]//tbody//tr     xpath 中下标是从 1 开始的
substring-before(substring-after(//script[contains(text(), '/apps/feedlist')]/text(), 'html":"'), '"})')
//div[text()="hello"]/p/text()
//a[@class="movie-name"][1]/text()
string(//a[@class="movie-name"][1])

1. 获取父节点属性
    首先选中 href 属性为 link4.html的a节点,然后再获取其父节点,然后再获取其class属性result1 = response.xpath('//a[@href="link4.html"]/../@class')
    我们也可以通过parent::来获取父节点result2 = response.xpath('//a[@href="link4.html"]/parent::*/@class')
    注意: //a表示html中的所有a节点,他们的href属性有多个,这里[]的作用是属性匹配,找到a的href属性为link4.html的节点
2. 获取节点内部文本
    获取class为item-1的li节点文本, result3 = response.xpath('//li[@class="item-0"]/a/text()')
    返回结果为:['first item', 'fifth item']
3. 属性获取
    获取所有li节点下的所有a节点的href属性result4 = response.xpath('//li/a/@href')
    返回结果为:['link1.html', 'link2.html', 'link3.html', 'link4.html', 'link5.html']
4. 按序选择result = response.xpath('//li[1]/a/text()')   #选取第一个li节点 result = response.xpath('//li[last()]/a/text()')   #选取最后一个li节点 result = response.xpath('//li[position()<3]/a/text()')   #选取位置小于3的li节点,也就是1和2的节点 result = response.xpath('//li[last()-2]/a/text()')  #选取倒数第三个节点 
5. 节点轴选择
    1)返回第一个li节点的所有祖先节点,包括html,body,div和ul
                result = response.xpath('//li[1]/ancestor::*')     
    2)返回第一个li节点的<div>祖先节点
                result = response.xpath('//li[1]/ancestor::div')     
    3)返回第一个li节点的所有属性值
                result = response.xpath('//li[1]/attribute::*')     
    4)首先返回第一个li节点的所有子节点,然后加上限定条件,选组href属性为link1.html的a节点
                result = response.xpath('//li[1]/child::a[@href="link1.html"]')     
    5)返回第一个li节点的所有子孙节点,然后加上只要span节点的条件
                result = response.xpath('//li[1]/descendant::span')     
    6)following轴可获得当前节点之后的所有节点,虽然使用了*匹配,但是又加了索引选择,所以只获取第2个后续节点,也就是第2个<li>节点中的<a>节点
                result = response.xpath('//li[1]/following::*[2]')     
    7)following-sibling可获取当前节点之后的所有同级节点,也就是后面所有的<li>节点
                result = response.xpath('//li[1]/following-sibling::*') 
6. 属性多值匹配
                <li class="li li-first"><a href="link.html">first item</a></li>     
                result5 = response.xpath('//li[@class="li"]/a/text()')
    返回值为空,因为这里HTML文本中li节点为class属性有2个值li和li-first,如果还用之前的属性匹配就不行了,需要用contain()函数     
    正确方法如下
                result5 = response.xpath('//li[contains(@class, "li")]/a/text()')
    contains()方法中,第一个参数为属性名,第二个参数传入属性值,只要此属性名包含所传入的属性值就可完成匹配 
 7. 多属性匹配,这里说一下不用框架的时候,xpath的常规用法
    有时候我们需要多个属性来确定一个节点,那么就需要同时匹配多个属性,可用and来连接    
    from lxml import etree
    text = '''
    <li class = "li li-first" name="item"><a href="link.html">first item</a></li>
    '''
    html = etree.HTML(text)
    result6 = html.xpath('//li[contains(@class, "li") and @name="item"]/a/text()')
    print(result)    
    这里的li节点有class和name两个属性,需要用and操作符相连,然后置于中括号内进行条件筛选

xpath 学习笔记

1.依靠自己的属性,文本定位
   //td[text()='Data Import']
   //div[contains(@class,'cux-rightArrowIcon-on')]
   //a[text()='马上注册']
   //input[@type='radio' and @value='1']     多条件
   //span[@name='bruce'][text()='bruce1'][1]   多条件
   //span[@id='bruce1' or text()='bruce2']  找出多个
   //span[text()='bruce1' and text()='bruce2']  找出多个
2.依靠父节点定位
  //div[@class='x-grid-col-name x-grid-cell-inner']/div
  //div[@id='dynamicGridTestInstanceformclearuxformdiv']/div
  //div[@id='test']/input
3.依靠子节点定位
  //div[div[@id='navigation']]
  //div[div[@name='listType']]
  //div[p[@name='testname']]
4.混合型
  //div[div[@name='listType']]//img
  //td[a//font[contains(text(),'seleleium2从零开始 视屏')]]//input[@type='checkbox']
5.进阶部分
   //input[@id='123']/following-sibling::input   找下一个兄弟节点
   //input[@id='123']/preceding-sibling::span    上一个兄弟节点
   //input[starts-with(@id,'123')]               以什么开头
   //span[not(contains(text(),'xpath'))]        不包含xpath字段的span
6.索引
  //div/input[2]
  //div[@id='position']/span[3]
  //div[@id='position']/span[position()=3]
  //div[@id='position']/span[position()>3]
  //div[@id='position']/span[position()<3]
  //div[@id='position']/span[last()]
  //div[@id='position']/span[last()-1]
7.substring 截取判断
  <div data-for="result" id="swfEveryCookieWrap"></div>
  //*[substring(@id,4,5)='Every']/@id  截取该属性 定位3,取长度5的字符 
  //*[substring(@id,4)='EveryCookieWrap']  截取该属性从定位3 到最后的字符 
  //*[substring-before(@id,'C')='swfEvery']/@id   属性 'C'之前的字符匹配
  //*[substring-after(@id,'C')='ookieWrap']/@id   属性'C之后的字符匹配
8.通配符*
  //span[@*='bruce']
  //*[@name='bruce']
9.轴
  //div[span[text()='+++current node']]/parent::div    找父节点
  //div[span[text()='+++current node']]/ancestor::div    找祖先节点
10.孙子节点
  //div[span[text()='current note']]/descendant::div/span[text()='123']
  //div[span[text()='current note']]//div/span[text()='123']          两个表达的意思一样
11.following pre
https://www.baidu.com/s?wd=xpath
  //span[@class="fk fk_cur"]/../following::a       往下的所有a
  //span[@class="fk fk_cur"]/../preceding::a[1]    往上的所有a
  
xpath提取多个标签下的text
在写爬虫的时候,经常会使用xpath进行数据的提取,对于如下的代码:
<div id="test1">大家好!</div>
使用xpath提取是非常方便的。假设网页的源代码在selector中:
data = selector.xpath('//div[@id="test1"]/text()').extract()[0]
就可以把“大家好!”提取到data变量中去。
然而如果遇到下面这段代码呢?
<div id="test2">美女,<font color=red>你的微信是多少?</font><div>
如果使用:
data = selector.xpath('//div[@id="test2"]/text()').extract()[0]
只能提取到“美女,”;
如果使用:
data = selector.xpath('//div[@id="test2"]/font/text()').extract()[0]
又只能提取到“你的微信是多少?”
可是我本意是想把“美女,你的微信是多少?”这一整个句子提取出来。
<div id="test3">我左青龙,<span id="tiger">右白虎,
<ul>上朱雀,<li>下玄武。</li></ul>老牛在当中,</span>龙头在胸口。
<div>
而且内部的标签还不固定,如果我有一百段这样类似的html代码,
又如何使用xpath表达式,以最快最方便的方式提取出来?
使用xpath的string(.)
以第三段代码为例:
data = selector.xpath('//div[@id="test3"]')
info = data.xpath('string(.)').extract()[0]
这样,就可以把“我左青龙,右白虎,上朱雀,下玄武。老牛在当中,龙头在胸口”整个句子提取出来,
赋值给info变量。

示例 XML 文档

<?xml version="1.0" encoding="utf8"?>
<bookstore>
  <book>
    <title lang="eng">Harry Potter</title>
    <price>29.99</price>
  </book>
  <book>
    <title lang="eng">Learning XML</title>
    <price>39.95</price>
  </book>
</bookstore>
选取节点

以下为基本路径的表达方式,记住 XPath 的路径表达式都是基于某个节点之上的,例如最初的当前节点一般是根节点,这与 Linux 下路径切换原理是一样的。

表达式	描述
nodename	选取已匹配节点下名为 nodename 的子元素节点。
/	如果以 / 开头,表示从根节点作为选取起点。
//	在已匹配节点后代中选取节点,不考虑目标节点的位置。
.	选取当前节点。
..	选取当前节点的父元素节点。
@	选取属性。
>>> from lxml import etree
>>> xml = """<?xml version="1.0" encoding="utf8"?>
<bookstore>
  <book>
    <title lang="eng">Harry Potter</title>
    <price>29.99</price>
  </book>
  <book>
    <title lang="eng">Learning XML</title>
    <price>39.95</price>
  </book>
</bookstore>"""
 
 
# 得到根节点
>>> root = etree.fromstring(xml)  
>>> print root
<Element bookstore at 0x2c9cc88>
 
# 选取所有book子元素
>>> root.xpath('book')  
[<Element book at 0x2d88878>, <Element book at 0x2d888c8>]
 
# 选取根节点bookstore
>>> root.xpath('/bookstore')  
[<Element bookstore at 0x2c9cc88>]
 
# 选取所有book子元素的title子元素
>>> root.xpath('book/title')  
[<Element title at 0x2d88878>, <Element title at 0x2d888c8>]
 
# 以根节点为始祖,选取其后代中的title元素
>>> root.xpath('//title')    
[<Element title at 0x2d88878>, <Element title at 0x2d888c8>]
 
# 以book子元素为始祖,选取后代中的price元素
>>> root.xpath('book//price')  
[<Element price at 0x2ca20a8>, <Element price at 0x2d88738>]
 
# 以根节点为始祖,选取其后代中的lang属性值
>>> root.xpath('//@lang')    
['eng', 'eng']

预判(Predicates)

预判是用来查找某个特定的节点或者符合某种条件的节点,预判表达式位于方括号中。

# 选取bookstore的第一个book子元素
 
>>> root.xpath('/bookstore/book[1]')          
 
[<Element book at 0x2ca20a8>]
 
 
# 选取bookstore的最后一个book子元素
 
>>> root.xpath('/bookstore/book[last()]')        
 
[<Element book at 0x2d88878>]
 
 
# 选取bookstore的倒数第二个book子元素
 
>>> root.xpath('/bookstore/book[last()-1]')      
 
[<Element book at 0x2ca20a8>]
 
 
# 选取bookstore的前两个book子元素
 
>>> root.xpath('/bookstore/book[position()<3]')    
 
[<Element book at 0x2ca20a8>, <Element book at 0x2d88878>]
 
 
# 以根节点为始祖,选取其后代中含有lang属性的title元素
 
>>> root.xpath('//title[@lang]')     
 
[<Element title at 0x2d888c8>, <Element title at 0x2d88738>]
 
 
# 以根节点为始祖,选取其后代中含有lang属性并且值为eng的title元素
 
>>> root.xpath("//title[@lang='eng']")
 
[<Element title at 0x2d888c8>, <Element title at 0x2d88738>]
 
 
# 选取bookstore子元素book,条件是book的price子元素要大于35
 
>>> root.xpath("/bookstore/book[price>35.00]")
 
[<Element book at 0x2ca20a8>]
 
 
# 选取bookstore子元素book的子元素title,条件是book的price子元素要大于35
 
>>> root.xpath("/bookstore/book[price>35.00]/title")
 
[<Element title at 0x2d888c8>]

通配符

通配符	描述
*	匹配任何元素。
@*	匹配任何属性。
node()	匹配任何类型的节点。

# 选取 bookstore 所有子元素
 
>>> root.xpath('/bookstore/*')
 
[<Element book at 0x2d888c8>, <Element book at 0x2ca20a8>]
 
 
# 选取根节点的所有后代元素
 
>>> root.xpath('//*')  
 
[<Element bookstore at 0x2c9cc88>, <Element book at 0x2d888c8>, <Element title at 0x2d88738>, <Element price at 0x2d88878>, <Element book at 0x2ca20a8>, <Element title at 0x2d88940>, <Element price at 0x2d88a08>]
 
 
# 选取根节点的所有具有属性节点的title元素
 
>>> root.xpath('//title[@*]')  
 
[<Element title at 0x2d88738>, <Element title at 0x2d88940>]
 
 
# 选取当前节点下所有节点。'\n ' 是文本节点。
 
>>> root.xpath('node()')
 
['\n ', <Element book at 0x2d888c8>, '\n ', <Element book at 0x2d88878>, '\n']
 
 
# 选取根节点所有后代节点,包括元素、属性、文本。
 
>>> root.xpath('//node()')
 
[<Element bookstore at 0x2c9cc88>, '\n ', <Element book at 0x2d888c8>, '\n ', <Element title at 0x2d88738>, 'Harry Potter', '\n ', <Element price at 0x2d88940>, '29.99', '\n ', '\n ', <Element book at 0x2d88878>, '\n ', <Element title at 0x2ca20a8>, 'Learning XML', '\n ', <Element price at 0x2d88a08>, '39.95', '\n ', '\n']

或条件选取

使用 "|" 运算符,你可以选取符合“或”条件的若干路径。

# 选取所有book的title元素或者price元素
 
>>> root.xpath('//book/title|//book/price')  
 
[<Element title at 0x2d88738>, <Element price at 0x2d88940>, <Element title at 0x2ca20a8>, <Element price at 0x2d88a08>]
 
 
# 选择所有title或者price元素
 
>>> root.xpath('//title|//price')  
 
[<Element title at 0x2d88738>, <Element price at 0x2d88940>, <Element title at 0x2ca20a8>, <Element price at 0x2d88a08>]
 
 
# 选择book子元素title或者全部的price元素
 
>>> root.xpath('/bookstore/book/title|//price')
 
[<Element title at 0x2d88738>, <Element price at 0x2d88940>, <Element title at 0x2ca20a8>, <Element price at 0x2d88a08>]

lxml 用法
首先我们利用它来解析 HTML 代码,先来一个小例子来感受一下它的基本用法。

from lxml import etree
text = '''
<div>
    <ul>
         <li class="item-0"><a href="link1.html">first item</a></li>
         <li class="item-1"><a href="link2.html">second item</a></li>
         <li class="item-inactive"><a href="link3.html">third item</a></li>
         <li class="item-1"><a href="link4.html">fourth item</a></li>
         <li class="item-0"><a href="link5.html">fifth item</a>
     </ul>
 </div>
'''
html = etree.HTML(text)
result = etree.tostring(html)
print(result)

首先我们使用 lxml 的 etree 库,然后利用 etree.HTML 初始化,然后我们将其打印出来。

其中,这里体现了 lxml 的一个非常实用的功能就是自动修正 html 代码,大家应该注意到了,最后一个 li 标签,其实我把尾标签删掉了,是不闭合的。不过,lxml 因为继承了 libxml2 的特性,具有自动修正 HTML 代码的功能。

所以输出结果是这样的

<html><body>
<div>
    <ul>
         <li class="item-0"><a href="link1.html">first item</a></li>
         <li class="item-1"><a href="link2.html">second item</a></li>
         <li class="item-inactive"><a href="link3.html">third item</a></li>
         <li class="item-1"><a href="link4.html">fourth item</a></li>
         <li class="item-0"><a href="link5.html">fifth item</a></li>
</ul>
 </div>
 
</body></html>
不仅补全了 li 标签,还添加了 body,html 标签。

文件读取
除了直接读取字符串,还支持从文件读取内容。比如我们新建一个文件叫做 hello.html,内容为

<div>
    <ul>
         <li class="item-0"><a href="link1.html">first item</a></li>
         <li class="item-1"><a href="link2.html">second item</a></li>
         <li class="item-inactive"><a href="link3.html"><span class="bold">third item</span></a></li>
         <li class="item-1"><a href="link4.html">fourth item</a></li>
         <li class="item-0"><a href="link5.html">fifth item</a></li>
     </ul>
 </div>
利用 parse 方法来读取文件。

from lxml import etree
html = etree.parse('hello.html')
result = etree.tostring(html, pretty_print=True)
print(result)
同样可以得到相同的结果。

XPath 实例测试
python3解析库 lxml :http://www.cnblogs.com/zhangxinqi/p/9210211.html

依然以上一段程序为例

(1)获取 所有 的 <li> 标签

from lxml import etree
html = etree.parse('hello.html')
print type(html)
result = html.xpath('//li')
print result
print len(result)
print type(result)
print type(result[0])
运行结果

<type 'lxml.etree._ElementTree'>
[<Element li at 0x1014e0e18>, <Element li at 0x1014e0ef0>, <Element li at 0x1014e0f38>, <Element li at 0x1014e0f80>, <Element li at 0x1014e0fc8>]
5
<type 'list'>
<type 'lxml.etree._Element'>
可见,etree.parse 的类型是 ElementTree,
通过调用 xpath 以后,得到了一个列表,包含了 5 个 <li> 元素,每个元素都是 Element 类型。
获取所有节点。返回一个列表每个元素都是Element类型,所有节点都包含在其中

from lxml import etree
 
html = etree.parse('hello.html', etree.HTMLParser())
result = html.xpath('//*')  # //代表获取子孙节点,*代表获取所有
 
print(type(html))
print(type(result))
print(result)
 
# 如要获取li节点,可以使用//后面加上节点名称,然后调用xpath()方法
html.xpath('//li')   # 获取所有子孙节点的li节点
(2)获取 子节点

通过 / 或者 // 即可查找元素的 子节点 或者 子孙节点,如果想选择li节点的所有直接a节点,可以这样使用

# 通过追加/a选择所有li节点的所有直接a节点,因为//li用于选中所有li节点,/a用于选中li节点的所有直接子节点a
result=html.xpath('//li/a')
(3)获取 父节点

通过 / 或者 // 可以查找 子节点 或 子孙节点,那么要查找父节点可以使用 .. 来实现也可以使用 parent:: 来获取父节点

from lxml import etree
from lxml.etree import HTMLParser
text='''
<div>
    <ul>
         <li class="item-0"><a href="link1.html">第一个</a></li>
         <li class="item-1"><a href="link2.html">second item</a></li>
     </ul>
 </div>
'''
 
html=etree.HTML(text,etree.HTMLParser())
result=html.xpath('//a[@href="link2.html"]/../@class')
result1=html.xpath('//a[@href="link2.html"]/parent::*/@class')
print(result)
print(result1)
 
 
'''
['item-1']
['item-1']
'''

(4)属性 匹配

在选取的时候,我们还可以用 @符号 进行属性过滤。比如,这里如果要选取 class 为 link1.html 的 li 节点,可以这样实现:

from lxml import etree
from lxml.etree import HTMLParser
text='''
<div>
    <ul>
         <li class="item-0"><a href="link1.html">第一个</a></li>
         <li class="item-1"><a href="link2.html">second item</a></li>
     </ul>
 </div>
'''
 
html=etree.HTML(text, etree.HTMLParser())
result=html.xpath('//li[@class="link1.html"]')
print(result)
 
# 获取 <li> 标签的所有 class
result = html.xpath('//li/@class')
print(result)

(5)文本 获取

我们用XPath中的 text() 方法获取节点中的文本

from lxml import etree
 
text='''
<div>
    <ul>
         <li class="item-0"><a href="link1.html">第一个</a></li>
         <li class="item-1"><a href="link2.html">second item</a></li>
     </ul>
 </div>
'''
 
html=etree.HTML(text,etree.HTMLParser())
result=html.xpath('//li[@class="item-1"]/a/text()') #获取a节点下的内容
result1=html.xpath('//li[@class="item-1"]//text()') #获取li下所有子孙节点的内容
 
print(result)
print(result1)

(6)属性 获取

使用 @符号即可获取节点的属性,如下:获取所有li节点下所有a节点的href属性

result=html.xpath('//li/a/@href')  #获取a的href属性
result=html.xpath('//li//@href')   #获取所有li子孙节点的href属性
(7)属性 多值 匹配

如果某个属性的值有多个时,我们可以使用 contains() 函数来获取

from lxml import etree
 
text1='''
<div>
    <ul>
         <li class="aaa item-0"><a href="link1.html">第一个</a></li>
         <li class="bbb item-1"><a href="link2.html">second item</a></li>
     </ul>
 </div>
'''
 
html=etree.HTML(text1,etree.HTMLParser())
result=html.xpath('//li[@class="aaa"]/a/text()')
result1=html.xpath('//li[contains(@class,"aaa")]/a/text()')
 
print(result)
print(result1)
 
#通过第一种方法没有取到值,通过contains()就能精确匹配到节点了
[]
['第一个']

(8)多 属性 匹配

另外我们还可能遇到一种情况,那就是根据多个属性确定一个节点,这时就需要同时匹配多个属性,此时可用运用and运算符来连接使用:

from lxml import etree
 
text1='''
<div>
    <ul>
         <li class="aaa" name="item"><a href="link1.html">第一个</a></li>
         <li class="aaa" name="fore"><a href="link2.html">second item</a></li>
     </ul>
 </div>
'''
 
html=etree.HTML(text1,etree.HTMLParser())
result=html.xpath('//li[@class="aaa" and @name="fore"]/a/text()')
result1=html.xpath('//li[contains(@class,"aaa") and @name="fore"]/a/text()')
 
 
print(result)
print(result1)
 
 
#
['second item']
['second item']

(9)按序 选择

有时候,我们在选择的时候某些属性可能同时匹配多个节点,但我们只想要其中的某个节点,如第二个节点或者最后一个节点,这时可以利用中括号引入索引的方法获取特定次序的节点:

from lxml import etree
 
text1='''
<div>
    <ul>
         <li class="aaa" name="item"><a href="link1.html">第一个</a></li>
         <li class="aaa" name="item"><a href="link1.html">第二个</a></li>
         <li class="aaa" name="item"><a href="link1.html">第三个</a></li>
         <li class="aaa" name="item"><a href="link1.html">第四个</a></li> 
     </ul>
 </div>
'''
 
html=etree.HTML(text1,etree.HTMLParser())
 
result=html.xpath('//li[contains(@class,"aaa")]/a/text()') #获取所有li节点下a节点的内容
result1=html.xpath('//li[1][contains(@class,"aaa")]/a/text()') #获取第一个
result2=html.xpath('//li[last()][contains(@class,"aaa")]/a/text()') #获取最后一个
result3=html.xpath('//li[position()>2 and position()<4][contains(@class,"aaa")]/a/text()') #获取第一个
result4=html.xpath('//li[last()-2][contains(@class,"aaa")]/a/text()') #获取倒数第三个
 
 
print(result)
print(result1)
print(result2)
print(result3)
print(result4)
 
 
#
['第一个', '第二个', '第三个', '第四个']
['第一个']
['第四个']
['第三个']
['第二个']

这里使用了last()、position()函数,在XPath中,提供了100多个函数,包括存取、数值、字符串、逻辑、节点、序列等处理功能,它们的具体作用可参考:http://www.w3school.com.cn/xpath/xpath_functions.asp

(10)节点轴 选择

XPath提供了很多节点选择方法,包括获取子元素、兄弟元素、父元素、祖先元素等,示例如下:

from lxml import etree
 
text1='''
<div>
    <ul>
         <li class="aaa" name="item"><a href="link1.html">第一个</a></li>
         <li class="aaa" name="item"><a href="link1.html">第二个</a></li>
         <li class="aaa" name="item"><a href="link1.html">第三个</a></li>
         <li class="aaa" name="item"><a href="link1.html">第四个</a></li> 
     </ul>
 </div>
'''
 
html=etree.HTML(text1,etree.HTMLParser())
result=html.xpath('//li[1]/ancestor::*')  #获取所有祖先节点
result1=html.xpath('//li[1]/ancestor::div')  #获取div祖先节点
result2=html.xpath('//li[1]/attribute::*')  #获取所有属性值
result3=html.xpath('//li[1]/child::*')  #获取所有直接子节点
result4=html.xpath('//li[1]/descendant::a')  #获取所有子孙节点的a节点
result5=html.xpath('//li[1]/following::*')  #获取当前子节之后的所有节点
result6=html.xpath('//li[1]/following-sibling::*')  #获取当前节点的所有同级节点
 
 
#
[<Element html at 0x3ca6b960c8>, <Element body at 0x3ca6b96088>, <Element div at 0x3ca6b96188>, <Element ul at 0x3ca6b961c8>]
[<Element div at 0x3ca6b96188>]
['aaa', 'item']
[<Element a at 0x3ca6b96248>]
[<Element a at 0x3ca6b96248>]
[<Element li at 0x3ca6b96308>, <Element a at 0x3ca6b96348>, <Element li at 0x3ca6b96388>, <Element a at 0x3ca6b963c8>, <Element li at 0x3ca6b96408>, <Element a at 0x3ca6b96488>]
[<Element li at 0x3ca6b96308>, <Element li at 0x3ca6b96388>, <Element li at 0x3ca6b96408>]

# 获取 <li> 标签下 href 为 link1.html 的 <a> 标签
result = html.xpath('//li/a[@href="link1.html"]')
print result

# 获取 <li> 标签下的所有 <span> 标签 (应为是所有,所以使用 // )
result = html.xpath('//li//span')

# 获取 <li> 标签下的所有 class,不包括 <li>
result = html.xpath('//li/a//@class')
print result

# 获取最后一个 <li> 的 <a> 的 href
result = html.xpath('//li[last()]/a/@href')
print result

# 获取倒数第二个元素的内容
result = html.xpath('//li[last()-1]/a')
print result[0].text

# 获取 class 为 bold 的标签名
result = html.xpath('//*[@class="bold"]')
print result[0].tag

以上使用的是XPath轴的用法,更多轴的用法可参考:http://www.w3school.com.cn/xpath/xpath_axes.asp

案例应用:抓取TIOBE指数前20名排行开发语言
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# @Author      : 
# @File        : test_1.py
# @Software    : PyCharm
# @description : XXX
 
 
import requests
from requests.exceptions import RequestException
from lxml import etree
from lxml.etree import ParseError
import json
 
 
def one_to_page(html):
    headers = {
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 '
                      '(KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36'
    }
    try:
        response = requests.get(html, headers=headers)
        body = response.text  # 获取网页内容
        try:
            html = etree.HTML(body, etree.HTMLParser())  # 解析HTML文本内容
            result = html.xpath('//table[contains(@class,"table-top20")]/tbody/tr//text()')  # 获取列表数据
            pos = 0
            for i in range(20):
                if i == 0:
                    yield result[i:5]
                else:
                    yield result[pos:pos + 5]  # 返回排名生成器数据
                pos += 5
        except ParseError as e:
            print(e.position)
    except RequestException as e:
        print('request is error!', e)
 
 
def write_file(data):  # 将数据重新组合成字典写入文件并输出
    for i in data:
        sul = {
            '2018年6月排行': i[0],
            '2017年6排行': i[1],
            '开发语言': i[2],
            '评级': i[3],
            '变化率': i[4]
        }
        with open('test.txt', 'a', encoding='utf-8') as f:
            f.write(json.dumps(sul, ensure_ascii=False) + '\n')  # 必须格式化数据
            f.close()
        print(sul)
 
 
def main():
    url = 'https://www.tiobe.com/tiobe-index/'
    data = one_to_page(url)
    write_file(data)
 
 
if __name__ == '__main__':
    main()
 
 
'''
{'2018年6月排行': '1', '2017年6排行': '1', '开发语言': 'Java', '评级': '15.932%', '变化率': '+2.66%'}
{'2018年6月排行': '2', '2017年6排行': '2', '开发语言': 'C', '评级': '14.282%', '变化率': '+4.12%'}
{'2018年6月排行': '3', '2017年6排行': '4', '开发语言': 'Python', '评级': '8.376%', '变化率': '+4.60%'}
{'2018年6月排行': '4', '2017年6排行': '3', '开发语言': 'C++', '评级': '7.562%', '变化率': '+2.84%'}
{'2018年6月排行': '5', '2017年6排行': '7', '开发语言': 'Visual Basic .NET', '评级': '7.127%', '变化率': '+4.66%'}
{'2018年6月排行': '6', '2017年6排行': '5', '开发语言': 'C#', '评级': '3.455%', '变化率': '+0.63%'}
{'2018年6月排行': '7', '2017年6排行': '6', '开发语言': 'JavaScript', '评级': '3.063%', '变化率': '+0.59%'}
{'2018年6月排行': '8', '2017年6排行': '9', '开发语言': 'PHP', '评级': '2.442%', '变化率': '+0.85%'}
{'2018年6月排行': '9', '2017年6排行': '-', '开发语言': 'SQL', '评级': '2.184%', '变化率': '+2.18%'}
{'2018年6月排行': '10', '2017年6排行': '12', '开发语言': 'Objective-C', '评级': '1.477%', '变化率': '-0.02%'}
{'2018年6月排行': '11', '2017年6排行': '16', '开发语言': 'Delphi/Object Pascal', '评级': '1.396%', '变化率': '+0.00%'}
{'2018年6月排行': '12', '2017年6排行': '13', '开发语言': 'Assembly language', '评级': '1.371%', '变化率': '-0.10%'}
{'2018年6月排行': '13', '2017年6排行': '10', '开发语言': 'MATLAB', '评级': '1.283%', '变化率': '-0.29%'}
{'2018年6月排行': '14', '2017年6排行': '11', '开发语言': 'Swift', '评级': '1.220%', '变化率': '-0.35%'}
{'2018年6月排行': '15', '2017年6排行': '17', '开发语言': 'Go', '评级': '1.189%', '变化率': '-0.20%'}
{'2018年6月排行': '16', '2017年6排行': '8', '开发语言': 'R', '评级': '1.111%', '变化率': '-0.80%'}
{'2018年6月排行': '17', '2017年6排行': '15', '开发语言': 'Ruby', '评级': '1.109%', '变化率': '-0.32%'}
{'2018年6月排行': '18', '2017年6排行': '14', '开发语言': 'Perl', '评级': '1.013%', '变化率': '-0.42%'}
{'2018年6月排行': '19', '2017年6排行': '20', '开发语言': 'Visual Basic', '评级': '0.979%', '变化率': '-0.37%'}
{'2018年6月排行': '20', '2017年6排行': '19', '开发语言': 'PL/SQL', '评级': '0.844%', '变化率': '-0.52%'}
'''

案例应用:解析 古文网 并打印 诗经 所对应的 URL
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# @Author      : 
# @File        : shijing.py
# @Software    : PyCharm
# @description : XXX
 
 
import json
import traceback
import requests
from lxml import etree
 
"""
step1: 安装 lxml 库。
step2: from lxml import etree
step3: selector = etree.HTML(网页源代码)
step4: selector.xpath(一段神奇的符号)
"""
 
 
def parse():
    url = 'https://www.gushiwen.org/guwen/shijing.aspx'
    r = requests.get(url)
    if r.status_code == 200:
        selector = etree.HTML(r.text)
        s_all_type_content = selector.xpath('//div[@class="sons"]/div[@class="typecont"]')
        print(len(s_all_type_content))
 
        article_list = list()
        for s_type_content in s_all_type_content:
            book_m1 = s_type_content.xpath('.//strong/text()')[0].encode('utf-8').decode('utf-8')
            s_all_links = s_type_content.xpath('.//span/a')
            article_dict = dict()
            for s_link in s_all_links:
                link_name = s_link.xpath('./text()')[0].encode('utf-8').decode('utf-8')
                try:
                    link_href = s_link.xpath('./@href')[0].encode('utf-8').decode('utf-8')
                except BaseException as e:
                    link_href = None
                article_dict[link_name] = link_href
            temp = dict()
            temp[book_m1] = article_dict
            article_list.append(temp)
        print(json.dumps(article_list, ensure_ascii=False, indent=4))
 
    else:
        print(r.status_code)
 
 
if __name__ == '__main__':
    parse()
    pass

CSS 选择器——cssSelector 定位方式详解
CSS 选择器 参考手册:http://www.w3school.com.cn/cssref/css_selectors.asp
CSS 选择器 :http://www.runoob.com/cssref/css-selectors.html

Selenium之CSS Selector定位详解:https://www.bbsmax.com/A/MyJxLGE1Jn/

css selector

CSS选择器用于选择你想要的元素的样式的模式。

"CSS"列表示在CSS版本的属性定义(CSS1,CSS2,或对CSS3)。

选择器	示例	示例说明	CSS
.class	.intro	选择所有class="intro"的元素	1
#id	#firstname	选择所有id="firstname"的元素	1
*	*	选择所有元素	2
element	p	选择所有<p>元素	1
element,element	div,p	选择所有<div>元素和<p>元素	1
element element	div p	选择<div>元素内的所有<p>元素	1
element>element	div>p	选择所有父级是 <div> 元素的 <p> 元素	2
element+element	div+p	选择所有紧接着<div>元素之后的<p>元素	2
[attribute]	[target]	选择所有带有target属性元素	2
[attribute=value]	[target=-blank]	选择所有使用target="-blank"的元素	2
[attribute~=value]	[title~=flower]	选择标题属性包含单词"flower"的所有元素	2
[attribute|=language]	[lang|=en]	选择 lang 属性以 en 为开头的所有元素	2
:link	a:link	选择所有未访问链接	1
:visited	a:visited	选择所有访问过的链接	1
:active	a:active	选择活动链接	1
:hover	a:hover	选择鼠标在链接上面时	1
:focus	input:focus	选择具有焦点的输入元素	2
:first-letter	p:first-letter	选择每一个<P>元素的第一个字母	1
:first-line	p:first-line	选择每一个<P>元素的第一行	1
:first-child	p:first-child	指定只有当<p>元素是其父级的第一个子级的样式。	2
:before	p:before	在每个<p>元素之前插入内容	2
:after	p:after	在每个<p>元素之后插入内容	2
:lang(language)	p:lang(it)	选择一个lang属性的起始值="it"的所有<p>元素	2
element1~element2	p~ul	选择p元素之后的每一个ul元素	3
[attribute^=value]	a[src^="https"]	选择每一个src属性的值以"https"开头的元素	3
[attribute$=value]	a[src$=".pdf"]	选择每一个src属性的值以".pdf"结尾的元素	3
[attribute*=value]	a[src*="runoob"]	选择每一个src属性的值包含子字符串"runoob"的元素	3
:first-of-type	p:first-of-type	选择每个p元素是其父级的第一个p元素	3
:last-of-type	p:last-of-type	选择每个p元素是其父级的最后一个p元素	3
:only-of-type	p:only-of-type	选择每个p元素是其父级的唯一p元素	3
:only-child	p:only-child	选择每个p元素是其父级的唯一子元素	3
:nth-child(n)	p:nth-child(2)	选择每个p元素是其父级的第二个子元素	3
:nth-last-child(n)	p:nth-last-child(2)	选择每个p元素的是其父级的第二个子元素,从最后一个子项计数	3
:nth-of-type(n)	p:nth-of-type(2)	选择每个p元素是其父级的第二个p元素	3
:nth-last-of-type(n)	p:nth-last-of-type(2)	选择每个p元素的是其父级的第二个p元素,从最后一个子项计数	3
:last-child	p:last-child	选择每个p元素是其父级的最后一个子级。	3
:root	:root	选择文档的根元素	3
:empty	p:empty	选择每个没有任何子级的p元素(包括文本节点)	3
:target	#news:target	选择当前活动的#news元素(包含该锚名称的点击的URL)	3
:enabled	input:enabled	选择每一个已启用的输入元素	3
:disabled	input:disabled	选择每一个禁用的输入元素	3
:checked	input:checked	选择每个选中的输入元素	3
:not(selector)	:not(p)	选择每个并非p元素的元素	3
::selection	::selection	匹配元素中被用户选中或处于高亮状态的部分	3
:out-of-range	:out-of-range	匹配值在指定区间之外的input元素	3
:in-range	:in-range	匹配值在指定区间之内的input元素	3
:read-write	:read-write	用于匹配可读及可写的元素	3
:read-only	:read-only	用于匹配设置 "readonly"(只读) 属性的元素	3
:optional	:optional	用于匹配可选的输入元素	3
:required	:required	用于匹配设置了 "required" 属性的元素	3
:valid	:valid	用于匹配输入值为合法的元素	3
:invalid	:invalid	用于匹配输入值为非法的元素	3
CSS选择器的常见语法:



1.  根据 标签 定位 tagName (定位的是一组,多个元素)
        find_element_by_css_selector("div")

2. 根据 id属性 定位 ( 注意:id 使用 # 表示)
        find_element_by_css_selector("#eleid")
        find_element_by_css_selector("div#eleid")
3. 根据 className 属性 定位(注意:class 属性 使用 . )

        两种方式:前面加上 tag 名称。也可以不加。如果不加 tag 名称时,点不能省略。
        find_element_by_css_selector('.class_value')       
        find_element_by_css_selector("div.eleclass")
        find_element_by_css_selector('tag_name.class_value')

        有的 class_value 比较长,而且中间有空格时,不能把空格原样写进去,那样不能识别。
        这时,空格用点代替,前面要加上 tag_name。
        driver.find_element_by_css_selector('div.panel.panel-email').click()
        # <p class="important warning">This paragraph is a very important warning.</p>
        driver.find_element_by_css_selector('.important')
        driver.find_element_by_css_selector('.important.warning')
4. 根据 标签 属性 定位
        两种方式,可以在前面加上 tag 名称,也可以不加。
        find_element_by_css_selector("[attri_name='attri_value']")
        find_element_by_css_selector("input[type='password']").send_keys('密码')
        find_element_by_css_selector("[type='password']").send_keys('密码')
    4.1 精确 匹配:
        find_element_by_css_selector("div[name=elename]")  #属性名=属性值,精确值匹配
        find_element_by_css_selector("a[href]") #是否存在该属性,判断a元素是否存在href属性

    注意:如果 class属性值 里带空格,用.来代替空格
    4.2 模糊 匹配
        find_element_by_css_selector("div[name^=elename]") #从起始位置开始匹配
        find_element_by_css_selector("div[name$=name2]") #从结尾匹配
        find_element_by_css_selector("div[name*=name1]") #从中间匹配,包含
    4.3 多属性 匹配
        find_element_by_css_selector("div[type='eletype][value='elevalue']") #同时有多属性
        find_element_by_css_selector("div.eleclsss[name='namevalue'] #选择class属性为eleclass并且name为namevalue的div节点
        find_element_by_css_selector("div[name='elename'][type='eletype']:nth-of-type(1) #选择name为elename并且type为eletype的第1个div节点

5. 定位  子元素 (A>B)
        find_element_by_css_selector("div#eleid>input") #选择id为eleid的div下的所有input节点
        find_element_by_css_selector("div#eleid>input:nth-of-type(4) #选择id为eleid的div下的第4个input节点
        find_element_by_css_selector("div#eleid>nth-child(1)") #选择id为eleid的div下的第一个子节点

6. 定位  后代元素 (A空格B)
        find_element_by_css_selector("div#eleid input") #选择id为eleid的div下的所有的子孙后代的 input 节点
        find_element_by_css_selector("div#eleid>input:nth-of-type(4)+label #选择id为eleid的div下的第4个input节点的相邻的label节点
        find_element_by_css_selector("div#eleid>input:nth-of-type(4)~label #选择id为eleid的div下的第4个input节点之后中的所有label节点

7. 不是 ( 否 )
        find_element_by_css_selector("div#eleid>*.not(input)") #选择id为eleid的div下的子节点中不为input 的所有子节点
        find_element_by_css_selector("div:not([type='eletype'])") #选择div节点中type不为eletype的所有节点

8. 包含 
        find_element_by_css_selector("li:contains('Goa')") # <li>Goat</li>
        find_element_by_css_selector("li:not(contains('Goa'))) # <li>Cat</li>

9. by index
        find_element_by_css_selector("li:nth(5)")

10. 路径  法
        两种方式,可以在前面加上 tag 名称,也可以不加。注意它的层级关系使用大于号">"。
        find_element_by_css_selector("form#loginForm>ul>input[type='password']").send_keys('密码')



高阶:





基本 css 选择器
CSS 选择器中,最常用的选择器 如下:

选择器	描述	举例
*	通配选择器,选择所有的元素	*
<type>	选择特定类型的元素,支持基本HTML标签	h1
.<class>	选择具有特定class的元素。	.class1
<type>.<class>	特定类型和特定class的交集。(直接将多个选择器连着一起表示交集)	h1.class1
#<id>	选择具有特定id属性值的元素	#id1
属性选择器
除了最基本的核心选择器外,还有可以 基于属性 的 属性选择器:

选择器	描述	举例
[attr]	选取定义attr属性的元素,即使该属性没有值	[placeholder]
[attr="val"]	选取attr属性等于val的元素	[placeholder="请输入关键词"]
[attr^="val"]	选取attr属性开头为val的元素	[placeholder^="请输入"]
[attr$="val"]	选取attr属性结尾为val的元素	[placeholder$="关键词"]
[attr*="val"]	选取attr属性包含val的元素	[placeholder*="入关"]
[attr~="val"]	选取attr属性包含多个空格分隔的属性,其中一个等于val的元素	[placeholder~="关键词"]
[attr|="val"]	选取attr属性等于val的元素或第一个属性值等于val的元素	[placeholder|="关键词"]
        <p class="important warning">This paragraph is a very important warning.</p>
        selenium举例: (By.CSS_SELECTOR,'p[class="import warning"]') 
        属性与属性的值需要完全匹配,如上面用p[class='impprtant']就定位不到; 
        部分属性匹配:(By.CSS_SELECTOR,'p[class~="import warning"]'); 
        子串匹配&特定属性匹配: 
        [class^="def"]:选择 class 属性值以 "def" 开头的所有元素 
        [class$="def"]:选择 class 属性值以 "def" 结尾的所有元素 
        [class*="def"]:选择class 属性值中包含子串 "def" 的所有元素 
        [class|="def"]:选择class 属性值等于"def"或以"def-"开头的元素(这个是特定属性匹配)

关系选择器
有一些选择器是基于层级之间的关系,这类选择器称之为关系选择器。

选择器	描述	举例
<selector> <selector>	第二个选择器为第一个选择器的后代元素,选取第二个选择器匹配结果	.class1 h1
<selector> > <selector>	第二个选择器为第一个选择器的直接子元素,选取第二个选择器匹配结果	.class1 > *
<selector> + <selector>	第二个选择器为第一个选择器的兄弟元素,选取第二个选择器的下一兄弟元素	.class1 + [lang]
<selector> ~ <selector>	第二个选择器为第一个选择器的兄弟元素,选取第二个选择器的全部兄弟元素	.class1 ~ [lang]
        选择 某个元素 的 后代的元素: 
        selenium举例:(By.CSS_SELECTOR,‘div button’)
        div元素的所有的后代元素中标签为button元素,不管嵌套有多深

        选择 某个元素 的 子代元素: 
        selenium举例:(By.CSS_SELECTOR,‘div > button’)
        div元素的所有的子代元素中标签为button元素(>符号前后的空格可有可无)

        一个元素不好定位时,它的兄长元素很起眼,可以借助兄长来扬名,因此不妨称之为 "弟弟选择器".
        即选择某个元素的弟弟元素(先为兄,后为弟): 
        selenium举例: (By.CSS_SELECTOR,'button + li')
        button与li属于同一父元素,且button与li相邻,选择button下标签为li的元素

联合选择器与反选择器
利用 联合选择器与反选择器,可以实现 与和或 的关系。

选择器	描述	举例
<selector>,<selector>	属于第一个选择器的元素或者是属于第二个选择器的元素	h1, h2
:not(<selector>)	不属于选择器选中的元素	:not(html)
伪元素和伪类选择器
CSS选择器支持了 伪元素和伪类选择器。

:active	鼠标点击的元素
:checked	处于选中状态的元素
:default	选取默认值的元素
:disabled	选取处于禁用状态的元素
:empty	选取没有任何内容的元素
:enabled	选取处于可用状态的元素
:first-child	选取元素的第一个子元素
:first-letter	选取文本的第一个字母
:first-line	选取文本的第一行
:focus	选取得到焦点的元素
:hover	选取鼠标悬停的元素
:in-range	选取范围之内的元素
:out-of-range	选取范围之外的元素
:lang(<language>)	选取lang属性为language的元素
:last-child	选取元素的最后一个子元素
————————————————
版权声明:本文为CSDN博主「「已注销」」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/lyshark_lyshark/article/details/125846734

您可能还喜欢...

发表回复