1. 数据解析概述
数据解析:是指对网页中指定的内容进行提取的过程
数据解析分类:
- 正则数据解析
- bs4数据解析
- xpath数据解析
数据解析原理:
- 解析局部的文本内容都会在标签之间或者标签对应的属性中进行存储
- 数据解析要先进行指定标签的定位
- 然后对标签或者标签对应的属性中存储的数据进行存储(解析)
数据解析编码流程:
- 指定url
- 发起请求
- 获取响应数据
- 数据解析
- 持久化存储
2. 数据解析--正则表达式
用正则表达式进行数据解析步骤:
- 使用通用爬虫对url对应的一整张页面进行爬取
- 找出要爬取图片或文本所在位置的通用格式
- 使用正则表达出所爬取内容的通用表达式
- 使用re.findall()找到符合表达式所有内容
- 完成爬取内容的输出或保存
注意:图片使用.content,content返回的是二进制形式的数据解析;text返回的是字符串形式,json返回的是对象形式
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import requests
import re
import os
#需求:爬取糗事百科中糗图板块下所有的糗图图片
if __name__ == "__main__":
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36'
}
#创建一个文件夹,保存所有的图片
if not os.path.exists('./qiutuLibs'):
os.mkdir('./qiutuLibs')
#设置一个通用的url模板
url = 'https://www.qiushibaike.com/pic/page/%d/?s=5184961'
# pageNum = 2
for pageNum in range(1,3):
#对应页码的url
new_url = format(url%pageNum)
#使用通用爬虫对url对应的一整张页面进行爬取
page_text = requests.get(url=new_url,headers=headers).text
#使用聚焦爬虫将页面中所有的糗图进行解析/提取
ex = '.*?'
img_src_list = re.findall(ex,page_text,re.S)
# print(img_src_list)
for src in img_src_list:
#拼接出一个完整的图片url
src = 'https:'+src
#请求到了图片的二进制数据
img_data = requests.get(url=src,headers=headers).content
#生成图片名称
img_name = src.split('/')[-1]
#图片存储的路径
imgPath = './qiutuLibs/'+img_name
with open(imgPath,'wb') as fp:
fp.write(img_data)
print(img_name,'下载成功!!!')
3. 数据解析--bs4
只能用于Python中,其他语言不能使用bs4数据解析
bs4数据解析原理:
- 实例化一个BeautifulSoup对象,并且将页面源码数据加载到该对象中
- 通过调用BeautifulSoup对象中相关的属性或者方法进行标签定位和数据提取
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import requests
from bs4 import BeautifulSoup
#需求:爬取三国演义小说所有的章节标题和章节内容http://www.shicimingju.com/book/sanguoyanyi.html
if __name__ == "__main__":
#对首页的页面数据进行爬取
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36'
}
url = 'http://www.shicimingju.com/book/sanguoyanyi.html'
page_text = requests.get(url=url,headers=headers).text
#在首页中解析出章节的标题和详情页的url
#1.实例化BeautifulSoup对象,需要将页面源码数据加载到该对象中
soup = BeautifulSoup(page_text,'lxml')
#解析章节标题和详情页的url
li_list = soup.select('.book-mulu > ul > li')
fp = open('./sanguo.txt','w',encoding='utf-8')
for li in li_list:
title = li.a.string
detail_url = 'http://www.shicimingju.com'+li.a['href']
#对详情页发起请求,解析出章节内容
detail_page_text = requests.get(url=detail_url,headers=headers).text
#解析出详情页中相关的章节内容
detail_soup = BeautifulSoup(detail_page_text,'lxml')
div_tag = detail_soup.find('div',class_='chapter_content')
#解析到了章节的内容
content = div_tag.text
fp.write(title+':'+content+'\n')
print(title,'爬取成功!!!')
4. 数据解析--xpath解析
4.1 xpath解析概述
xpath解析:是最常用且最便捷高效的一种解析方式,通用性非常高
xpath解析原理:
- 实例化一个etree的对象,且需要将被解析的页面源码数据加载到该对象中
- 调用etree对象中的xpath方法结合着xpath表达式实现标签的定位和内容的捕获
如何实例化一个etree对象:from lxml import etree
- 将本地的html文档中的源码数据加载到etree对象中:etree.parse(filePath)
- 可以将从互联网上获取的源码数据加载到该对象中:etree.HTML('page_text')
xpath('xpath表达式'):
- /:表示的是从根节点开始定位,表示的是一个层级
- //:表示的是多个层级,可以表示从任意位置开始定位
#下面三者表示相同:html标签中的所有div标签
xpath('/html/body/div')
xpath('/html//div')
xpath('//div')
- 属性定位:通用格式为tag[@attrName="attrValue"]
#定位到属性为'song'的div标签下
xpath('//div[@class="song"]')
- 索引定位://div[@class="song"]/p[3],索引是从1开始的
#定位到属性为'tang'的div标签下的第5个li标签
xpath('//div[@class="tang"]//li[5]')
- 取文本:
- /text():获取的是标签中直系的文本内容
- //text():标签中非直系的文本内容(所有的文本内容)
#返回的是列表类型数据
xpath('//div[@class="tang"]//li[5]/a/text()')[0]
xpath('//li[7]//text()')
xpath('//div[@class="tang"]//text()')
- 取属性:通用格式为/@attrName
#定位到属性为'song'的div标签下的img标签的src属性
xpath('//div[@class="song"]/img/@src')
4.2 使用方法
案例一:58二手房
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import requests
from lxml import etree
#需求:爬取58二手房中的房源信息
if __name__ == "__main__":
headers = {
'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36'
}
#爬取到页面源码数据
url = 'https://bj.58.com/ershoufang/'
page_text = requests.get(url=url,headers=headers).text
#数据解析
tree = etree.HTML(page_text)
#存储的就是li标签对象
li_list = tree.xpath('//ul[@class="house-list-wrap"]/li')
fp = open('58.txt','w',encoding='utf-8')
for li in li_list:
#局部解析 ./代表从当前标签下开始解析
title = li.xpath('./div[2]/h2/a/text()')[0]
print(title)
fp.write(title+'\n')
案例二:解析下载图片数据
#!/usr/bin/env python
# -*- coding:utf-8 -*-
#需求:解析下载图片数据 http://pic.netbian.com/4kmeinv/
import requests
from lxml import etree
import os
if __name__ == "__main__":
url = 'http://pic.netbian.com/4kmeinv/'
headers = {
'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36'
}
response = requests.get(url=url,headers=headers)
#手动设定响应数据的编码格式
# response.encoding = 'utf-8'
page_text = response.text
#数据解析:src的属性值 alt属性
tree = etree.HTML(page_text)
li_list = tree.xpath('//div[@class="slist"]/ul/li')
#创建一个文件夹
if not os.path.exists('./picLibs'):
os.mkdir('./picLibs')
for li in li_list:
img_src = 'http://pic.netbian.com'+li.xpath('./a/img/@src')[0]
img_name = li.xpath('./a/img/@alt')[0]+'.jpg'
#通用处理中文乱码的解决方案
img_name = img_name.encode('iso-8859-1').decode('gbk')
# print(img_name,img_src)
#请求图片进行持久化存储
img_data = requests.get(url=img_src,headers=headers).content
img_path = 'picLibs/'+img_name
with open(img_path,'wb') as fp:
fp.write(img_data)
print(img_name,'下载成功!!!')
案例三:全国城市名称爬取
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import requests
from lxml import etree
#项目需求:解析出所有城市名称https://www.aqistudy.cn/historydata/
if __name__ == "__main__":
# headers = {
# 'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36'
# }
# url = 'https://www.aqistudy.cn/historydata/'
# page_text = requests.get(url=url,headers=headers).text
#
# tree = etree.HTML(page_text)
# host_li_list = tree.xpath('//div[@class="bottom"]/ul/li')
# all_city_names = []
# #解析到了热门城市的城市名称
# for li in host_li_list:
# hot_city_name = li.xpath('./a/text()')[0]
# all_city_names.append(hot_city_name)
#
# #解析的是全部城市的名称
# city_names_list = tree.xpath('//div[@class="bottom"]/ul/div[2]/li')
# for li in city_names_list:
# city_name = li.xpath('./a/text()')[0]
# all_city_names.append(city_name)
#
# print(all_city_names,len(all_city_names))
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36'
}
url = 'https://www.aqistudy.cn/historydata/'
page_text = requests.get(url=url, headers=headers).text
tree = etree.HTML(page_text)
#解析到热门城市和所有城市对应的a标签
# //div[@class="bottom"]/ul/li/ 热门城市a标签的层级关系
# //div[@class="bottom"]/ul/div[2]/li/a 全部城市a标签的层级关系
# 使用'|'可以对两者进行同时解析
a_list = tree.xpath('//div[@class="bottom"]/ul/li/a | //div[@class="bottom"]/ul/div[2]/li/a')
all_city_names = []
for a in a_list:
city_name = a.xpath('./text()')[0]
all_city_names.append(city_name)
print(all_city_names,len(all_city_names))