数据解析
- 正则
- bs4
- xpath
- pyquery(自学,通用性不强)
正则解析
格式(规范)
使用正则进行图片数据的批量解析爬取1️⃣
前提知识:爬取图片数据的两种方式
-
方式1:基于requests
img_url="https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=3205720277,4209513487&fm=26&gp=0.jpg" response = requests.get(url=img_url,headers=headers) img_data = response.content #content返回的是二进制形式的响应数据 with open('1.jpg','wb') as fp: fp.write(img_data)
-
方式2:基于urllib
- urllib模块作用和requests模块一样,都是基于网络请求的模块
- 当requests问世后就迅速地替代了urllib模块
img_url="https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=3205720277,4209513487&fm=26&gp=0.jpg" #可以直接对url发起请求且进行持久化存储 urllib.request.urlretrieve(img_url,'./2.jpg')
- urllib模块作用和requests模块一样,都是基于网络请求的模块
上述爬图片的不同之处
- 使用urllib的方式爬取图片无法进行UA伪装,而requests的方式可以
需求:爬取校花网(已过期)中的图片数据
- 操作:需要将每一张图片的地址解析出来,然后对图片地址发起请求即可。
浏览器开发者工具中Elements和network这两个选项卡对应的页面源码数据的不同之处
- Elements中包含的显示的页面源码数据为当前页面所有的数据加载完毕后对应的完整的页面源码数据(包含了动态加载数据)
- network中显示的页面源码数据仅仅为某一个单独的请求对应的响应数据(不包含动态加载数据)
- 结论:如果在进行数据解析的时候,一定是需要对页面布局进行分析,如果当前网站没有动态加载的数据就可以直接使用Elements对页面布局进行分析,否则只可以属于network对页面数据进行分析
知识点
- 利用os进行文件夹的创建
- 利用urllib保存图片到相应文件夹
- 正则表达式
#正则包
import re
import os
dirName="imgLibs"
if not os.path.exists(dirName):
os.make(dirName)
#1.捕获到当前首页的页面源码数据
url = ''
page_text = requests.get(url=url,headers=headers).text
#2.从当前获取的页面源码数据中解析出图片地址
ex = '<li>.*?<img src="(.*?)" width=.*?</li>'
#若文本本身有换行,用re.S处理换行和回车
img_sec_list = re.findall(ex,page_text,re.S)
for src in img_src_list:
src = '...'+src
imgPath = dirName + '/' +src.split('/')[-1]
urllib.request.urlretrieve(src,imgPath)
print(imgPath,'下载成功')
数据解析概念
作用
- 用来实现聚焦爬虫
网页中显示的数据都是存储在哪里?
- 都是存储在HTML的标签中或者是标签的属性中
通用原理
- 指定标签的定位
- 取出标签中存储的数据或者标签属性中的数据
bs4
bs4解析原理
基于通用原理
- 实例化一个BeautifulSoup的对象,且将待解析的页面源码数据加载到该对象中
- 调用BeautifulSoup对象中的相关方法或者属性进行标签定位和文本数据的提取
环境
lxml,bs4
用法2️⃣
BeautifulSoup对象的实例化
- BeautifulSoup(fp(本地文件),‘lxml’):用来将本地存储的html文档中的数据进行解析
- BeautifulSoup(page_text,‘lxml’):用来将互联网上请求到的页面源码数据进行解析
标签定位
注:soup为BeautifulSoup对象
-
soup.tagName
只可以定位到第一次出现的tagName标签
-
soup.find('tagName',attrName='value')
属性定位
例如:
soup.find('div',class_='song')
soup.find('a',id='feng')
-
soup.findAll()
跟find一样用作属性定位,只不过findAll返回的是列表
例如:
soup.findAll('a',id='feng')
-
soup.select('选择器')
- 常用的选择器
- 类选择器(.)
- id选择器(#)
- 层级选择器
- >:表示一个层级
- 空格:表示多个层级
例如:
定位所有的li标签
soup.select('.tang > ul > li')
或soup.select('.tang li)
- 常用的选择器
取数据
-
.text
返回的是该标签下所有的文本内容,包括子内容的内容,例如:
<div> <p>内容1</p> <p>内容2</p> </div>
-
.string
返回的是该标签直系的文本内容,上面的例子取为空
取属性
tag['attrName']
bs4案例:爬取三国全篇内容3️⃣
url: https://www.shicimingju.com/book/sanguoyanyi.html
#该网站不是动态加载的
main_url = 'https://www.shicimingju.com/book/sanguoyanyi.html'
response = requests.get(url=main_url,headers=headers)
response.encoding='utf-8'
page_text = response.text
fp = open('./sanguo.txt','w',encoding='utf-8')
#数据解析:章节标题,详情页url,章节内容
soup = BeautifulSoup(page_text,'lxml')
#定位到的所有符合要求的a标签
a_list = soup.select('.book-mulu > ul > li > a')
#print(a_list)
for a in a_list:
title = a.string
detail_url = 'https://www.shicimingju.com' + a['href']
#对详情页发起请求解析出章节内容
response = requests.get(url=detail_url,headers=headers)
response.encoding='utf-8'
page_text_detail = response.text
soup = BeautifulSoup(page_text_detail,'lxml')
div_tag = soup.find('div',class_="chapter_content")
content = div_tag.text
fp.write(title+':'+content+'\n')
print(title,'保存成功!!!')
fp.close()
xpath解析
环境
lxml
解析原理
html标签是以树状的形式进行展示
- 实例化一个etree对象,且将待解析的页面源码数据加载到该对象中
- 调用etree对象的xpath方法结合着不同的xpath表达式实现标签的定位和数据提取
用法4️⃣
实例化etree对象
-
etree.parse('filename')
将本地html文档加载到该对象中
-
etree.HTML(page_text)
网上获取的页面数据加载到该对象
标签定位
#定位meta
tree.xpath('/html/head/meta')
#或者tree.xpath('/html//meta')
#或者tree.xpath('//meta')
-
最左侧的 / (一般不用)
如果xpath表达式最左侧是以 / 开头则表示该path表达式一定要从根标签开始定位指定标签
-
最左侧的 //
xpath表达式可以从任意位置进行标签定位
-
非最左侧的 /
表示一个层级
-
非最左侧的 //
表示多个层级
-
属性定位
tagName[@attrName="xx"]
例如:
tree.xpath('//div[@class="song"]/p')
-
索引定位
索引是从1开始
tag[index]
例如:
tree.xpath('//div[@class="song"]/p[2]')
-
模糊匹配(不常用)
例如:
div[contains(@class,"ng")]
div[starts-with(@class,"ta")]
取文本
-
/text()
直系文本内容
例如:
tree.xpath('//div[@class="song"]/p[1]/text()')
-
//text()
所有文本内容
取属性
-
/@attrName
例如:
tree.xpath('//a[@id="feng"]/@href')
局部数据解析
-
要将定位到的页面中的标签作为待解析的数据,再次使用xpath表达式解析待解析的数据。
例如:li的数据类型和tree的数据类型一样,li也可以调用xpath方法
-
在局部数据解析的时候,xpath表达式中要使用 ./或者.// 的操作。
./ 表示的就是当前的局部数据(xpath的调用者)
xpath案例:使用xpath爬取图片名称和图片数据5️⃣
url: http://pic.netbian.com/4kmeinv/
总结
-
换页(利用format)
#定义一个通用的url模板:不可变 url = 'http://pic.netbian.com/4kmeinv/index_%d.html' for page in range(1,6): if page == 1: new_url = 'http://pic.netbian.com/4kmeinv/' else: new_url = format(url%page)
-
获得图片路径
#解析图片名称+图片数据 tree = etree.HTML(page_text) #存储的是定位到的指定的li标签 li_list = tree.xpath('//div[@class="slist"]/ul/li') for li in li_list: #xpath返回的是列表,[0]表示的是取列表的第0个,即['文本']转为'文本' title = li.xpath('./a/img/@alt')[0]+'.jpg' #进行局部数据解析 img_src = 'http://pic.netbian.com' + li.xpath('./a/img/@src')[0]
-
xpath表达式可以直接复制
例如://*[@id=“main”]/div[3]/ul/li[4]/a/img
bs4与xpath区别
如果要解析出携带html标签的局部数据:
bs4可以在实现标签定位的时候返回的直接就是定位到该标签对应的字符串数据
xpath表达式如何更加具有通用性?
-
在xpath表达式中使用**管道符(|)**分割的作用,可以表示管道符左右两侧的子xpath表达式同时生效或者一个生效
案例:将https://www.aqistudy.cn/historydata/所有的城市名称解析出来6️⃣
作业:爬取前5页的图片和简历
联系数据解析bs4或xpath
url:
- https://sc.chinaz.com/tupian/
- https://sc.chinaz.com/jianli/