首页 > 编程语言 > 详细

Python爬虫〇七———数据解析之XPATH的使用

时间:2021-02-28 15:31:09      阅读:35      评论:0      收藏:0      [点我收藏+]

今天来总结最后一种说句解析的方式——XPath。 

XPath是一门在XML文档中查找信息的语言,用于在XML文档中通过元素和属性进行导航。

XPath简介

 下面来简单介绍一下XPath。

XPath的特点

  1. XPath使用路径表达式在XML文档中进行导航
  2. XPath包含一个标准函数库
  3. XPath是XSLT(Extensible Stylesheet Language Transformation)中的主要元素
  4. XPath是一个W3C标准

XPath解析方法

  1. 实例化一个etree对象,在实例化的时候讲被解析的页面源码数据加载到该对象中
  2. 调用etree的xpath方法结合xpath表达式实现标签的定位和数据的获取

环境的配置

XPath需要lxml库,lxml库的安装我们在前面讲bs4的时候已经说过了,可以通过pip直接安装。

pip3 install lxml

 

etree对象的实例化

和bs4一样,etree对象的实例化分两种情况

加载本地的html文件

加载本地html文件有两种方式,比方有个test.html文件

####################方法1####################
from lxml import etree
with open(./test.html,r) as f:
    data = f.read()
    tree = etree.HTML(data)

####################方法2####################
from lxml import etree
tree = etree.parse(./test.html,etree.HTMLParser())

一个是吧html代码读取以后用HTML方法处理,还有一种方法是直接指定路径,但是这种方法一定要指定一个解释器。

加载互联网上爬取的源码数据

加载网络爬取的数据的方法和上面的第一种方法一样,就是把拿到的字符串加载到HTML方法。

 XPath表达式

在拿到tree对象以后,我们要通过XPath表达式来定位到所需要的标签以及里面的内容 。假设我们本地存有一个test.html文件,内容和上一章的一样

技术分享图片
 <html>
  <head>
   <title>
    The Dormouse‘s story
   </title>
  </head>
  <body>
   <p class="title">
    <b>
     The Dormouse‘s story
    </b>
   </p>
   <p class="story">
    Once upon a time there were three little sisters; and their names were
    <a class="sister" href="http://example.com/elsie" id="link1">
     Elsie
    </a>
    ,
    <a class="sister" href="http://example.com/lacie" id="link2">
     Lacie
    </a>
    and
    <a class="sister" href="http://example.com/tillie" id="link2">
     Tillie
    </a>
    ; and they lived at the bottom of a well.
   </p>
   <p class="story">
    ...
   </p>
  </body>
 </html>
test.html

然后实例化一个tree对象,并且把带解析的源码加载进去

from lxml import etree
tree = etree.parse(./test.html,etree.HTMLParser())

下面我们就用这个tree对象来讲xpath到用法

XPath术语

想要了解XPath的用法,我们要先了解XPath的基本术语

节点(Node)

在XPath中有其中类型的节点:元素,属性,文本,命名空间,处理指令以及文档节点,整个文档是被作为节点树来对待的,树的根被称为文档节点或根节点。

基本值(Atomic Value)

又称原子值,无父或子节点

节点关系

节点关系分为父,子同胞,先辈,后代。顾名思义就是各个节点之间的关系,要注意的是先辈是包含父类关系的,而后代也包含子级关系的。

xpath节点选取

首先要了解最基础的xpath表达式

表达式 描述
nodename 选取此节点的所有子节点
/ 从根节点选取
//

放在开始从匹配到当前节点选择文档中的节点,而不考虑其位置

放在两个标签内表示间隔多个标签层级

. 选取当前节点
.. 选取当前节点的父节点
@ 选取属性

下面可以针对上面的表达式,结合test.html实例化的tree对象代码来演示一下

依靠节点

a_tags = tree.xpath(/html/body/p/a)
print(a_tags)
##########输出##########
[<Element a at 0x7fdb8f189e00>, <Element a at 0x7fdb8f226b00>, <Element a at 0x7fdb8f10f8c0>]

上面的代码就是搜索html——>body——>p——>a标签,返回值是一个列表,里面放到都是<class ‘lxml.etree._Element‘>对象

依靠属性定位

