爬虫以及数据保存
这篇文章, 分享如何将爬虫爬到的数据, 保存到excel表格当中。
文章目录
1.安装保存数据的第三方库openpyxl并使用
2.爬虫加单表数据保存
3.爬虫加多表数据保存
4.实战
一、安装保存数据的第三方库openpyxl并使用
我们需要安装openpyxl的第三方库
安装命令:
pip install openpyxl
安装成功后我们就可以使用了。
我们导入第三方库:
import openpyxl
创建对象 工作簿:
wb = openpyxl.Workbook()
选择工作子表(选择第一个工作子表)
ws = wb.active
修改工作子表的名字:
ws.title = '测试子表'
添加数据 执行一次append就是添加一行数据:
ws.append(['姓名','性别','年龄'])
注意:列表中的每一个数据对应的是表格中的一个单元格内容。
从第二行开始添加详细数据(因为刚才已经添加过一行了):
ws.append(['小1','女',18])
ws.append(['小2','男',18])
ws.append(['小嘿','女',20])
ws.append(['xoap','女',18])
这里我们添加了四行数据。
生成文件保存数据, 方法是工作簿对象.save(‘文件的路径’):
wb.save('学生表.xlsx')
完整代码:
# 创建对象 工作簿
import openpyxl
wb = openpyxl.Workbook()
# 选择工作子表(第一个)
ws = wb.active
# 修改工作子表的名字
ws.title = '测试子表'
# 添加数据 执行一次append就是添加一行数据
ws.append(['姓名','性别','年龄']) # 列表中的每一个数据对应的是表格中的一个单元格内容
# 第二行开始添加详细数据
ws.append(['小1','女',18])
ws.append(['小2','男',18])
ws.append(['小嘿','女',20])
ws.append(['xoap','女',18])
# 生成文件保存数据
# wb.save('文件的路径')
wb.save('学生表.xlsx')
运行结果:
在用一个文件夹下面, 多出了一个叫学生表.xslx的excel表格。这张表格, 就是我们刚刚用代码去创建的的表格。
同时, 我们打开表格来看一看数据:
我们发现信息成功的写入表格, 最下面那个测试子表, 就是对应 ws.title = ‘测试子表’ 这行代码。表格标题和表格里面的内容, 都是用append方法去添加的,注意, 这里append的方法, 只会增加固定的行, 比如我在第三个append里面修改要添加的数据, 把ws.append([‘小2’,‘男’,18])改为ws.append([‘小22’,‘男’,19]), 运行过后, 表格里面的第三行数据, 会发生变化, 它不会因改变信息而添加数据, 只会覆盖第三行的数据。如果想要追加数据, 那就必须写更多的append函数去追加数据。
我们还有一种方式去创建excel表格并且保存数据(这种方法, 适合创建多张excel表格, 并且同时保存多张excel表格数据)。
代码:
import openpyxl
wb = openpyxl.Workbook()
list_name = ["小明", "小红", "小强", "小慧", "小蓝"]
list_gender = ["男", "女", "男", "女", "男"]
list_age = [20, 19, 21, 19, 19]
for i in range(100):
# 创建新的子表
sheet = wb.create_sheet(title=f'第{i}张表格')
# 添加表头
sheet.append(["姓名", "性别", "年龄"])
for i in range(5):
sheet.append([list_name[i], list_gender[i], list_age[i]])
# 删除第一个默认的子表
wb.remove(wb.active)
# 保存表格
wb.save('全部球员数据.xlsx')
结果:
利用sheet = wb.create_sheet(title=f’第{i}张表格’)这行代码, 创建excel表格
二、爬虫加单表数据保存
我们看一个案例:
我们打开nba官网, url是https://china.nba.cn/statistics/index.html
找到数据里面的球员数据.
我们需要爬取表格里面的信息, 有球员姓名, 球队, 比赛场次, 出场时间, 得分, 篮板, 助攻, 抢新, 盖帽, 投篮命中率, 三分命中数, 三分命中率, 罚球命中率这么些信息。
我们打开开发者工具, 找到数据的相应请求:
将请求数据的对应的url复制下来:https://api.nba.cn/sib/v2/league/playerstats?app_key=tiKB2tNdncnZFPOi&app_version=1.1.0&channel=NBA&conference=All&device_id=6d02def8348ce928cca4cfa777ee6a4e&individual=All&install_id=799163069&network=N%2FA&os_type=3&os_version=1.0.0&page_no=1&page_size=50&position=All&scope=team&season=2023&seasonType=4&sign=sign_v2&sign2=076D913573642C47DDFC1D2F2A0E4910046862A35D8D4AFC8FC05BB2B73466C0&t=1723805890324&total=perGame
代码:
import requests
url = 'https://api.nba.cn/sib/v2/league/playerstats?app_key=tiKB2tNdncnZFPOi&app_version=1.1.0&channel=NBA&conference=All&device_id=6d02def8348ce928cca4cfa777ee6a4e&individual=All&install_id=799163069&network=N%2FA&os_type=3&os_version=1.0.0&page_no=1&page_size=50&position=All&scope=team&season=2023&seasonType=4&sign=sign_v2&sign2=076D913573642C47DDFC1D2F2A0E4910046862A35D8D4AFC8FC05BB2B73466C0&t=1723805890324&total=perGame'
res = requests.get(url, headers=headers)
res_data = res.json()
# 数据解析
for i in res_data['data']['player']['Data']:
# 姓名
name = i['Player']['displayName']
# 球队名
team = i['Team']['name']
# 比赛场次
games = i['Games']
# 出场时间
minspg = i['Minspg']
# 得分
pointspg = i['Pointspg']
# 篮板
rebspg = i['Rebspg']
# 助攻
assistspg = i['Assistspg']
# 抢断
stealspg = i['Stealspg']
# 盖帽
offrebspg = i['Offrebspg']
# 投篮命中率
fgpct = f'{i["Fgpct"]}%'
# 三分命中数
rebs = i['Rebs']
# 三分命中率
tppct = f'{i["Tppct"]}%'
# 罚球命中率
ftpct = f'{i["Ftpct"]}%'
print(name,team,games,minspg,pointspg,rebspg,assistspg,stealspg,offrebspg,fgpct,rebs,tppct,ftpct)
结果:
报错了, 说明在url里面有参数有误, 导致请求不成功。
唉, 我们不是把headers请求头都加了么, 怎么还是获取不到数据呢?
这里我们需要注意, 有个参数t, 这个里面的参数代表时间戳, 没有拿到正确响应的原因, 就是因为时间戳的问题, 这个就是典型的网站反爬机制, 需要把时间戳的值对上号才能获取到数据。
解决办法:
python中有个获取时间戳的库:
import time
print("获取时间戳:", int(time.time()))
那我们需要把int(time.time())传入到url里面的t参数。
修改过后的代码:
import requests
import time
url = f'https://api.nba.cn/sib/v2/league/playerstats?app_key=tiKB2tNdncnZFPOi&app_version=1.1.0&channel=NBA&conference=All&device_id=6d02def8348ce928cca4cfa777ee6a4e&individual=All&install_id=799163069&network=N%2FA&os_type=3&os_version=1.0.0&page_no=1&page_size=50&position=All&scope=team&season=2023&seasonType=4&sign=sign_v2&sign2=076D913573642C47DDFC1D2F2A0E4910046862A35D8D4AFC8FC05BB2B73466C0&t={int(time.time())}&total=perGame'
res = requests.get(url, headers=headers)
res_data = res.json()
# 数据解析
for i in res_data['data']['player']['Data']:
# 姓名
name = i['Player']['displayName']
# 球队名
team = i['Team']['name']
# 比赛场次
games = i['Games']
# 出场时间
minspg = i['Minspg']
# 得分
pointspg = i['Pointspg']
# 篮板
rebspg = i['Rebspg']
# 助攻
assistspg = i['Assistspg']
# 抢断
stealspg = i['Stealspg']
# 盖帽
offrebspg = i['Offrebspg']
# 投篮命中率
fgpct = f'{i["Fgpct"]}%'
# 三分命中数
rebs = i['Rebs']
# 三分命中率
tppct = f'{i["Tppct"]}%'
# 罚球命中率
ftpct = f'{i["Ftpct"]}%'
print(name,team,games,minspg,pointspg,rebspg,assistspg,stealspg,offrebspg,fgpct,rebs,tppct,ftpct)
代码优化:
增加一个分页爬虫的功能并且保存数据到excel。
'''
前面几次测试可以得到正常的响应数据
突然得不到,加上了伪装
还发现分页参数有变化,时间戳变化
通过测试,更改时间戳,数据可以正常返回
验证当前拿不到正确响应的原因:时间戳的问题
'''
import time
# print(res_data)
# {'data':{'player':{'Data':[]}}}
# 创建工作表的代码
import openpyxl
import requests
wb = openpyxl.Workbook()
sheet = wb.active
sheet.title = '球队数据'
# 表头
sheet.append(['姓名','球队名','比赛场次','出场时间','得分','篮板','助攻','抢断','盖帽','投篮命中率','三分命中数','三分命中率','罚球命中率'])
# 加入分页 不能确定次数,因为年份不同,总页数不一样
page = 1
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36'
}
while True:
url = f'https://api.nba.cn/sib/v2/league/playerstats?app_key=tiKB2tNdncnZFPOi&app_version=1.1.0&channel=NBA&conference=All&device_id=6d02def8348ce928cca4cfa777ee6a4e&individual=All&install_id=799163069&network=N%2FA&os_type=3&os_version=1.0.0&page_no={page}&page_size=50&position=All&scope=team&season=2023&seasonType=4&sign=sign_v2&sign2=076D913573642C47DDFC1D2F2A0E4910046862A35D8D4AFC8FC05BB2B73466C0&t={int(time.time())}&total=perGame'
res = requests.get(url, headers=headers)
res_data = res.json()
# 结束循环的代码 如果Data对应的列表为[] 代表没有数据了
# {'Data':[{},{}]}
# {'Data':[]}
if len(res_data['data']['player']['Data']) == 0:
break
# 数据解析
for i in res_data['data']['player']['Data']:
# 姓名
name = i['Player']['displayName']
# 球队名
team = i['Team']['name']
# 比赛场次
games = i['Games']
# 出场时间
minspg = i['Minspg']
# 得分
pointspg = i['Pointspg']
# 篮板
rebspg = i['Rebspg']
# 助攻
assistspg = i['Assistspg']
# 抢断
stealspg = i['Stealspg']
# 盖帽
offrebspg = i['Offrebspg']
# 投篮命中率
fgpct = f'{i["Fgpct"]}%'
# 三分命中数
rebs = i['Rebs']
# 三分命中率
tppct = f'{i["Tppct"]}%'
# 罚球命中率
ftpct = f'{i["Ftpct"]}%'
print(name,team,games,minspg,pointspg,rebspg,assistspg,stealspg,offrebspg,fgpct,rebs,tppct,ftpct)
sheet.append([name,team,games,minspg,pointspg,rebspg,assistspg,stealspg,offrebspg,fgpct,rebs,tppct,ftpct])
print(f'第{page}页数据已经全部获取完毕')
page += 1
# 保存表格
wb.save('aaa/球队数据.xlsx')
结果:
三、爬虫加多表数据保存
还是用刚才的nba球员的数据, 这次我们不仅仅实现分页爬虫加上保存数据, 我们在这里需要爬取不同年份里面的所有的nba球员所有的数据并保存, 以年份为准保存每一年的nba球员的数据。
url关键会变化的参数:
年份参数: year, 分页参数: page, 时间戳参数: t。
代码:
import time
import datetime
'''
一个年份对应一个子表
'''
import openpyxl
import requests
wb = openpyxl.Workbook()
# 加入分页 不能确定次数,因为年份不同,总页数不一样
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36'
}
year_now = datetime.datetime.now().year
for year in range(1996,year_now):
page = 1 # 根据年份重置分页的起始
# 创建子表要放入到年份循环的代码中
# 因为文件是按照年份进行划分子表
# 创建新的子表
sheet = wb.create_sheet(title=f'{year}年球员数据')
# 表头
sheet.append(['姓名', '球队名', '比赛场次', '出场时间', '得分', '篮板', '助攻', '抢断', '盖帽', '投篮命中率', '三分命中数', '三分命中率', '罚球命中率'])
while True:
# 休眠
time.sleep(0.5)
url = f'https://api.nba.cn/sib/v2/league/playerstats?app_key=tiKB2tNdncnZFPOi&app_version=1.1.0&channel=NBA&conference=All&device_id=6d02def8348ce928cca4cfa777ee6a4e&individual=All&install_id=799163069&network=N%2FA&os_type=3&os_version=1.0.0&page_no={page}&page_size=50&position=All&scope=team&season={year}&seasonType=4&sign=sign_v2&sign2=076D913573642C47DDFC1D2F2A0E4910046862A35D8D4AFC8FC05BB2B73466C0&t={int(time.time())}&total=perGame'
res = requests.get(url, headers=headers)
res_data = res.json()
# 结束循环的代码 如果Data对应的列表为[] 代表没有数据了
# {'Data':[{},{}]}
# {'Data':[]}
if len(res_data['data']['player']['Data']) == 0:
break
# 数据解析
for i in res_data['data']['player']['Data']:
# 姓名
name = i['Player']['displayName']
# 球队名
try:
team = i['Team']['name']
except:
team = ''
# 比赛场次
games = i['Games']
# 出场时间
minspg = i['Minspg']
# 得分
pointspg = i['Pointspg']
# 篮板
rebspg = i['Rebspg']
# 助攻
assistspg = i['Assistspg']
# 抢断
stealspg = i['Stealspg']
# 盖帽
offrebspg = i['Offrebspg']
# 投篮命中率
fgpct = f'{i["Fgpct"]}%'
# 三分命中数
rebs = i['Rebs']
# 三分命中率
tppct = f'{i["Tppct"]}%'
# 罚球命中率
ftpct = f'{i["Ftpct"]}%'
print(name,team,games,minspg,pointspg,rebspg,assistspg,stealspg,offrebspg,fgpct,rebs,tppct,ftpct)
sheet.append([name,team,games,minspg,pointspg,rebspg,assistspg,stealspg,offrebspg,fgpct,rebs,tppct,ftpct])
print(f'第{year}年的{page}页数据已经全部获取完毕')
page += 1
# 删除第一个默认的子表
wb.remove(wb.active)
# 保存表格
wb.save('全部球员数据.xlsx')
year_now = datetime.datetime.now().year这行代码指的是获取当前的年份, 当前的年份是2024, 所以获取到的值的2024。而我们在nba网站上面看到的球员信息, 正好到2023年, 所以我们可以把这个数据放到循环里面去使用:for year in range(1996,year_now)。
运行完之后的结果:
在最下面, 有很多张表格, 分别保存着每一年的球员数据。
四、实战
我们打开网站:
url是https://bgm.tv/anime/browser?sort=rank
要求: 我们需要爬取动画的标题, 动画信息, 评分这三个信息, 同样需要分页查询, 将数据保存到同一张表格当中, 并将表格命名为动漫数据大全, 将excel文件命名为动漫信息, 文件以xlsx为后缀。
先不要马上看答案, 尝试自己去做一做哦。
参考答案:
import requests
from bs4 import BeautifulSoup
import openpyxl
page = 1
headers = {
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36"
}
wb = openpyxl.Workbook()
sheet1 = wb.active
sheet1.title = "动漫数据大全"
sheet1.append(["标题", "动漫基本信息", "动漫评分"])
while True:
url = f"https://bgm.tv/anime/browser?sort=rank&page={page}"
res = requests.get(url, headers=headers)
res.encoding = 'utf-8'
soup = BeautifulSoup(res.text, "lxml")
section = soup.select(".section>ul>li")
if len(section) == 0:
break
else:
for item in section:
# 标题
title = item.select("div>h3>a")[0].text
# 动漫基本信息
info = item.select("div>p")[0].text.replace('\n', ' ')
# 动漫评分
rating = item.select("div>.rateInfo>.fade")[0].text
print("标题:", title, "\t动漫基本信息:", info, "\t动漫评分:", rating)
sheet1.append([title, info, rating])
print(f"第{page}页的数据已爬完")
page += 1
wb.save('动漫信息.xlsx')
结果:
这道实战题, 你写出来了吗? 如果写出来的话, 给自己鼓掌哦👏
以上就是爬虫以及数据保存的所有内容了, 如果有哪里不懂的地方,可以把问题打在评论区, 欢迎大家在评论区交流!!!
如果我有写错的地方, 望大家指正, 也可以联系我, 让我们一起努力, 继续不断的进步.
学习是个漫长的过程, 需要我们不断的去学习并掌握消化知识点, 有不懂或概念模糊不理解的情况下,一定要赶紧的解决问题, 否则问题只会越来越多, 漏洞也就越老越大.
人生路漫漫, 白鹭常相伴!!!