二、数据解析
数据解析:
1、数据解析概述
1.1 数据解析分类:
* 正则 https://www.jianshu.com/p/5c80a7a874ae
* bs4
* xpath(通用性最强)
1.2 数据解析原理概述:
- 解析的局部的文本内容会在标签之间或者标签对应的属性中进行存储;
- 进行指定的标签定位;
- 标签或者标签对应的属性中存储的数据值进行提取(解析)
2、xpath方式爬数据:
图片数据返回时为二进制形式的数据: ------------ 用 requests.get(xxx).content
文本数据返回为字符串 : ------------ 用 requests.get(xxx).text
json格式数据返回: ----------- 用 requests.get(xxx).json
2.1 xpath 解析原理:
- 1.实例化一个etree的对象,并需要将被解析的页面源码数据加载到该对象中;
- 2.调用etree对象中的xpath方法结合着xpath表达式实现标签的定位和内容的捕获;
环境安装:
--- pip install lxml
如何实例化一个etree对象: from lxml import etree?
1.将本地的html文档中的源码数据加载到etree对象中;
- tree = etree.parse(filePath,etree.HTMLParser())
2.可以将从互联网上获取到的源码数据加载到该对象中;
- tree = etree.HTML('page_text')
2.2 xpath 表达式:
https://blog.csdn.net/qq_1290259791/article/details/85864041
https://www.jianshu.com/p/85a3004b5c06
路径表达式:
- / :表示的是从根节点开始定位。表示的是一个层级。
- //:表示的是多个层级。可以表示从任意位置定位标签元素。
# 高级用法:
html = etree.HTML(text)
# 获取第一个
result = html.xpath('//li[1]/a/text()')
print(result)
# 获取最后一个
result = html.xpath('//li[last()]/a/text()')
print(result)
# 获取前两个
result = html.xpath('//li[position()<3]/a/text()')
print(result)
# 获取倒数第三个
result = html.xpath('//li[last()-2]/a/text()')
print(result)
未知结点:
/store/*
:选取store
所有子元素//*
:选取文档所有元素//title[@*]
:选取带有属性的title
元素
属性、文本高级用法:
-
属性定位: tree.xpath('tag[@attrName="attrValue"]')
-
索引定位: tree.xpath('tag[@attrName="attrValue"]/p[3]') 注意索引是从1开始的
-
取文本:tree.xpath('tag'[@attrName="attrValue"]//li[5]/a/text()')[0]
- /text() : 获取的是标签中直系的文本内容
- //text():获取的是标签下所有的文本内容
-
取属性: /@attrName ==> tree.xpath('tag[@attrName="attrValue"']/a/img/@src')[0]
-
属性多值匹配(contains):
//title[contains(text,'cn')]
查询text
节点值中带有cn
字符串的title
节点- and、not、count、concat、string用法:
//title[contains(text,'cn') and contains(@ID, '1')]
查询所有text
节点值中带有cn
字符串并且属性ID
值中有1
的title
节点title[not(@data)]
不包含data
属性的title节点count(//title)
统计title
节点的数量concat(//title[@data="one"]/text(),//title[@data="three"]/text())
字符串链接string(//title)
解析第一个匹配到节点下的值
3、xpath实战案例:
3.1 xpath数据解析之 58二手房数据爬取:
# 58二手房数据解析
import requests
from lxml import etree
if __name__ == '__main__':
# 1.爬取页面数据
url='https://www.58.com/ershoufang/'
headers={
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36'
}
response=requests.get(url,headers).text
# 2.生成etree对象解析数据
tree=etree.HTML(response)
# 3.定位获取到房源的名称信息
houses=tree.xpath('//div[@class="cb"]//table//tr')
fp=open('./58_houses.txt','w',encoding='utf-8')
for one in houses:
house_name=one.xpath('./td[2]/a/text()')[0]
# 持久化存储
fp.write(house_name)
3.2 xpath数据解析之 下载4k图片:
(1). 爬取数据中文乱码的解决方案:
- 首先可以尝试对相应结果 response 进行整体编码为 utf-8 形式,但是注意需要在对responses解析前进行;
response.encoding='utf-8'
如果上述方法不行那么就可以尝试对乱码的结果数据进行处理,在解析数据完成时进行:
ima_name = img_name.encode('iso-8859-1').decode('gbk')
各种编码的转换问题: https://blog.csdn.net/kelindame/article/details/75014485
!注意:以上两种方式不能同时使用,因为在response.encoding = 'utf-8' 时将编码设置为了 utf-8,而在之后又修改为 iso-8859-1 , 而 utf-8为定长编码,iso-8859-1为单字节码,从utf-8转化为 iso-8859-1相当于高精度转化为低精度,造成精度丢失。
(2). 爬取数据的持久化存储----存储到文件夹操作:
判断文件夹/文件 是否存在:
os.path模块主要用于文件的属性获取,exists是“存在”的意思,所以顾名思义,os.path.exists()就是判断括号里的文件是否存在的意思,括号内的可以是文件路径。
import os path = os.path.exists('user.py') print(path)
创建文件夹:
os.mkdir(path)
# 彼岸桌面照片爬取下载本地
import requests
from lxml import etree
import os
if __name__ == '__main__':
# 1.爬取页面数据
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/85.0.4183.121 Safari/537.36 Edg/85.0.564.63'
}
responses=requests.get(url,headers)
page_data=responses.text
# 2.xpath解析数据
tree=etree.HTML(page_data)
photos=tree.xpath('//div[@class="slist"]/ul/li')
# 创建收录图片的文件夹
if not os.path.exists('./bian_photo'):
os.mkdir('./bian_photo')
# 指定每张图片的url,请求图片返回二进制数据
for photo in photos:
img_src='http://pic.netbian.com/'+photo.xpath('./a/img/@src')[0]
img_name=photo.xpath('./a/img/@alt')[0]+'.jpg'
img_name=img_name.encode('iso-8859-1').decode('gbk')
img_path='./bian_photo/'+img_name
#发送请求----content
image_datas=requests.get(img_src,headers).content
#持久化数据
with open(img_path,'wb') as fp:
fp.write(image_datas)
print(img_name,"下载成功!")
3.3 xpath数据解析之 爬取全国城市名:
# 爬取全国城市名
import requests
from lxml import etree
if __name__ == '__main__':
# 1.爬取数据
url='https://www.aqistudy.cn/historydata/'
headers={
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36 Edg/85.0.564.63'
}
responses=requests.get(url,headers).text
# 2.数据解析---获取热门城市名+全国城市名
tree=etree.HTML(responses)
# 热门城市
# hot_citys_name=[]
# hot_citys_lis=tree.xpath('//div[@class="hot"]/div[@class="bottom"]/ul/li')
# for city in hot_citys_lis:
# hot_citys_name.append(city.xpath('./a/text()')[0])
# print(hot_citys_name)
# # 全部城市
# all_citys_name=[]
# all_citys_uls=tree.xpath('//div[@class="all"]/div[@class="bottom"]/ul')
# for city_ul in all_citys_uls:
# city_lis=city_ul.xpath('./div[2]/li')
# for city in city_lis:
# all_citys_name.append(city.xpath('./a/text()')[0])
# print(all_citys_name)
# 3.获取热门城市+全国城市 的href
city_hrefs=[]
citys=tree.xpath('//div[@class="bottom"]/ul/li | //div[@class="bottom"]/ul/div[2]/li')
for city in citys:
href=city.xpath('./a/@href')[0]
city_hrefs.append(href)
print(city_hrefs)