数据解析
- 数据解析的作用?
- 用来实现聚焦爬虫。
- 网页中显示的数据都是存储在哪里?
- 都是存储在html的标签中或者是标签的属性中
- 数据解析的通用原理是什么?
- 指定标签的定位
- 取出标签中存储的数据或者标签属性中的数据
1. 正则解析
单字符:
. : 除换行以外所有字符
[] :[aoe] [a-w] 匹配集合中任意一个字符
\d :数字 [0-9]
\D : 非数字
\w :数字、字母、下划线、中文
\W : 非\w
\s :所有的空白字符包,括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。
\S : 非空白
数量修饰:
* : 任意多次 >=0
+ : 至少1次 >=1
? : 可有可无 0次或者1次
{m} :固定m次 hello{3,}
{m,} :至少m次
{m,n} :m-n次
边界:
$ : 以某某结尾
^ : 以某某开头
分组:
(ab)
贪婪模式: .*
非贪婪(惰性)模式: .*?
2. 图片解析
- 如何爬取图片数据?
- 方式1:基于requests
- 方式2:基于urllib
- urllib模块作用和requests模块一样,都是基于网络请求的模块。
- 当requests问世后就迅速的替代了urllib模块
- urllib模块作用和requests模块一样,都是基于网络请求的模块。
- 上述两种爬取图片的操作不同之处是什么?
- 使用urllib的方式爬取图片无法进行UA伪装,而requests的方式可以。
#方式1:
img_url = ‘https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=1312059974,1893880587&fm=11&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:
img_url = ‘https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=1312059974,1893880587&fm=11&gp=0.jpg‘
#可以直接对url发起请求且进行持久化存储
urllib.request.urlretrieve(img_url,‘./2.jpg‘)
2.1 使用正则进行图片数据的批量解析爬取
- 分析浏览器开发者工具中Elements和network这两个选项卡对应的页面源码数据有何不同之处?
- Elements中包含的显示的页面源码数据为当前页面所有的数据加载完毕后对应的完整的页面源码数据(包含了动态加载数据)
- network中显示的页面源码数据仅仅为某一个单独的请求对应的响应数据(不包含动态加载数据)
- 结论:如果在进行数据解析的时候,一定是需要对页面布局进行分析,如果当前网站没有动态加载的数据就可以直接使用Elements对页面布局进行分析,否则只可以使用network对页面数据进行分析。
dirName = ‘ImgLibs‘
if not os.path.exists(dirName):
os.mkdir(dirName)
#1.捕获到当前首页的页面源码数据
url = ‘‘
page_text = requests.get(url=url,headers=headers).text
#2.从当前获取的页面源码数据中解析出图片地址
ex = ‘‘
img_src_list = re.findall(ex,page_text,re.S)
for src in img_src_list:
src = ‘http://www.521609.com‘+src
imgPath = dirName+‘/‘+src.split(‘/‘)[-1]
urllib.request.urlretrieve(src,imgPath)
print(imgPath,‘下载成功!!!‘)
3. bs4解析
- bs4解析原理
- 实例化一个BeautifulSoup的对象,且将待解析的页面源码数据加载到该对象中
- 调用BeautifulSoup对象中相关方法或者属性进行标签定位和文本数据的提取
- 环境安装:
- pip install lxml #解析器
- pip install bs4
- BeautifulSoup对象的实例化:
- BeautifulSoup(fp,‘lxml‘):用来将本地存储的html文档中的数据进行解析
- BeautifulSoup(page_text,’lxml‘):用来将互联网上请求到的页面源码数据进行解析
- 标签定位:
- soup.tagName:只可以定位到第一次出现的tagName标签
- soup.find(‘tagName‘,attrName=‘value‘):属性定位
- soup.findAll:跟find一样用作属性定位,只不过findAll返回的是列表
- soup.select(‘选择器‘):选择器定位
- 类选择器
- id选择器
- 层级选择
- 大于号:表示一个层级
- 空格:表示多个层级
- 取数据
- .text:返回的是该标签下所有的文本内容
- .string:返回的是该标签直系的文本内容
- 取属性:
- tag[‘attrName‘]
3.1 爬取三国
from bs4 import BeautifulSoup
import requests
main_url = ‘http://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‘)
for a in a_list:
title = a.string
detail_url = ‘http://www.shicimingju.com‘+a[‘href‘]
#对详情页发起请求解析出章节内容
page_text_detail = requests.get(url=detail_url,headers=headers).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()
4. xpath解析
- 环境安装:
- pip install lxml
- 解析原理:html标签是以树状的形式进行展示
- 1.实例化一个etree的对象,且将待解析的页面源码数据加载到该对象中
- 2.调用etree对象的xpath方法结合着不同的xpath表达式实现标签的定位和数据提取
- 实例化etree对象
- etree.parse(‘filename‘):将本地html文档加载到该对象中
- etree.HTML(page_text):网站获取的页面数据加载到该对象
- 标签定位:
-
最左侧的/:如果xpath表达式最左侧是以/开头则表示该xpath表达式一定要从根标签开始定位指定标签(忽略)
-
非最左侧的/:表示一个层级
-
非左侧的//:表示多个层级
-
最左侧的//:xpath表达式可以从任意位置进行标签定位
-
属性定位:tagName[@attrName="value"]
-
索引定位:tag[index]:索引是从1开始
-
模糊匹配:
- //div[contains(@class, "ng")]
- //div[starts-with(@class, "ta")]
-
- 取文本
- /text():直系文本内容
- //text():所有的文本内容
- 取属性
- /@attrName
4.1 彼岸图
#爬取多页
dirName = ‘GirlsLib‘
if not os.path.exists(dirName):
os.mkdir(dirName)
#定义一个通用的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)
response = requests.get(url=new_url,headers=headers)
response.encoding = ‘gbk‘
page_text = response.text
#图片名称+图片数据
tree = etree.HTML(page_text)
#存储的是定位到的指定的li标签
li_list = tree.xpath(‘//div[@class="slist"]/ul/li‘)
for li in li_list:
# print(type(li)) #li的数据类型和tree的数据类型一样,li也可以调用xpath方法
title = li.xpath(‘./a/img/@alt‘)[0]+‘.jpg‘#进行局部数据解析
img_src = ‘http://pic.netbian.com‘+li.xpath(‘./a/img/@src‘)[0]
img_data = requests.get(url=img_src,headers=headers).content
imgPath = dirName +‘/‘+title
with open(imgPath,‘wb‘) as fp:
fp.write(img_data)
print(title,‘保存成功!!!‘)
注意
: 编码为gbk,二进制数据
5.bs4与xpath对比
- 需求:要求解析出携带html标签的局部数据?
- bs4,bs4在实现标签定位的时候返回的直接就是定位到标签对应的字符串数据
- xpath表达式如何更加具有通用性?
- 在xpath表达式中使用管道符分割的作用,可以表示管道符左右两侧的子xpath表达式同时生效或者一个生效。
#将https://www.aqistudy.cn/historydata/所有的城市名称解析出来
url = ‘https://www.aqistudy.cn/historydata/‘
page_text = requests.get(url=url,headers=headers).text
tree = etree.HTML(page_text)
# hot_cities = tree.xpath(‘//div[@class="bottom"]/ul/li/a/text()‘)
# all_cities = tree.xpath(‘//div[@class="bottom"]/ul/div[2]/li/a/text()‘)
tree.xpath(‘//div[@class="bottom"]/ul/li/a/text() | //div[@class="bottom"]/ul/div[2]/li/a/text()‘)