Xpath解析,是我们爬虫解析的另外一种方式,它可以帮助我们针对XML,HTML类型的数据进行比较方便的筛选。类似于我们的文件路径操作,下面我将对它进行一个初步的介绍
我们先自己写了一个xml的数据,book作为我们最大的集,类似于我们html中div包含各种子集的用法。下面我们将对这个xml进行数据的相关操作
首先在终端中导包 Pip install lxml
接着我们在py文件中进行操作
参考上面的代码,我们先从lxml中导入我们的etree模块,这个模块可以帮助我们,将我们的字符串进行类的转换,变成我们的etree对象,就类似于我们之前的bs4操作中的beautifulsoup操作。然后我们的etree模块中又有着很多的功能,比如我们的xml()函数,和html()函数,这种操作我认为是等同于bs4.BeautifulSoup()操作的,这里就不进行详细的说明。
接着我们对上面的内容进行打印操作,得到结果如下:
结果1. etree.XML(xml) 成功地帮我们把字符串类型的数据转化成了etree类型
结果2.我们用tree.xpath() 方法,用文件的类似操作,规定了我们需要选择的路径 ("/book/name/text()")
这种表明我们需要寻找book目录下的,name目录下的文本,于是我们就返回了野花这个数据。
【attention】. 1.我们的括号中(“/book”)要有前面的“/”不然return的是一个空的列表
2.(“/text()”) 进行获取文本操作的时候要对text()加上括号(),不然会认为是要text标签
3.我们的return 值是一个列表类型的数据,非常的方便
1.现在我们提出疑问,我们想要获得nick数据中的人名该怎么办?
第一个问题比较简单,我们直接 tree.xpath("/book/auther/nick/text()")
它就会return 一个 【“胡肖安”,“印象这”,“李迎春”,“郭祥顺”】这样的一个列表数据
2上面我们的xml结构比较简单,但我们的xml结构数据稍微复杂一点,类似于我们下面这种情况,我们又该怎么获取数据呢?
A.获取所有的人名数据
如果我们还要按照上面的方法来写,我们肯定不能一次获得所有的数据,因为我们的人名的分布结构不一样。于是我们定义了一个//的方法,就是获得所有的子集元素。参考下面的代码
List_name = tree.xpath("/book/auther//nick/text()") //这种就是获得auther子集下,所有的nick名称数据
我们打印list_name的化,结果就会是我们【“胡肖安”,“印象这”,“李迎春”,“郭祥顺”,“周杰伦”,“黄1”,“黄2”】 这样的数据
B.获取我们div中的黄1,黄2,不要其他的
如果我们按照最开始的方法来写,比如xpath(“/book/auther/div/div/nick/text()”)我们确实可以完成目的,但是如果我们的黄2是<span>标签包裹的或者我们的auther的一级目录不是div,那我们的写法就要更新。这样就很麻烦,于是我们就增加了*的目录方法,*可以指代我们的所有元素
xpath(“/book/auther/*/*/nick/text()”) 就会返回我们所要求的两级目录下的数据,且*不能为空字符
接下来我们通过一个实例,来对我们上面的内容进行提高学习,以猪八戒网的网页内容进行分析
要求: 在网站的搜索栏中输入我们的信息,针对这个信息我们的python要获取这个产品的价格,标题,网址,以及这个产品的相关评分
整体分析上面的要求,我们首先要获取这个网站的整体源代码,然后我们要在网站的源代码中筛选出对我们有用的相关信息,比如网站的标题,价格和网址,然后我们要根据网站的网址来进行二次爬取,获得网址对应的源代码中的用户评分
现在针对上面的分析我们进行一步一步的尝试:
Import requests
From lxml import etree
1.获取页面的整体数据:
我们还是通过requests的方法,获得我们的页面的整体源代码,不进行过多的描述
2.筛选出我们需要的相关内容
分析思路
由于我们本次使用的是lxml中的etree方法,我们肯定先要将我们的源代码的str类型转化成我的etree对象,然后我们针对这个etree对象进行后续的path操作,对于我们需要的path我们可以查看页面的源代码进行获取,先获得一个的path,然后将path中最后的标签中的【0】给删除掉,所得到的就是我们的整体的divs列表,里面存放了我们需要的每一个div元素,形成了【div,div,div】的存储形式,然后我们对这个列表进行for循环,继续xpath抓取,就能获得我们所需要的元素,针对每一个元素进行重复的操作,我们就能获得我们需要的整体信息
1.获得一个div的path
结果如下: divs中有的是每一个div的列表数据【div,div,div】其中每一个div对应的就是我们每一个商品
2.针对每一个div操作,并进行存放和打印处理
每一个div中,我们对其进行了xpath的操作,获得了我们需要的数据,其中xpath的路径在原来的路径上./了一下,思路和我的总思路一样,由于爬取的时间较长,我们新增了一个printf方法告诉我爬取的进度
最后运行结果如下:
源代码:
Impor trequests
from lxm limportetree
headers={
"User-Agent":'Mozilla/5.0(WindowsNT10.0;Win64;x64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/116.0.0.0Safari/537.36Edg/116.0.1938.62'
}
html=requests.get('https://www.zbj.com/fw/?k=SAAS',headers=headers)
html.encoding='utf-8'
tree=etree.HTML(html.text)
divs=tree.xpath('//*[@id="__layout"]/div/div[3]/div/div[4]/div/div[2]/div[1]/div')
list1=[]
id=1
fordivindivs:
dic1={}
name=div.xpath('./div/div[3]/div[2]/a/text()')
price=div.xpath('./div/div[3]/div[1]/span/text()')
href=div.xpath('./div/div[2]/a/@href')
data=requests.get(url=href[0],headers=headers)
data.encoding='utf-8'
tree_pin=etree.HTML(data.text)
fen_fen=tree_pin.xpath('//*[@id="eval"]/div[2]/div[1]/p[2]/text()')
dic1['id']=id
dic1['name']=name
dic1['price']=price
dic1['href']=href[0]
dic1['大众评分']=fen_fen
print(f'完成第{id}个')
list1.append(dic1)
id+=1
foriinlist1:
print(i)