Python之数据解析
1.图片数据爬取
**需求:**爬取糗图百科的一张图片
图片数据爬取代码:
import requests
if __name__ == '__main__':
#如何爬取图片数据
url = 'https://pic.qiushibaike.com/system/pictures/12462/124627742/medium/87WZPLC7TCXBL455.jpg'
#content返回的是二进制形式的图片数据
#text(字符串) content(二进制)json()(对象)
img_data = requests.get(url = url,).content
with open("D:/qiutu.jpg","wb") as fp:
fp.write(img_data)
<div class="thumb">
<a href="/article/124598970" target="_blank">
<img src="//pic.qiushibaike.com/system/pictures/12459/124598970/medium/G16Z94DSL6PR9128.jpg" alt="糗事#124598970" class="illustration" width="100%" height="auto">
</a>
</div>
2.Python爬虫之正则解析案例
爬取糗图百科页面的所有图片
代码:
import requests
import re
import os
#需求:爬取糗事百科中糗图模块下所有的糗图图片
if __name__ == '__main__':
#创建一个文件夹,保存所有的图片
if not os.path.exists('D:/糗图图片'):
os.mkdir('D:/糗图图片')
url = 'https://www.qiushibaike.com/imgrank/'
headers={"user-agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36 Edg/92.0.902.67"}
#使用通用爬虫对url对应的一整张页面进行爬取
page_text = requests.get(url = url,headers= headers).text
#使用聚焦爬虫将页面中的所有的糗图进行解析/提取
ex = '<div class="thumb">.*?<img src="(.*?)" alt.*?</div>'
img_src_list = re.findall(ex,page_text,re.S) #re.S单行匹配 re.M多行匹配
#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 = 'D:/糗图图片/'+img_name
with open(imgPath,'wb') as f:
f.write(img_data)
print("------------"+img_name+"下载成功!!!------------")
爬取糗图百科所有页面的所有图片
代码:
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/92.0.4515.131 Safari/537.36 Edg/92.0.902.67"}
#创建一个文件夹,保存所有的图片
if not os.path.exists('D:/糗图图片'):
os.mkdir('D:/糗图图片')
#设置一个通用的Url模板
url = 'https://www.qiushibaike.com/imgrank/page/%d/'
for page_Num in range(1,13):
new_url = format(url%page_Num)
#使用通用爬虫对url对应的一整张页面进行爬取
page_text = requests.get(url = new_url,headers= headers).text
#使用聚焦爬虫将页面中的所有的糗图进行解析/提取
ex = '<div class="thumb">.*?<img src="(.*?)" alt.*?</div>'
img_src_list = re.findall(ex,page_text,re.S) #re.S单行匹配 re.M多行匹配
#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 = 'D:/糗图图片/'+img_name
with open(imgPath,'wb') as f:
f.write(img_data)
print("------------"+img_name+"下载成功!!!------------")
3.bs4解析
数据解析的原理:
- 1.标签定位
- 2.提取标签、标签属性中存储的数据值
bs4数据解析的原理:
- 1.实例化一个BeautifulSoup对象,并且将页面源码数据加载到该对象中
- 2.通过调用BeautifulSoup对象中相关的属性或者方法进行标签定位和数据提取
如何实例化BesutifuiSoup对象:
- from bs4 import BeautifulSoup
- 对象的实例化:
- 1.将本地的html文档中的数据加载到该对象中
代码样例:
- 1.将本地的html文档中的数据加载到该对象中
from bs4 import BeautifulSoup
if __name__ == '__main__':
#将本地的html文档中的数据加载到该对象中
fp = open('D:/text.html','r',encoding = 'utf-8')
soup = BeautifulSoup(fp,'lxml') # BeautifulSoup()有两个参数,其中一个必是'lxml'
print(soup)
· 2.将互联网上获取的页面源码加载到该对象中
page_text = response.text
soup = BeautifulSoup(page_text,'lxml')
- 提供的用于数据解析的方法和属性:
- 一 .soup.tagName : 返回的是文档中第一次出现的tagName对应的标签
print(soup.a) # soup.taoName 返回的是html中第一次出现的taoName标签
print(soup.div) #返回的是html中第一次出现的div标签
- 二 .soup.find():
1.find(‘tagName’):等同于soup.div
2.属性定位:
----- soup.find(‘div’,class_/id/atter = ‘song)
3.soup.find_all(‘tageName’):返回符合要求的所有标签(列表)
4.select:
------ select(‘某种选择器(id,class,标签…选择器)‘),返回的是一个列表。
------ 层级选择器:
--------- soup.select(’.tang > ul > li > a’ ) : >返回的是一个层级
--------print(soup.select(’.tang > ul a’)[0]) : 空格表示的多个层级
------获取标签之间的文本数据:
---------soup.a.text/string/get_text()
---------text/get_text():可以获取某一个标签中所有的文本内容
---------string: 只可以获取该标签下面直系的文本内容
------获取标签中属性值:
---------soup.a[‘herf’]
代码:
from bs4 import BeautifulSoup
if __name__ == '__main__':
#将本地的html文档中的数据加载到该对象中
fp = open('D:/text.html','r',encoding = 'utf-8')
soup = BeautifulSoup(fp,'lxml') # BeautifulSoup()有两个参数,其中一个必是'lxml'
'''
print(soup) #输出的是整个fp文件的源代码内容
print(soup.a) # soup.taoName 返回的是html中第一次出现的taoName标签
print(soup.div) #返回的是html中第一次出现的div标签
'''
'''
find('tageName'):等同于soup.div
print(soup.find('div')) #等价于print(soup.div)
print(soup.find('div',class_= 'song')) #定位到属性为class='song'的div中
'''
#print(soup.find_all('a')) #返回的是符合要求的所有标签(列表)
#print(soup.selsect('.tang')) #返回的是列表
#print(soup.select('.tang > ul > li > a' )[0]) #拿到的是第一个a标签
#print(soup.select('.tang > ul a')[0]) #结果同上
'''
获取文本数据
print(soup.select('.tang > ul a')[0].text)
print(soup.select('.tang > ul a')[0].string)
'''
#print(soup.select('.tang > ul a')[0]['herf']) #获取标签中属性值
bs4解析实例之爬取三国演义(内含出现乱码的解决方法)
代码:
import requests
from bs4 import BeautifulSoup
#需求:爬取三国演义小说所有的章节标题和章节目录内容https://www.shicimingju.com/book/sanguoyanyi.html
if __name__ == '__main__':
#对首页面数据进行爬取
headers = {
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36 Edg/92.0.902.62",
}
url = 'https://www.shicimingju.com/book/sanguoyanyi.html'
#出现乱码的解决方式1:
page_text = requests.get(url = url,headers = headers)
page_text.encoding='utf-8'
page_text=page_text.text
#在首页中解析出章节的标题和详情页的url
#1.实例化BeautifulSoup对象,需要将页面源码数据加载到该对象中
soup = BeautifulSoup(page_text,'lxml')
fp = open('D:/sanguo.txt','w',encoding = 'utf-8')
#解析章节标题和详情页的url
li_list = soup.select('.book-mulu > ul > li') #获取li列表
for li in li_list:
title = li.a.string
detail_url = 'https://www.shicimingju.com' +li.a['href']
#对详情页发起请求,解析出章节内容
#出现乱码的解决方式2:
detail_page_text = requests.get(url = detail_url, headers= headers)
detail_page_text = bytes(detail_page_text.text,detail_page_text.encoding).decode('utf-8','ignore')
#解析出详情页中相关的章节内容
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数据分析
xpath解析:
xpath解析:最常用且最便捷高效的一种解决方式、通用性
xpath解析原理:
1.实例化一个etree的对象,且需要将被解析的页面源码数据加载到该对象中 ;
2.调用etree对象中的xpath方法结合着xpath表达式实现标签的定位和内容的捕获。
环境的安装:
pip install lxml
如何实例化一个etree对象:from lxml import etree
1.将本地的html文档中的源代码数据加载到etree对象中:
etree.parse(filePath)
2.可以将互联网上获取的源代码数据加载到该对象中
etree.HTML(‘page_text’)
xpath(‘xpath表达式’)
/ : 表示的是从根点开始定位,表示的是一个层级。
// :表示的是多个层级。可以表示从任意位置开始定位
属性定位: //div[@class=‘song’] tag[@attrName=“attrValue”]
索引定位://div[@class=“song”]/p[3] 索引时从1开始的。
取文本:
- /text() 获取的是标签中直系的文本内容
- //text() 标签中非直系的文本内容(所有文本内容)
取属性:
/@atterName ==>img/src
代码:
from lxml import etree
if __name__ == '__main__':
#实例化好了一个etree对象,且将被解析的源码加载到了该对象中
tree = etree.parse('test.html')
'''
单行层级:
r = tree.xpath('/html/head/title') #因为是从根节点,所以html前面也需要加上一个/
r = tree.xpath('/html/body/div')
'''
'''
多层级
r = tree.xpath('/html//div')
r = tree.xpath('//div')
'''
'''
定位:
r = tree.xpath('//div[@class="song"]') #属性定位
r = tree.xpath('//div[@class="song"]/p[3]') #索引定位:索引时从1开始的,不是从0
'''
'''
取文本
r = tree.xpath('//div[@class="tang"]//li[5]/a/text()')[0] #加text()是为了得到文本,而加[0]之前的文本是列表形式的,所以加了[0]为了只得到文本
r = tree.xpath('//li[5]//text()')[0] #加text()是为了得到文本,而加[0]之前的文本是列表形式的,所以加了[0]为了只得到文本
r = tree.xpath('//div[@class="tang"]//text()') #得到的是div下面的所有文本内容,而换为/text()则无法得到
'''
#r = tree.xpath('//div[@class="song"]img/@src') #取属性的标签
print(r)
实例1—爬取58同城二手房源信息
终于弄出来了,昨天可能因为我长时间访问他们的网站,就导致我一直都爬取不了,今天终于爬取到了。如果你也爬取不了,你或许可以换一个User-Agent试试。
import requests
from lxml import etree
if __name__ == '__main__':
url='https://bj.58.com/ershoufang/'
headers={
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36 Edg/92.0.902.78'
}
#获取整张数据
page_text=requests.get(url=url,headers=headers).text
#将得到的数据树化
tree=etree.HTML(page_text)
#获取整个数据
div_list=tree.xpath('//section[@class="list"]/div')
#创建文件
fp=open('D:/58fangyuan.txt','w',encoding='utf-8')
#获得数据中的标题
for div in div_list:
title = div.xpath('.//div[@class="property-content-title"]/h3/text()')[0]
print(title)
fp.write(title+'\n'+'.\n')
实列2—爬取彼岸图网的动漫图片
呜呜~~。要疯了,由于把ul写成了ur,无法成功爬取图片,便以为爬虫被发现了,就一直改,改了一下午,结果发现是一个字母写错了,郁闷死了。
网址链接:https://pic.netbian.com/.
代码:
#需求:解析下载图片数据
import requests
from lxml import etree
import os
if __name__ == '__main__':
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/92.0.4515.159 Safari/537.36 Edg/92.0.902.78'
}
reponse = requests.get(url = url,headers = headers)
#手动设定响应数据的编码格式
#reponse.encoding = 'utf-8'
page_text = reponse.text
#创建文件夹
if not os.path.exists('D:/动漫图片'):
os.mkdir('D:/动漫图片')
#数据分析:src的属性值 alt 属性
tree = etree.HTML(page_text)
li_list = tree.xpath('//div[@class="slist"]/ul/li')
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')
#请求图片进行持久化存储
img_data = requests.get(url = img_src,headers= headers).content
img_path= '动漫图片/'+img_name
with open(img_path,'wb') as fp:
fp.write(img_data)
print(img_name,'下载成功!!!—————————————')
重要知识点一:
1.中文乱码的解决办法一:
#手动设定响应数据的编码格式
reponse = requests.get(url = url,headers = headers)
#reponse.encoding = 'utf-8'
page_text = reponse.text
2.中文乱码的解决办法二:
#通用处理中文乱码的解决方案
img_name = li.xpath('./a/img/@alt')[0]+'.jpg'
img_name = img_name.encode('iso-8859-1').decode('gbk')
重要知识点二
路径节点的选取 | 用法 | 说明 |
---|---|---|
/ | xpath(’/html’) | 从根节点选取html节点 |
// | xpath(’//div’) | 从任意位置开始定位,匹配div节点 |
./ | xpath(’./div’) | 选取当前节点下的div |
实例3—全国城市名称爬取
代码
import requests
from lxml import etree
#项目需求:解析出所有城市名称https://www.aqistudy.cn/historydata/
if __name__ == '__main__':
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36 Edg/92.0.902.78'
}
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:
host_city_name = li.xpath('./a/text()')[0]
all_city_names.append(host_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))
简化版代码:
import requests
from lxml import etree
#项目需求:解析出所有城市名称https://www.aqistudy.cn/historydata/
if __name__ == '__main__':
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36 Edg/92.0.902.78'
}
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_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))