爬虫 - XPath

定义

XPath,全称 XML Path Language,即 XML 路径语言,它是一门在XML文档中查找信息的语言,是一个文档解析库。XPath 最初设计是用来搜寻XML文档的,但是它同样适用于 HTML 文档的搜索。
所以在做爬虫时,可以使用 XPath 来做相应的信息抽取,定位节点。XPath有特定的语法、函数、运算符去定位节点、获取节点信息

常用规则

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

1. lxml的etree模块可以对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.decode('utf-8'))

读取文件,再解析

from lxml import etree

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

test.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">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>

2. 选取所有节点

选取所有节点:XPath语法://*

from lxml import etree
html = etree.parse('./test.html', etree.HTMLParser())
result = html.xpath('//*')
print(result)

只选取所有li节点:XPath语法://li

from lxml import etree
html = etree.parse('./test.html', etree.HTMLParser())
result = html.xpath('//li')
print(result)
print(result[0])

3. 获取孩子节点(/)和孙子节点(//)

孩子节点

from lxml import etree

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

孙子节点

from lxml import etree

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

这个例子中,运行结果是相同的。因为ul里面只有一个a。

4. 获取父节点

XPath语法:/..或者parent::

from lxml import etree

html = etree.parse('./test.html', etree.HTMLParser())
result = html.xpath('//a[@href="link4.html"]/../@class')
print(result)
from lxml import etree

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

5. 获取有相应属性的节点(属性匹配)

选取 class 为 item-1 的 li 节点

from lxml import etree
html = etree.parse('./test.html', etree.HTMLParser())
result = html.xpath('//li[@class="item-1"]')
print(result)

6. 获取节点的文本

from lxml import etree

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

# 运行结果:['\n     ']

匹配到的结果就是被修正的 li 节点内部的换行符,因为自动修正的li节点的尾标签换行了
即选中的是这两个节点:

<li class="item-0"><a href="link1.html">first item</a></li>
<li class="item-0"><a href="link5.html">fifth item</a>
</li>

其中一个节点因为自动修正,li 节点的尾标签添加的时候换行了,所以提取文本得到的唯一结果就是 li 节点的尾标签和 a 节点的尾标签之间的换行符

如果我们想获取 li 节点内部的文本就有两种方式,一种是选取到 a 节点再获取文本,另一种就是使用 //

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     ']

先选取到特定的子孙节点,然后再调用 text() 方法获取其内部文本,这样可以保证获取的结果是整洁的

7. 获取属性值

获取所有 li 节点下所有 a 节点的 href 属性

from lxml import etree

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

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

8. 属性多值匹配

from lxml import etree
text = '''
<li class="li li-first"><a href="link.html">first item</a></li>
'''
html = etree.HTML(text)
result = html.xpath('//li[@class="li"]/a/text()')
print(result)

# 运行结果 []

有多个值就需要用 contains() 函数,因为//li[@class="li"]代表精确匹配

from lxml import etree
text = '''
<li class="li li-first"><a href="link.html">first item</a></li>
'''
html = etree.HTML(text)
result = html.xpath('//li[contains(@class, "li")]/a/text()')
print(result)

# 运行结果 ['first item']

9. 多属性匹配

可能需要根据多个属性才能确定一个节点,这是就需要同时匹配多个属性才可以,那么这里可以使用运算符 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)
result = html.xpath('//li[contains(@class, "li") and @name="item"]/a/text()')
print(result)

and是XPath的运算符,参考地址http://www.w3school.com.cn/xpath/xpath_operators.asp

10. 按序选择节点

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

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 = html.xpath('//li[1]/a/text()')    # 注意这里和代码中不同,序号是以 1 开头的,不是 0 开头的。result是0开头的,因为result是一个列表。
print(result)
result = html.xpath('//li[last()]/a/text()')    # 返回最后一个li节点
print(result)
result = html.xpath('//li[position()<3]/a/text()')    # 选取了位置小于 3 的 li 节点,也就是位置序号为 1 和 2 的节点。即得到了前两个节点
print(result)
result = html.xpath('//li[last()-2]/a/text()')    # 中括号中传入 last()-2即可,因为 last() 是最后一个,所以 last()-2 就是倒数第三个
print(result)

XPath 中提供了 100 多个函数,包括存取、数值、字符串、逻辑、节点、序列等处理功能,具体所有的函数作用可以参考:http://www.w3school.com.cn/xpath/xpath_functions.asp

11. 节点轴选择

XPath 提供了很多节点轴选择方法,英文叫做 XPath Axes,包括获取子元素、兄弟元素、父元素、祖先元素等等,在一定情况下使用它可以方便地完成节点的选择

from lxml import etree

text = '''
<div>
    <ul>
         <li class="item-0"><a href="link1.html"><span>first item</span></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 = html.xpath('//li[1]/ancestor::*')
print(result)
result = html.xpath('//li[1]/ancestor::div')
print(result)
result = html.xpath('//li[1]/attribute::*')
print(result)
result = html.xpath('//li[1]/child::a[@href="link1.html"]')
print(result)
result = html.xpath('//li[1]/descendant::span')
print(result)
result = html.xpath('//li[1]/following::*[2]')
print(result)
result = html.xpath('//li[1]/following-sibling::*')
print(result)

参考:http://www.w3school.com.cn/xpath/xpath_axes.asp

总结

XPath ,熟练使用之后可以大大提升 HTML(文档) 信息的提取效率

转载于:https://www.cnblogs.com/allen2333/p/9300122.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提取,编辑和轻松评估XPath查询。 XPath的助手很容易提取,编辑,并在任何网页评估XPath查询。 重要提示:安装此扩展后,必须重新加载任何现有的选项卡或重新启动Chrome浏览器扩展工作。 说明: 1.打开一个新的标签,并导航到任何网页。 2.按Ctrl-Shift键-X(或OS X命令移-X),或单击工具栏上的XPath的助手按钮,以打开XPath助手控制台。 3.按住Shift键将鼠标悬停在页面上的元素。查询框将不断更新,以显示鼠标指针下方的元件XPath查询,结果框将显示当前查询的结果。 4.如果需要,请在控制台直接编辑XPath查询。结果框会立即反映更改。 5.重复步骤(2)关闭控制台。 如果控制台在你的方式获得,按住Shift键,然后将鼠标移动到它; 它会移动到页面的相对侧。 一个忠告:当渲染HTML表格,浏览器插入人工<TBODY>标记到DOM,这将在随后通过该扩展提取查询显示出来。 Extract, edit, and evaluate XPath queries with ease. XPath Helper makes it easy to extract, edit, and evaluate XPath queries on any webpage. IMPORTANT: After installing this extension, you must reload any existing tabs or restart Chrome for the extension to work. Instructions: 1. Open a new tab and navigate to any webpage. 2. Hit Ctrl-Shift-X (or Command-Shift-X on OS X), or click the XPath Helper button in the toolbar, to open the XPath Helper console. 3. Hold down Shift as you mouse over elements on the page. The query box will continuously update to show the XPath query for the element below the mouse pointer, and the results box will show the results for the current query. 4. If desired, edit the XPath query directly in the console. The results box will immediately reflect your changes. 5. Repeat step (2) to close the console. If the console gets in your way, hold down Shift and then move your mouse over it; it will move to the opposite side of the page. One word of caution: When rendering HTML tables, Chrome inserts artificial <tbody> tags into the DOM, which will consequently show up in queries extracted by this extension.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值