print(tree.xpath(//a[@class="sister"]))
##########输出##########
[<Element a at 0x7fdb8f36cfc0>, <Element a at 0x7fdb8f11d4c0>, <Element a at 0x7fdb8f099380>]

上面的代码就实现了通过指定class的值搜索到对应的a标签。

谓语

我们还可以通过谓语(Predicates)来超找某个特定的节点或者包含某个指定值得节点

在下面的表格中,列出来一些带有谓语的表达式和其对应的结果

表达式 结果
/html/body/p/a[1] 选取a元素的第一个元素
/html/body/p/a[last()] 获取最后一个a元素(注意带括号)
/html/body/p/a[last()-1] 获取倒数第二个a元素(注意-1的位置)
/html/body/p/a[position()<3] 获取最前面两个属于p元素的子元素a
//a[@class] 获取所有有class属性的a元素

//a[@class=‘sister]

获取所有class属性值为sister的a元素
/html/body/div[p>20] 获取html->body->div下值大于20的p标签(该用法常用于xml中)
/html/body/div[p>20]/a 获取html->body->div下单a标签,且其中p标签内的值应大于20

这里有个要注意点地方,就是在获取第n个元素的时候,在表达式和列表里切片的n的值出来的是不一样的

st = """
<html>
<body>
<ul>
<li>0</li>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
<body>
</html>
"""

tree = etree.HTML(st,etree.HTMLParser())
t1 = tree.xpath(/html/body/ul/li[1]/text())
print(t1,t1)
t2 = tree.xpath(/html/body/ul/li/text())
print(t2,t2[1])
##########输出##########
t1 [0]
t2 1

 

通配符

在匹配到时候还可以使用通配符来匹配任意一个节点

通配符 效果 案例 效果
* 匹配任何元素节点 /html/body/*/li 匹配body标签下任意标签下单li标签
@* 匹配任何属性节点 //p[@*] 匹配具有任意属性的p标签
node() 匹配任何类型的节点 //* 选取文档中所有元素

多个路径的选取

在xpath表达式中我们可以通过管道符来选取多个路径,这里不在放案例了。

文本获取

在索引到需要的标签后我们就要获取标签里的文本。文本的获取有两个方法

  • /text()
  • //text()

注意,一个是单斜杠,另一个是双斜杠,效果如下

s="""
<div class=‘test‘>div标签内<p>p标签内</p></div>
"""

tree = etree.HTML(s,etree.HTMLParser())
print(//,tree.xpath(//div//text()))
print(/,tree.xpath(//div/text()))
##########输出##########
// [div标签内, p标签内]
/ [div标签内]

单斜杠是获取本标签直系的文本内容

双斜杠包含了本标签及后代标签内的文本内容。

案例

 下面结合一个案例来试一下XPath的使用

需求,从站长之家爬取免费的简历模板

url:https://sc.chinaz.com/jianli/free.html,要爬取5页的数据内容

直接放代码吧,看看怎么讲一下

 1 import requests
 2 from lxml import etree
 3 
 4 for page_index in range(1,6):     #爬取1-5页内容,指定url
 5     if page_index ==1:            #第一页的url和后面的规律不同
 6         url = https://sc.chinaz.com/jianli/free.html
 7     else:
 8         url = https://sc.chinaz.com/jianli/free_{}.html.format(page_index)
 9     
10     page = requests.get(url=url)
11     page.encoding=utf-8
12     page_text = page.text
13     
14 
15     tree = etree.HTML(page_text,etree.HTMLParser())
16 
17     tag = tree.xpath(//div[@class="box col3 ws_block masonry-brick"])
18 
19     tags = tree.xpath(//div[@id="main"]//div[contains(@class,"box") and contains(@class,"ws_block")]//p/a)
20     for tag in tags:
21         model_url = http:+tag.xpath(./@href)[0]
22         model_name = tag.xpath(./text())[0]
23         print(model_url)
24         
25         model_page_text = requests.get(url=model_url).text
26         model_tree = etree.HTML(model_page_text,etree.HTMLParser())
27         
28         model_link = model_tree.xpath(//ul[@class="clearfix"]//a/@href)[0]
29         
30     
31         print(model_link)
32         file_name = model_name+.rar
33         
34         with open(./简历模板/+file_name,wb) as f:
35             data = requests.get(url=model_link).content
36             f.write(data)
37         print(file_name,finished!)
38         
39     print(----------page{}finish!----------)

就是分了三个层次

第一层先爬取主页内容,在主页上有若干模板的子链接(页面2),第二层爬取页面2的内容,获取到待下载文件的名称以及链接地址;第三层直接爬取文件(二进制的压缩包),爬取后永久化存储至本地。

这里有个问题,运行一段时间后可能会报一个错误:Httpconnectionpool,是因为短时间发起来高频的请求导致ip被禁,或者http连接处中的连接资源被耗尽。针对第一个我们在下一章会讲到请求代理操作

第二个可以在headers里加一个新的键值对:Conection:"close"

 

Python爬虫〇七———数据解析之XPATH的使用

原文:https://www.cnblogs.com/yinsedeyinse/p/14427785.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!