Python高级应用程序设计任务
Posted Silver_Sakura
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python高级应用程序设计任务相关的知识,希望对你有一定的参考价值。
Python高级应用程序设计任务要求
用Python实现一个面向主题的网络爬虫程序,并完成以下内容:
(注:每人一题,主题内容自选,所有设计内容与源代码需提交到博客园平台)
一、主题式网络爬虫设计方案(15分)
1.主题式网络爬虫名称
B站的视频信息爬取
2.主题式网络爬虫爬取的内容与数据特征分析
爬取B站搜索视频结果界面的主体视频信息(视频名,视频播放时间、视频播放数,视频弹幕数、视频上传时间)
数据特征,我做了简单的简化,视频时间采用字符串存储,上传时间也是,mysql存储也比较简单,处理起来也比较简单。因为B站最多的搜索页数为50,每页20,所以最多只有1000条记录,
不过因为本程序有一定的扩展性,只要关键字就可以爬取不同主题的信息记录。
3.主题式网络爬虫设计方案概述(包括实现思路与技术难点)
1.设计,一开始其实本来想做个系统的、爬虫,并且爬取视频内容,但开发时遇到了一定的阻碍,计划临时改变
1.1 设计如下:
printShow类实现数据处理可视化输出
dataSave类实现数据的持久化
creeper类实现数据的爬取与清洗
creeperMain模块为运行的组函数
1.2实现思路:
printShow类使用matplotlib模块实现数据可视化。
dataSave类使用pymysql模块实现数据处理。
creeper类使用requests、BeautifulSoup、dataSave模块实现网页请求,处理网页,爬取网页、获取数据、清理数据、数据的持久化
creeperMain模块为主程序入口
1.3技术难点:
首先是对于数据的爬取,要找到网站有用的数据、还要使用BeautifulSoup爬取网站信息,这步需要对于网站的了解,还有要建立在网站不经常改变标识的情况下,找到较为合适的筛选规则。
其次对于数据的处理和传递,数据如何以文本的形式提取出来,数据如何转换,比如10万如何转变为整形的100000
再来数据的持久化处理,怎么存储,怎么使用。
最后是对与整个系统架构的设计,如何完善
二、主题页面的结构特征分析(15分)
1.主题页面的结构特征
主体页面为B站的搜索页面,基本的特征,基本就是网页头、网页中部、网页尾部、其中有用的数据在网页中部的
存有视频信息,结构由于工作比较忙懒得写了,直接上图
2.Htmls页面解析
主体页面为B站的搜索页面,基本的特征,基本就是网页头、网页中部、网页尾部、其中有用的数据在网页中部的有用信息,
简单描述救赎ul标签中有20个li标签,每个li标签中有视频名,视频播放时间、视频播放数,视频弹幕数、视频上传时间爬,就完事了
3.节点(标签)查找方法与遍历方法
(必要时画出节点树结构)
直接上图:
画的比较难看,但是工作真的很忙
三、网络爬虫程序设计(60分)
爬虫程序主体要包括以下各部分,要附源代码及较详细注释,并在每部分程序后面提供输出结果的截图。
1.数据爬取与采集
使用模块化开发,模块为creeperBm,代码在如下
代码可实现功能挺多,我就不多写了,写几个典型的例子我觉得就行了。
2.对数据进行清洗和处理
使用模块化开发,模块为creeperBm,代码在如下
由于模块开发,功能合并,功能如上。
3.文本分析(可选):jieba分词、wordcloud可视化
这部分没做
4.数据分析与可视化
(例如:数据柱形图、直方图、散点图、盒图、分布图、数据回归分析等)
使用模块化开发,模块为printShow,代码在如下
plt自带的放大功能可看
用户体验可能差了点,标题忘记改了
但是程序命名上有所体现
这只是一部分功能,具体功能可以查看代码有注释
5.数据持久化
使用模块化开发,模块为dataSave,代码在如下
6.附完整程序代码
creeperBm模块:
#数据爬取加清洗模块,比较懒,放一起简单,主要是爬取B站搜索界面的一些视频信息。信息比较少也是因为懒。但是核心功能是有完成的。 #导入模块,这个不用多说了吧 import requests from bs4 import BeautifulSoup from dataSave import dataSave import time import numpy as np import re #定义creeper类,实现爬取和清洗功能 class creeper(object): #初始化 def __init__(self): pass # def creeperHtmlUrl(self,url): # reader=requests.get(url) # print(reader.text.title())没有用到 #B站搜索界面爬取获取reader url=路径 kw为关键词默认新宝岛,part为页数默认1 return reader def creeperSearchAll(self, url="https://search.bilibili.com/all", *, kw=\'新宝岛\', part=1): reader = requests.get(url, params={"keyword": kw, "page": part}) return reader # def creeperVideoHtmlAv(self,url="https://www.bilibili.com/video/",av="av53851218"): # reader = requests.get(url+av)没有用到 # def creeperVideoOnAv(self,url="https://www.bilibili.com/video/",av="av53851218"): # reader = requests.get(url + av) #数据获取VideoName list表 def creeperVideoName(self,reader): bs = BeautifulSoup(reader.text, "html.parser") videoli = bs.find_all("li", class_="video-item matrix") listVN=[] for item in videoli: # print(item.a["title"])#获取视频名 listVN.append(item.a["title"]) return listVN # 数据获取PlayTime list表 def creeperPlayTime(self,reader): bs = BeautifulSoup(reader.text, "html.parser") videoli = bs.find_all("li", class_="video-item matrix") listPT = [] for item in videoli: videotime = item.find_all("span", class_="so-imgTag_rb") for i in videotime : # print(i.get_text()) #视频长度 listPT.append(i.get_text()) return listPT # 数据获取PlayNum list表 def creeperPlayNum(self,reader): bs = BeautifulSoup(reader.text, "html.parser") videoli = bs.find_all("li", class_="video-item matrix") listPN=[] for item in videoli: time = item.find_all("span", title="观看") for i in time: # print(i.get_text()) if ("万") in i.get_text().strip(): listPN.append(int(float(i.get_text().strip()[0:-1])*10000)) else: listPN.append(int(i.get_text().strip())) return listPN # 数据获取VideoTime list表 def creeperVideoTime(self,reader): bs = BeautifulSoup(reader.text, "html.parser") videoli = bs.find_all("li", class_="video-item matrix") listVT=[] for item in videoli: time = item.find_all("span", title="上传时间") for i in time: # print(i.get_text()) listVT.append(i.get_text().strip()) return listVT # 数据获取DanNum list表 def creeperDanNum(self,reader): bs = BeautifulSoup(reader.text, "html.parser") videoli = bs.find_all("li", class_="video-item matrix") listDN=[] for item in videoli: dan=item.find_all("span", title="弹幕")#弹幕数量可迭代 for i in dan: # print(i.get_text()) if ("万") in i.get_text().strip(): listDN.append(int(float(i.get_text().strip()[0:-1])*10000)) else: listDN.append(int(i.get_text().strip())) return listDN #多页爬取信息并持久化处理 入参page,kw为关键字,默认新宝岛 def creeperAllForPage(self,page,kw=\'新宝岛\'): mysql = dataSave() db = mysql.initMySql() cur= db.cursor() for part in range(page): crer=creeper() readerpart=crer.creeperSearchAll( "https://search.bilibili.com/all", kw=kw ,part=part+1) if crer.creeperVideoName(readerpart)==[]: break listVN=crer.creeperVideoName(readerpart) listPT=crer.creeperPlayTime(readerpart) listDN=crer.creeperDanNum(readerpart) listPN=crer.creeperPlayNum(readerpart) listVT=crer.creeperVideoTime(readerpart) for i in range(len(listVN)): # print(range(len(listVN)))有点坑必须赋值之后再添加 datai={"videoname":listVN[i],"playtime":listPT[i],"dannum":listDN[i],"playnum":listPN[i],"videotime":listVT[i]} mysql.addToTable(db=db,cur=cur,kwargs=datai) print("页数较多会比较慢,请耐心等待") cur.close() db.close()
dataSave模块:
#工作太忙,代码基本写死了,可扩展性较弱,不过还行 #实际使用请自己建立数据库,实现数据的持久化 #127.0.0.1本地连接,你们连接不上运行肯定会出错的 #代码的优化还有可扩展性比较糟糕,不过就这样了,没时间了 #基本实现数据的持久化。creat、updata没做,不过基本不会用到 import pymysql #类dataSave class dataSave(object): #类初始化 def __init__(self): pass #初始化mysql连接 def initMySql(self): config = { "host": "localhost", "user": "root", "password": "1qaz@WSX", "port": 3308, "database": "python_creeper", } db = pymysql.connect(**config) return db #创建表,没做,可扩展项目 def creatTable(self): pass #添加记录,基本就是简单的sql语句插入记录,写死了。 def addToTable(self,*,db,cur,kwargs): sql ="INSERT INTO b_creeper(" \\ "video_name,play_time,dan_num,play_num,video_time)" \\ "values(%s,%s,%s,%s,%s)" # cur.execute(sql,("1","1",3,4,"5")) cur.execute(sql,(kwargs["videoname"],kwargs["playtime"],kwargs["dannum"],kwargs["playnum"],kwargs["videotime"])) db.commit() data = cur.fetchall() # 清空记录,基本就是简单的sql语句,写死了。(每次换关键词爬取就要清空一次,比较局限,防止数据冲突) def deleteToTableAll(self): mysql = dataSave() db = mysql.initMySql() cur = db.cursor() cur.execute("truncate table b_creeper ") cur.close() db.close() #查询记录个数 def queryNum(self,*,db,id): cur = db.cursor() cur.execute("select count(1) from a_student ") data = cur.fetchall() cur.close() db.close() #查询列video_time和play_num def queryTimeToNum(self): mysql =dataSave() db=mysql.initMySql() cur=db.cursor() cur.execute("SELECT video_time,play_num from b_creeper GROUP BY video_time ") data = cur.fetchall() cur.close() db.close() return data #查询列video_time,dan_num def queryTimeToDNum(self): mysql =dataSave() db=mysql.initMySql() cur=db.cursor() cur.execute("SELECT video_time,dan_num from b_creeper GROUP BY video_time ") data = cur.fetchall() cur.close() db.close() return data #查询列video_time和其对应个数count(video_time) def queryTimeToCNum(self): mysql =dataSave() db=mysql.initMySql() cur=db.cursor() cur.execute("SELECT video_time,count(video_time) from b_creeper GROUP BY video_time ") data = cur.fetchall() cur.close() db.close() return data #查询列dan_num def queryDanNumToBox(self): mysql =dataSave() db=mysql.initMySql() cur=db.cursor() cur.execute("SELECT dan_num from b_creeper ") data = cur.fetchall() cur.close() db.close() return data #查询列play_num def queryPlayNumToBox(self): mysql =dataSave() db=mysql.initMySql() cur=db.cursor() cur.execute("SELECT play_num from b_creeper ") data = cur.fetchall() cur.close() db.close() return data
printShow模块:
from creeperBm import creeper import matplotlib.pyplot as plt import numpy as np import pandas as pd #printShow数据可视化类,只做了简单的数据的条形统计,折线,还有箱型图,其他的没做 class printShow(object): def __init__(self): pass #以下都是绘制统计图,传入所需参数Bar条形,Plot折线,box箱型 #大部分都是重复的 def timeToNumBar(self,*,data): listVT = [] listPN = [] for item in data: listVT.append(item[0]) listPN.append(item[1]) plt.figure() plt.bar(listVT, listPN) plt.show() def timeToNumPlot(self,*,data): listVT = [] listPN = [] for item in data: listVT.append(item[0]) listPN.append(item[1]) plt.figure() plt.plot(listVT, listPN) plt.show() def timeToDNumBar(self,*,data): listVT = [] listDN = [] for item in data: listVT.append(item[0]) listDN.append(item[1]) plt.figure() plt.bar(listVT, listDN) plt.show() def timeToDNumPlot(self,*,data): listVT = [] listDN = [] for item in data: listVT.append(item[0]) listDN.append(item[1]) plt.figure() plt.plot(listVT, listDN) plt.show() def timeToCNumBar(self,*,data): listVT = [] listCN = [] for item in data: listVT.append(item[0]) listCN.append(item[1]) plt.figure() plt.bar(listVT, listCN) plt.show() def timeToCNumPlot(self,*,data): listVT = [] listCN = [] for item in data: listVT.append(item[0]) listCN.append(item[1]) plt.figure() plt.plot(listVT, listCN) plt.show() def danNumBox(self,*,data): df = pd.DataFrame(data) df.boxplot() plt.show() def playNumBox(self,*,data): df = pd.DataFrame(data) df.boxplot() plt.show()
creeperMain:
#本来想做一个较为系统的但是能力不够啊。所以我只做了个大概。 #可扩展性不强,很多地方偷懒数据、方法直接写死了。 #B站现在官方也不开放api了,野生的基本挂了,爬取视频比较麻烦。 #所以现在就只是基本完成功能,数据爬取,清洗,持久化、可视化处理。除了爬取跟清洗我一起做了其他都是一部分一个python模块 #搜索仅仅限于50页,最高的精度了。B站搜索最高1000的记录,更早的搜索不出来。 #本程序可以更换关键词,有可扩展性,以另外一种方式实现了对于数据条数的要求,有多少个关键词就有多少的记录 #模块化开发,有挺多的功能的,所以我就不一一写了 #每个部分去掉*号就可以执行,有关数据库的,要自己安装,更改配置。我用的本地自己的数据库,外网是不可能连接到的。 from creeperBm import creeper from printShowM import printShow from dataSave import dataSave from bs4 import BeautifulSoup import requests import matplotlib.pyplot as plt import numpy as np import pandas as pd #打印网页html # c=creeper() # reader=c.creeperSearchAll("https://search.bilibili.com/all",kw="python",part=1) # print(reader.text) #获取listVN # c=creeper() # reader=c.creeperSearchAll("https://search.bilibili.com/all",kw="python",part=1) # listVN=c.creeperVideoName(reader) # print(listVN) #删除所有记录 # mysql = dataSave() # db = mysql.initMySql() # mysql.deleteToTableAll() #爬取多页信息存储持久化 20页,可以更多最多50,记得删除记录 # c=creeper() # c.creeperAllForPage(20,kw="英雄联盟") #查询列video_time和play_num # d=dataSave() # data=d.queryTimeToNum() # print(data) #数据可视化模块 # d=dataSave() # p=printShow() # data=d.queryTimeToNum() # p.timeToNumBar(data=data) #数据可视化模块plot # d=dataSave() # p=printShow() # data=d.queryTimeToNum() # p.timeToNumPlot(data=data) #数据可视化模块box # d=dataSave() # p=printShow() # data=d.queryDanNumToBox() # p.danNumBox(data=data)
四、结论(10分)
1.经过对主题数据的分析与可视化,可以得到哪些结论?
1.对弹幕数来说英雄联盟关键词在B站的弹幕数主要集中在2000以下,少数会超过10000,所以所在B站做视频还是挺辛苦的,处于中下游的up主居多。
2.对于视频和播放数柱状图和折线图来说B站的视频播放数一般会在有节日意义的日子变多,比如12.12日、11月11日等
3.对于视频和弹幕数柱状图和折线图来说B站的视频弹幕数一般会在有节日意义的日子变多,比如12.12日、11月11日等
4.从我未列举出来的数据表(视频的上传时间统计表)可以得出B站up一般会选择在有意义的节日上传视频,来提高播放和弹幕数。
5.根据所有数据可以得出结论,B站有关英雄联盟视频弹幕数主要集中在2000以下,但是也有弹幕数十分多的视频最高可对于140000
2.对本次程序设计任务完成的情况做一个简单的小结。
这次的程序,总体来说较为失败,没有较好的完成先前的指标,临时改变了开发方向,对于用户的体验也不是十分的友好,数据可视化也做的较为糟糕,但是基本来说完成了任务,
数据量的要求还是有达到的,数据的可视化虽然做的不够完善,但是仔细查看代码,会发现,代码的框架和架构还是ok的,不过可扩展性较差,但是基本所有的要求都有达到,
望老师,给个及格。工作了,时间比较少,也没办法。有时间的话可能会填下这个坑,不过,最近基本没时间了。(咕咕咕)以上是关于Python高级应用程序设计任务的主要内容,如果未能解决你的问题,请参考以下文章