Python高级应用程序设计任务要求
用Python实现一个面向主题的网络爬虫程序,并完成以下内容:
(注:每人一题,主题内容自选,所有设计内容与源代码需提交到博客园平台)
一、主题式网络爬虫设计方案(15分)
1.主题式网络爬虫名称
B站番剧页面数据的爬取与分析
2.主题式网络爬虫爬取的内容与数据特征分析
获取B站单个页面的视频信息,包括av号、上传者、上传时间、观看人数、弹幕数、分享数、排名等
3.主题式网络爬虫设计方案概述(包括实现思路与技术难点)
实现思路:使用requests库爬取数据,使用matplotlib模块实现数据可视化
技术难点:B站数据的爬取和破解B站反爬
二、主题页面的结构特征分析(15分)
1.主题页面的结构特征
主体页面为B站的番剧页面,分为网页头部、网页中部、网页尾部、其中有用的数据在网页中部的有用信息,
2.Htmls页面解析
3.节点(标签)查找方法与遍历方法
(必要时画出节点树结构)
三、网络爬虫程序设计(60分)
爬虫程序主体要包括以下各部分,要附源代码及较详细注释,并在每部分程序后面提供输出结果的截图。
1.数据爬取与采集
# 导入对应的 package import numpy as np import pandas as pd import requests import time def get_data(base_url, page): url = base_url.format(str(page)) # 得到对应的url response = requests.get(url, headers=header) # 发出请求,获取回应 response.encoding="utf-8" videos = pd.read_json(response.text[37:-1]).iloc[:, 3].iloc[0] # 获取列表 videos_list = [] # 用来储存数据 for video in videos: # 循环每个番剧 video_inf = [] # 用来储存每个番剧的信息 video_inf.append(video['stat']['aid']) # av号 video_inf.append(video["title"]) # 标题 video_inf.append(video['owner']["name"]) # 上传者 video_inf.append(time.ctime(video['pubdate'])) # 上传时间 video_inf.append(video['stat']['view']) # 观看人数 video_inf.append(video['stat']['danmaku']) # 弹幕数 video_inf.append(video['stat']['reply']) # 评论数量 video_inf.append(video['stat']['favorite']) # 收藏数量 video_inf.append(video['stat']['coin']) # 投币数 video_inf.append(video['stat']['share']) # 分享数 video_inf.append(video['stat']['like']) # 点喜欢的人数 video_inf.append(video['stat']['dislike']) # 点不喜欢的人数 video_inf.append(video['stat']["now_rank"]) # 排名 video_inf.append(video['stat']["his_rank"]) # 排名 video_inf.append(video['tname']) # 标签 video_inf.append(video['desc']) # 描述 videos_list.append(video_inf) return videos_list def get_all_data(n): # 数据对应的列名 col = ['av号', '标题', 'up主', '上传日期', '观看次数', '弹幕', 'reply', '收藏', '投币', '分享', '喜欢', '不喜欢', '现在排名', '他的排名', '标签', '描述'] # 建立 DataFrame 来储存数据 data = pd.DataFrame(columns=col) # 循环页数 for i in range(1, n + 1): data_temp = pd.DataFrame( get_data(base_url, i), columns=col) # 对应页的数据,临时储存 data = pd.concat([data, data_temp], axis=0, ignore_index=True) # 与之前的数据合并在一块 # 适当的停顿,防止请求过快,封ip time.sleep(np.random.rand() * np.random.randint(1, 3)) return data base_url = "https://api.bilibili.com/x/web-interface/newlist?callback=jqueryCallback_bili_4431985766884974&rid=33&type=0&pn={}&ps=20&jsonp=jsonp&_=1558156016281" # 一些的请求头,伪装成浏览器,可以防止一些反爬虫的机制 header = {"Referer": "https://www.bilibili.com/v/anime/serial/?spm_id_from=333.334.b_7072696d6172795f6d656e75.8", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36"} data = get_all_data(1325) # 获取1325页的视频数据,页数为网页直接查看获得 filename='bilibili_data1.csv' data.to_csv(filename,encoding="utf-8")
2.对数据进行清洗和处理
import matplotlib.pyplot as plt import numpy as np import pandas as pd data = pd.read_csv('C:/Users/3号/PycharmProjects/biliHello/bilibili_data.csv') data.head() # 首先查看下数据是否有 nan 值 data.isnull().sum() 查看是哪一行 data[data.isnull()['up主']] # 去掉这一行 data.drop(26397, inplace=True) # 查看数据有没有重复项 data.duplicated().sum() # 确认下最小值 data.min() # 将上传时间 转换成 datetime 类型 data['上传日期'] = pd.to_datetime(data['上传日期']) # 查看一下统计 data.describe()
3.文本分析(可选):jieba分词、wordcloud可视化
4.数据分析与可视化
(例如:数据柱形图、直方图、散点图、盒图、分布图、数据回归分析等)
# 看一下各数据的相关性 data.corr()
# 查看up主投稿的数量 data.groupby("up主").count().sort_values("av号", ascending=False) # 根据up主投稿的数量排序
data.sort_values("观看次数", ascending=False).reset_index(drop=True)['观看次数'].plot()
# 查看投币排序 data.sort_values("投币", ascending=False).reset_index(drop=True)['投币'].plot()
# 查看一下根据投稿时间的播放量情况 plt.plot(data.set_index("上传日期")['观看次数'].sort_index()) plt.title(u'播放量', fontproperties=font_hei)
5.数据持久化
6.附完整程序代码
1.获取B站HTML源码 import requests from bs4 import BeautifulSoup url='https://www.bilibili.com/v/anime/serial/#/all/default' def getHTMLText(url,timeout=30): try: r=requests.get(url,timeout=30) r.raise_for_status() r.enconding=r.apparent_encoding return r.text except: return '产生异常' html=getHTMLText(url) soup=BeautifulSoup(html,'html.parser') print(soup.prettify()) 2.获取B站番剧数据 # 导入对应的 package import numpy as np import pandas as pd import requests import time def get_data(base_url, page): url = base_url.format(str(page)) # 得到对应的url response = requests.get(url, headers=header) # 发出请求,获取回应 response.encoding="utf-8" videos = pd.read_json(response.text[37:-1]).iloc[:, 3].iloc[0] # 获取列表 videos_list = [] # 用来储存数据 for video in videos: # 循环每个番剧 video_inf = [] # 用来储存每个番剧的信息 video_inf.append(video['stat']['aid']) # av号 video_inf.append(video["title"]) # 标题 video_inf.append(video['owner']["name"]) # 上传者 video_inf.append(time.ctime(video['pubdate'])) # 上传时间 video_inf.append(video['stat']['view']) # 观看人数 video_inf.append(video['stat']['danmaku']) # 弹幕数 video_inf.append(video['stat']['reply']) # 评论数量 video_inf.append(video['stat']['favorite']) # 收藏数量 video_inf.append(video['stat']['coin']) # 投币数 video_inf.append(video['stat']['share']) # 分享数 video_inf.append(video['stat']['like']) # 点喜欢的人数 video_inf.append(video['stat']['dislike']) # 点不喜欢的人数 video_inf.append(video['stat']["now_rank"]) # 排名 video_inf.append(video['stat']["his_rank"]) # 排名 video_inf.append(video['tname']) # 标签 video_inf.append(video['desc']) # 描述 videos_list.append(video_inf) return videos_list def get_all_data(n): # 数据对应的列名 col = ['av号', '标题', 'up主', '上传日期', '观看次数', '弹幕', 'reply', '收藏', '投币', '分享', '喜欢', '不喜欢', '现在排名', '他的排名', '标签', '描述'] # 建立 DataFrame 来储存数据 data = pd.DataFrame(columns=col) # 循环页数 for i in range(1, n + 1): data_temp = pd.DataFrame( get_data(base_url, i), columns=col) # 对应页的数据,临时储存 data = pd.concat([data, data_temp], axis=0, ignore_index=True) # 与之前的数据合并在一块 # 适当的停顿,防止请求过快,封ip time.sleep(np.random.rand() * np.random.randint(1, 3)) return data base_url = "https://api.bilibili.com/x/web-interface/newlist?callback=jqueryCallback_bili_4431985766884974&rid=33&type=0&pn={}&ps=20&jsonp=jsonp&_=1558156016281" # 一些的请求头,伪装成浏览器,可以防止一些反爬虫的机制 header = {"Referer": "https://www.bilibili.com/v/anime/serial/?spm_id_from=333.334.b_7072696d6172795f6d656e75.8", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36"} data = get_all_data(1325) # 获取1325页的视频数据,页数为网页直接查看获得 filename='bilibili_data.csv' data.to_csv(filename,encoding="utf-8") 3.数据清洗 import matplotlib.pyplot as plt import numpy as np import pandas as pd data = pd.read_csv('C:/Users/3号/PycharmProjects/biliHello/bilibili_data.csv') data.head() # 首先查看下数据是否有 nan 值 data.isnull().sum() 查看是哪一行 data[data.isnull()['up主']] # 去掉这一行 data.drop(26397, inplace=True) # 再次确认缺失值 data.isnull().sum() # 查看数据有没有重复项 data.duplicated().sum() # 确认下最小值 data.min() # 将上传时间 转换成 datetime 类型 data['上传日期'] = pd.to_datetime(data['上传日期']) data.drop(data[-1 == data['观看次数']].index, inplace=True) # 查看一下统计 data.describe() # 看一下各数据的相关性 data.corr() # 查看up主投稿的数量 data.groupby("up主").count().sort_values("av号", ascending=False) # 根据up主投稿的数量排序 data.sort_values("观看次数", ascending=False).reset_index(drop=True) data.sort_values("收藏", ascending=False).reset_index(drop=True) # 收藏数量排序 data.sort_values("观看次数", ascending=False).reset_index(drop=True)['观看次数'].plot() # 查看投币排序 data.sort_values("投币", ascending=False).reset_index(drop=True)['投币'].plot() # 查看一下根据投稿时间的播放量情况 plt.plot(data.set_index("上传日期")['观看次数'].sort_index()) plt.title(u'播放量', fontproperties=font_hei) # 得到对应的的番剧信息 data.set_index("上传日期")["2014"].sort_values("观看次数", ascending=False).iloc[0]
四、结论(10分)
1.经过对主题数据的分析与可视化,可以得到哪些结论?
1.观看次数、弹幕、评论、投币和分享之间都有很大的相关性。
2.收藏的的很多都是剧场版。可能是相对于TV版,剧场版制作更精良的缘故。
3. 播放次数到10000左右就趋近于持平。播放次数和投币次数的相关性很强,趋势几乎相同。
4.2014年末开始,播放量剧增。
2.对本次程序设计任务完成的情况做一个简单的小结。
在这次爬虫的过程中,最大的难点在于B站数据的爬取和破解B站反爬,通过上网查资料学习,终于成功获取了1327页的视频数据。