第三章:数据解析
分类:
- 正则法
- bs4
- xpath(通用性较强)
数据解析原理概述:
- 解析的局部的文本内容都会在标签之间或者标签对应的属性中进行存储
- ①进行指定标签的定位
- ②标签或者标签对应的属性中存储的数据进行提取(解析)
回顾—— 聚焦爬虫:
爬取页面中指定的页面内容;而获得相应的数据信息之后的处理我们就称之为数据解析。
编码流程
- 指定url
- 发起请求
- 获取响应数据
- 数据解析
- 持久化存储
3.1正则法
3.1.1-python正则表达式(regular expression——regex)
作用:在一大段文本文字中快速定位到目标字段
代码理解:
import re
text = "xxxx"#待处理文本
#①统计该文本中有多少个目标字符(findstring-name)
#以下仅为概览,如果要寻找一个完整的字符,还要注意实际文本中,字符串与空格的格式排列问题
number=len(re.findall("findstring-name"),text)
#②查找以"a"开头,字符串长度为"3"的单词,"."表示任意字符,但这种调用无法避免有空格的情况,eg.a c
number=len(re.findall("a.."),text)
#去除空格
number=len(re.findall("a[a-z][a-z]"),text)
#去除统计过程中重复的结果
result=re.findall("a[a-z][a-z]",text)
result=set(result)
number=len(result)
#统计字符串开头为a/A
result=re.findall("[Aa][a-z][a-z]",text)
result=set(result)
number=len(result)
#统计字符串开头为a/A
result=re.findall("[Aa][a-z][a-z]",text)
result=set(result)
number=len(result)
#'*'通常表示可以匹配一个或多个甚至不匹配字符串
#eg:以"a*"为例,其与下列式子均等价
#"null"
#"a"
#"aa"
#"aaa"
#"aaaa……"
#所以我们在处理字符串与空格的格式问题时,可以用[ *]进行取缔
result=re.findall(" *([Aa][a-z][a-z])",text)
result=set(result)
number=len(result)
#但是这种情况依赖于原文格式,极容易输出错误,所以更改为以下比较好,只要没有匹配到目标字符串就输出" "
result=re.findall(" (a[a-z][a-z])|(A[a-z][a-z] ",text)
result=set(result)
number=len(result)
#而上述这种情况的输出是一对一对一起输出,不是非常方便,我们进行简化
result=re.findall("[Aa][a-z][a-z]",text)
final_result=set()
for pair in result:
if pair[0] not in final_result:
final_result.add(pair[0])
if pair[1] not in final_result:
final_result.add(pair[1])
final_result.remove(" ")
number=len(final_result)
3.1.2实战演练:爬取糗事百科中热图板块下第一页的所有的图片。**
打开该页面之后我们会发现页面的主要信息为:①发布者的名称;②文字;③图片
而每一个图片都对应一个地址可以在浏览页中新建页面单独访问,这意味这就是图片的url。
获取一张图片的代码:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import requests
#验证用图片url获得图片数据
if __name__=="__main__":
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.11 Safari/537.36'
}
#如何爬取图片数据
url="https://pic.qiushibaike.com/system/pictures/12409/124090998/medium/XS6YNH6N3X097AQ9.jpg"
#content返回的是二进制形式的图片数据
#text(字符串形式)
#contnt(二进制形式)
#json(对象形式)
imag_data = requests.get(url=url).content
#"wb"指写入二进制数据
with open('./image.jpg','wb')as fp:
fp.write(imag_data)
print("读取成功!")
pass
运行结果:
而要获取当前页面所有的图片,我们要将步骤进行拆分:
- 先用通用爬虫获取整张页面的数据信息;
- 然后使用聚焦爬虫提取图片url;
- 再进行解析即可完成
同理我们用开发者检查工具找到当前图片在此页面中对应的标签地址:
观察后发现所有的图片数据都存在<div class="thumb">
对应的标签中(如下)
<div class="thumb">
<a href="/article/124090998" target="_blank">
<img src="//pic.qiushibaike.com/system/pictures/12409/124090998/medium/XS6YNH6N3X097AQ9.jpg" alt="糗事#124090998" class="illustration" width="100%" height="auto">
</a>
</div>
使用聚焦爬虫将页面中所有的图片进行解析/提取(正则表达式的运用,ex就是我们的正则):
ex='<div class="thumb">.*?<img src="(.*?)" alt.*?</div>'
代码:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import requests
import re
import os
#需求:爬取糗事百科中糗图板块下所有的糗事图片
if __name__=="__main__":
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.11 Safari/537.36'
}
#如何爬取图片数据
url="https://www.qiushibaike.com/imgrank/"
#使用通用爬虫对url对应的一整张页面数据进行爬取
page_text = requests.get(url=url,headers=headers).text
# 使用聚焦爬虫将页面中所有的图片进行解析/提取(正则表达式的运用,ex就是我们的正则)
ex='<div class="thumb">.*?<img src="(.*?)" alt.*?</div>'
#re.S是单行匹配,re.M是多行匹配
#re.findall返回的是一个列表
re.findall(ex,page_text,re.S)
img_src_list = re.findall(ex,page_text,re.S)
#创建一个文件夹,保存所有的图片
if not os.path.exists('./all_images'):
os.mkdir('./all_images')
#遍历列表
for src in img_src_list:
#凭借出一个完整的图片url
src = 'https:'+ src
#请求到了图片的二进制数据
img_data=requests.get(url=src,headers=headers).content
#生成图片名称,根据斜杠切分,并获得url最后一个/后的字符串
img_name =src.split('/')[-1]
#图片存储的路径
imgPath='./all_images/'+img_name
#持续化存储
with open(imgPath,'wb') as fp:
fp.write(img_data)
print("图片下载成功!")
pass
运行结果:
在当前项目中生成了一个文件夹,然后将下载的图片批量存储了进去
3.1.3-将3.1.2中的代码优化,使其爬取热图板块下所有页码的图片(分页处理)
当前的热图板块下共有13页,每一页对应一张页面数据,而每一张页面数据中都有相应的图片数据
分析共性:
第1页url:
https://www.qiushibaike.com/imgrank/
第2页url:
https://www.qiushibaike.com/imgrank/page/2/
第13页url:
https://www.qiushibaike.com/imgrank/page/13/
我们可以看到url出现了page/n
的部分,而这就是不同页面的区别,从而获得一个通用的url模板(可以随便访问一个页码):
https://www.qiushibaike.com/imgrank/page/%d/
代码:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import requests
import re
import os
#需求:爬取糗事百科中糗图板块下所有的糗事图片
if __name__=="__main__":
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.11 Safari/537.36'
}
number=0
# 创建一个文件夹,保存所有的图片
if not os.path.exists('./all_images'):
os.mkdir('./all_images')
#如何爬取图片数据,获取当前的url模板
url="https://www.qiushibaike.com/imgrank/page%d/"
for pageNum in range(1,3):
#对应页码的url
temp_url=format(url%pageNum)
#使用通用爬虫对url对应的一整张页面数据进行爬取
page_text = requests.get(url=temp_url,headers=headers).text
# 使用聚焦爬虫将页面中所有的图片进行解析/提取(正则表达式的运用,ex就是我们的正则)
ex='<div class="thumb">.*?<img src="(.*?)" alt.*?</div>'
#re.S是单行匹配,re.M是多行匹配
#re.findall返回的是一个列表
re.findall(ex,page_text,re.S)
img_src_list = re.findall(ex,page_text,re.S)
#遍历列表
for src in img_src_list:
#凭借出一个完整的图片url
src = 'https:'+ src
#请求到了图片的二进制数据
img_data=requests.get(url=src,headers=headers).content
#生成图片名称,根据斜杠切分,并获得url最后一个/后的字符串
img_name =src.split('/')[-1]
#图片存储的路径
imgPath='./all_images/'+img_name
#持续化存储
number+=1
with open(imgPath,'wb') as fp:
fp.write(img_data)
print("图片下载成功!")
print('共爬取了%d图片'%(number))
pass
运行结果:
因为担心代码没有优化,13页的图片数据会出bug就只爬取了两页(rang(1,3)
),但是与3.1.2对比可以发现50刚好是25的两倍,代码运行正常。