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,代码在如下
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()

  

四、结论(10分)
1.经过对主题数据的分析与可视化,可以得到哪些结论?


2.对本次程序设计任务完成的情况做一个简单的小结。

12-20 00:07
查看更多