python 爬虫解析 XPath

XPath

XPath , 全称 XML Path Language ,即 XML 路径语言,它是一门在 XML 文档中查找信息的语言 。它最初是用来搜寻 XML 文档的,但是它同样适用于 HTML 文档的搜索。

需要安装lxml,命令:pip install lxml

XPath常用规则

表达式 描述
nodename 选取此节点的所有子节点
/ 从当前节点选取直接子节点
// 从当前节点选取子孙节点
. 选取当前节点
选取当前节点的父节点
@ 选取属性

//title[@lang=‘eng’] 这就是一个 XPath 规则 ,它代表选择所有名称为 title ,同时属性 lang 的值为 eng 的节点 。

etree 模块

调用etree.HTML(str:) 可以构造一个 XPath 解析对象(html) ;调用 tostring()方法可输出修正后的 HTML 代码(自动补齐html的头,尾),但是结果是 bytes 类型 。

from lxml import etree

text = '''

'''
html = etree.HTML(text)
result= etree.tostring(html)
print(result.decode('utf-8'))

解析html文件

from lxml import etree

html = etree.parse('./test.html', etree.HTMLParser())
result= etree.tostring(html)
print(result.decode('utf-8'))

获取所有节点

// 开头的 XPath 规则来选取所有符合要求的节 ,返回list集合;元素类型为lxml.etree._Element,与 etree.parse()返回的的格式一致

from lxml import etree

html = etree.parse('./test.html', etree.HTMLParser())
result = html.xpath('//*')
print(result)
### 输出对象列表
# [, , , , , ,  ...]
# print(type(result[0])) == print(type(html)) 都是

子节点

通过 / 或 // 即可查找元素的子节点或子孙节点 。假如现在想选择 li 节点的所有直接 a 子节点,可以这样实现:

from lxml import etree

html = etree.parse('./test.html', etree.HTMLParser())
result = html.xpath('//li/a')
print(result)

## [,  , , ,]

/ 用于选取直接子节点 ,如果要获取所有子孙节点,就可以使用//。例如,要获取 ul 节点下的所有子孙 a 节点 :

from lxml import etree

html = etree.parse('./test.html', etree.HTMLParser())
result = html.xpath('//ul//a')
print(result)

## [,  , , ,]

父节点

用 … 表示选择父级节点。首先选中 href 属性为 link4.html 的 a 节点,然后再获取其父节点,然后再获取其 class属性

from lxml import etree

html = etree.parse('./test.html', etree.HTMLParser())
result = html.xpath('//a[@href="link4.html"]/../@class')
print(result)
## ['item-1']                    

也可以通过 parent:: 来获取父节点

from lxml import etree

html = etree.parse('./test.html', etree.HTMLParser())
result = html.xpath('//a[@href="link4.html"]/parent::*/@class')
print(result)
## ['item-1']    

属性匹配

在选取的时候,可以用@符号进行属性过滤 。 比如,这里如果要选取 class 为 item-0 的 li节点

from lxml import etree

html = etree.parse('./test.html', etree.HTMLParser())
result = html.xpath('//li[@class="item-0"]')
print(result)
##[, ]    

文本获取

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

from lxml import etree

html = etree.parse('./test.html', etree.HTMLParser())
result = html.xpath('//li[@class="item-0"]/a/text()')
print(result)
## ['first item','fifth item']

注意 // 与 / 的区别

from lxml import etree

html = etree.parse('./test.html', etree.HTMLParser())
result = html.xpath('//li[@class="item-0"]//text()')
print(result)
## ['first item','fifth item','\n    ']

属性获取

通过@href 即可获取节点的 href 属性。 注意,此处和属性匹配的方法不同,属性匹配是中括号加属性名和值来限定某个属性,如[@href=“linkl.html”],而此处的@href 指的是获取节点的某个属性,二者需要做好区分。

from lxml import etree

html = etree.parse('./test.html', etree.HTMLParser())
result = html.xpath('//li/a/@href')
print(result)
# [ 'linkl. html', 'link2. html','link3.html','link4 .html','links.html']

属性多值匹配

from lxml import etree

