前言:
上次学习过了
BeautifulSoup
进行解析的,这次就来学习一下
Xpath
进行解析
0x00:了解Xpath
Xpath
解析:最常用且最高效的一种解析方式
Xpath解析原理:
——1.实例化一个etree对象,且需要将解析的页面源码数据加载到该数据中。
——2.调用etree对象中的xpath方法结合xpath表达式实现标签的定位和内容的捕获
如何实例化一个etree对象
——1.将本地的html文档中的源码数据加载到etree对象中:
etree.parse(filePath)
——2.可以将从互联网上获取的源码数据加载到该对象中:
etree.HTML('page_text')
——xpath('xpath表达式')
xpath表达式
—— /:表示的是从根节点开始定位,表示的是一个层级。
—— // :
表示的是多个层级,可以从任意位置开始定位
—— 属性定位:
//div[@class='dingpai']
tag[@attrName="attrValue"]
——索引定位:
//div[@class="dingpai"]/p[3] 索引是从1开始的
——取文本:
—— /test() 获取的是标签中直系的文本内容
—— //test()
——取属性:
/@attrName
//div[@class="dingpai"]//a[1]/@href
测试文本:
>
练习代码:
import requests
from lxml import etree
if __name__ == '__main__':
#实例化一个etree对象,且将被解析的源码加载到该对象中
tree = etree.parse('test.html')
# r = tree.xpath('/html/div/li')
# r = tree.xpath('/html//li')
# r = tree.xpath('//li')
# r = tree.xpath('//div[@class="dingpai"]')
# r = tree.xpath('//div[@class="dingpai"]/p[3]')
#加[0]是为了得到字符串
# r = tree.xpath('//div[@class="dingpai"]/li/a[3]/text()')[0]
# r = tree.xpath('//a[3]//text()')
# r = tree.xpath('//div[@class="dingpai"]//a[1]/@href')[0]
print(r)
0x01:爬取58二手房房源信息
这次就使用Xpath来爬取一下58同城房源的标题
通过分析会发现这样的层级关系,各个房源的信息标题都存在这个层级之中
ul class="house-list-wrap">li>div class="list-info">h2 class="title">a
分析好之后,便可以使用
xpath
来进行解析
import requests
from lxml import etree
if __name__ == '__main__':
url = 'https://jiaozuo.58.com/ershoufang/'
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36'
}
content = requests.get(url=url,headers=headers).text
#数据解析
tree = etree.HTML(content)
#存储的是li标签的对象
li_list = tree.xpath('//ul[@class="house-list-wrap"]/li')
fp = open('58.txt','w',encoding='utf-8')
for li in li_list:
#从li标签开始调用
#./表示的是局部的li标签,直接定位到局部
title = li.xpath('./div[2]/h2/a/text()')[0]
# print(title)
price = li.xpath('./div[3]/p/b/text()')[0]
print(price+"万")
fp.write(title+price+'万'+'\n')
这样最需要注意的便是这个
./
,这个可以直接定位到当前的
li
标签而如果使用
//
的话就又从跟目录解析了
爬取成功
0x02:爬取4K超清壁纸
利用Xpath来爬取4K超强壁纸,首先还是需要分析一下:
我们需要爬取是图片的链接和名称,F12可以看到层级关系是这样的
div class="slist" >ul>li>a
分析一个其他用循环即可,下面就来写出爬取脚本:
import requests
from lxml import etree
if __name__ == '__main__':
url = 'http://pic.netbian.com/4kdongman/'
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36'
}
repose = requests.get(url=url,headers=headers).text
#进行实例化
tree = etree.HTML(repose)
#得到所有的li列表
li_list = tree.xpath('//div[@class="slist"]/ul/li')
for li in li_list:
#得到图片的url,但这里不是完整的,所以需要拼接一下
img_url = 'http://pic.netbian.com'+li.xpath('./a/img/@src')[0]
#得到图片的名称
imge_name = li.xpath('./a/img/@alt')[0]+'.jpg'
print(imge_name+':'+img_url)
这样就可以得到图片的链接和名称了,但是出现了一个问题
名称发生了乱码,这里就需要自己手动设置响应数据的编码格式了
repose = requests.get(url=url,headers=headers)
#手动进行设置响应数据的编码格式
repose.encoding = 'gbk'
page_txt = repose.text
这是第一种方法,对整体的响应数据设置特定的编码格式
#通用处理中文乱码的解决方法
image_name = imge_name.encode('iso-8859-1').decode('gbk')
接下来就只需请求图片的
url
,进行爬取即可
import requests
from lxml import etree
import os
if __name__ == '__main__':
url = 'http://pic.netbian.com/4kdongman/'
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36'
}
repose = requests.get(url=url,headers=headers)
#手动进行设置响应数据的编码格式
repose.encoding = 'gbk'
page_text = repose.text
#进行实例化
tree = etree.HTML(page_text)
#得到所有的li列表
li_list = tree.xpath('//div[@class="slist"]/ul/li')
#创建一个文件夹
if not os.path.exists('pic'):
os.mkdir('pic')
for li in li_list:
#得到图片的url,但这里不是完整的,所以需要拼接一下
img_url = 'http://pic.netbian.com'+li.xpath('./a/img/@src')[0]
#得到图片的名称
imge_name = li.xpath('./a/img/@alt')[0]+'.jpg'
#通用处理中文乱码的解决方法
# image_name = imge_name.encode('iso-8859-1').decode('gbk')
# print(imge_name,img_url)
#请求图片,持久化存储.二进制数据用content
img_data = requests.get(url=img_url,headers=headers).content
#图片路径
img_path = 'pic/'+imge_name
#进行IO操作,将图片存储到文件夹中
with open(img_path,'wb') as fp:
fp.write(img_data)
print(imge_name,"下载成功")
爬取成功
(PS:看看就行,分辨率太小)
0x03:使用|运算符获取相同信息
在爬取的过程中就会发现
爬取相同的信息
(如热门城市和全部城市),但信息分别位于不同的标签中,如果我们使用两个语句去进行解析,在这个过程还要再次循环,效率有点低。遇到这种问题便可以使用如下这种语句
#div/ul/li/a热门城市a标签的层级关系
#div/ul/div[2]/li/a全部城市a标签的层级关系
使用一行代码解析全部
tree.xpath('//div/ul/li/a | div/ul/div[2]/li/a')
中间添加一个|运算符进行分割即可获取全部
0x04:爬取各个城市的空气质量
分析和之前一样,就不再叙述
import requests
from lxml import etree
if __name__ == '__main__':
url = 'http://www.tianqi.com/air/?o=desc'
headers = {
'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36'
}
reponse = requests.get(url=url,headers=headers).text
#实例化一个对象
tree= etree.HTML(reponse)
#解析出所有的li标签列表
li_list = tree.xpath('//div[@class="wrapbox newsmain"]//ul[@class="aqi_ranklist"]/li')
fp = open('城市空气质量.txt','w',encoding='utf-8')
for li in li_list:
city_sort = li.xpath('./span[1]/text()')[0]
# print(city_sort)
city_name = li.xpath('./span/a/text()')[0]
# print(city_name)
city_province = li.xpath('./span[3]/text()')[0]
# print(city_province)
city_air = li.xpath('./span[4]/text()')[0]
# print(city_air)
air_condition = li.xpath('./span[5]/i/text()')[0]
# print(air_condition)
fp.write(city_sort+' '+city_name+' '+city_province+' '+city_air+' '+air_condition+'\n')
print(city_sort+' '+city_name+' '+city_province+' '+city_air+' '+air_condition+'\n')
print('Over!')
爬取成功
总结
这次就学习到这里,有空继续学习!!!