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

作者:神秘网友 发布时间:2021-02-28 11:20:03

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

今天来总结最后一种说句解析的方式——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[p20] 获取html-body-div下值大于20的p标签(该用法常用于xml中)
/html/body/div[p20]/a 获取html-body-div下单a标签,且其中p标签内的值应大于20

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

st = """
html
body
ul
li0/li
li1/li
li2/li
li3/li
li4/li
li5/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标签内pp标签内/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的使用 相关文章

  1. springboot中的数据源自动配置以及druid的整合

    一、springboot中使用数据源的依赖 (1)、JDBC启动器 (2)、数据库连接依赖包 dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-jdbc/artifactId/dependencydependency groupIdmysql/groupId artifactIdmysql-connector

  2. 将数据库中表生成excel

    依赖 dependency groupIdorg.apache.poi/groupId artifactIdpoi/artifactId version3.10-FINAL/version /dependency /** * 生成Excel表 * @param response * @param dataList 表格数据 * ListString[] dataList = new ArrayList(); * ListMapString, Object

  3. go语言设计与实现-数据结构-阅读笔记

    数组 Go 语言中数组在初始化之后大小就无法改变,存储元素类型相同、但是大小不同的数组类型在 Go 语言看来也是完全不同的,只有两个条件都相同才是同一个类型。 func NewArray(elem *Type, bound int64) *Type { if bound 0 { Fatalf("NewArray: invalid bo

  4. Python - lambda 匿名函数

    说匿名函数之前,先来回归一下 函数的语法格式: def 函数名([形式参数1, 形式参数2, ....., 形式参数n]): 函数体 当函数中只有一行return语句时,函数的定义可以用一个lambda表达式来代替。 lambda的语法格式: lambda [形式参数1, 形式参数2, ....., 形式

  5. MySQL数据库之索引与慢查询优化

    索引与慢查询优化 索引参考博客:https://www.cnblogs.com/linhaifeng/articles/7274563.html 知识回顾:数据都是存在硬盘上的,那查询数据不可避免的需要进行IO操作 索引在MySQL中也叫做“键”,是存储引擎用于快速找到记录的一种数据结构。 primary key uni

  6. 使用TCP协议循环发送数据

    循环很简单,像这样就OK: TCPOfSend.java: 1 package com.hw.TCP0226; 2 3 import java.io.IOException; 4 import java.io.OutputStream; 5 import java.net.Socket; 6 import java.net.UnknownHostException; 7 import java.util.Scanner; 8 9 @SuppressWar

  7. python进阶(12)闭包

    闭包 首先了解一下:如果在一个函数的内部定义了另一个函数,外部的我们叫他外函数,内部的我们叫他内函数。 在一个外函数中定义了一个内函数,内函数里运用了外函数的 临时变量 ,并且外函数的返回值是内函数的引用。这样就构成了一个闭包。 一般情况下,在

  8. 八大数据类型

    //八大基本数据类型 //整数类 byte n1 = 10;// Byte short n2 = 10; int n3 = 10;//最常用 Integer long n4 = 10L;//long类型后面要加L //浮点类 float n5 = 10.5F;//float类型后面要加F double n6 = 10.5;//最常用 //字符 char name1 = 'a';//char要用单引

  9. Uoj 285 数据分块鸡

    Uoj 285 数据分块鸡 决策单调性+二维数点。 /*{####################### Author ## Gary ## 2021 #######################*/#pragma GCC optimize("Ofast")#includebits/stdc++.h#define rb(a,b,c) for(int a=b;a=c;++a)#define rl(a,b,c) for(int a=b;a=c;-

  10. python进阶(13)装饰器

    装饰器 装饰器放在一个函数开始定义的地方,它就像一顶帽子一样戴在这个函数的头上。和这个函数绑定在一起。在我们调用这个函数的时候,第一件事并不是执行这个函数,而是将这个函数做为参数传入它头顶上这顶帽子,这顶帽子我们称之为 装饰器 。 装饰器的功

每天更新java,php,javaScript,go,python,nodejs,vue,android,mysql等相关技术教程,教程由网友分享而来,欢迎大家分享IT技术教程到本站,帮助自己同时也帮助他人!

Copyright 2020, All Rights Reserved. Powered by 跳墙网(www.tqwba.com)|网站地图|关键词