text ='''
  • first item
  • ''' html = etree.HTML(text) result = html.xpath('//li[@class="li"]/a/text()') print(result) # []
  • 上例无法获取 a 标签内的文本,因为li 的class 属性有多个值,而 //li[@class=“li”] 匹配不到li对象。通过contains ()函数可以解决这个问题

    from lxml import etree
    
    text ='''
    
  • first item
  • ''' html = etree.HTML(text) result = html.xpath('//li[contains(@class,"li")]/a/text()') print(result) # ['first item'] result = html.xpath('//li[contains(@class,"li li-first")]/a/text()') print(result) # ['first item']
  • 多属性匹配

    同时匹配多个属性,可以使用and运算符连接

    from lxml import etree
    
    text ='''
    
  • first item
  • ''' html = etree.HTML(text) result = html.xpath('//li[contains(@class,"li") and @name="item"]/a/text()') print(result) # ['first item']
  • 运算符 描述 实例 返回值
    or age=19 or age=20 如果 age 是 19 ,则返回 true 。 如果 age 是 21 ,则返回 false
    and age>19 and age<21 如果 age 是 20 ,则返回 true 。 如果 age 是 18 ,则返回 false
    mod 除法的余数 5 mod 2 1
    | 计算两个节点集 //book | //cd 返回所有拥有 book 和 cd 元素的节点集
    + 加法 6+4 10
    - 减法 6-4 2
    * 乘法 6*4 24
    div 除法 8 dev 4 2
    = 等于 age=19 如果 age 是 19 ,则返回 true 。如果 age 是 20 ,则返回false
    != 不等于 age!=19 如果 age 是 18 ,则返回 true 。如果 age 是 19,则返回false
    < 小于 age<19 如果 age 是 18 ,则返回 true 。 如果 age 是 19 ,则返回 false
    <= 不大与 age=<19 如果 age 是 19,则返回 true 。 如果 age 是 20 ,则返回 false
    > 大于 age>19 如果 age 是 20 ,则返回 true 。 如果 age 是 19 ,则返回 false
    >= 不小于 age>=19 如果 age 是 19 ,则返回 true 。 如果 age 是 18,则返回 false

    按序选择

    在选择的时候某些属性可能同时匹配了多个节点,但是只想要其中的某个节点

    from lxml import etree
    
    text = '''
    
    '''
    html = etree.HTML(text)
    # 取第一个 li 节点(注意序号从1开始,不是0)
    result = html.xpath('//li[1]/a/text()')
    print(result)
    # 取第最后一个 li 节点
    result = html.xpath('//li[last()]/a/text()')
    print(result)
    # 取前2个 li 节点
    result = html.xpath('//li[position()<3]/a/text()')
    print(result)
    # 取倒数第3个 li 节点
    result = html.xpath('//li[last()-2]/a/text()')
    print(result)
    
    

    节点轴选择

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

    from lxml import etree
    
    text = '''
    
    '''
    html = etree.HTML(text)
    # ancestor 轴,可以获取所有祖先节点
    result = html.xpath('//li[1]/ancestor::*')
    print(result)
    #加了限定条件,这次在冒号后面加了 div ,这样得到的结果就只有 div 这个祖先节点
    result = html.xpath('//li[1]/ancestor::div')
    print(result)
    # attribute 轴,可以获取所有属性值,其后跟的选择器还是*,这代表获取节点的所有属性
    result = html.xpath('//li[1]/attribute::*')
    print(result)
    #child 轴,可以获取所有直接子节点 。 这里加了限定条件,选取 href 属性为 link1.html 的 a 节点
    result = html.xpath('//li[1]/child::a[@href="link1.html"]')
    print(result)
    #descendant 轴,可以获取所有子孙节点 。 这里我们又加了限定条件获取 span 节点
    result = html.xpath('//li[1]/descendant::span')
    print(result)
    #following 轴,可以获取当前节点之后的所有节点。这里虽然使用的是*匹配,但又加了索引选择,所以只获取了第二个后续节点
    result = html.xpath('//li[1]/following::*[2]')
    print(result)
    #following-sibling 轴,可以获取当前节点之后的所有同级节点。这里我们使用*匹配,所以获取了所有后续同级节点
    result = html.xpath('//li[1]/following-sibling::*')
    print(result)
    

    你可能感兴趣的:(Python爬虫,python,爬虫,开发语言)