python大作业有哪些题目,python期末大作业项目

这篇文章主要介绍了python大作业有哪些题目,具有一定借鉴价值,需要的朋友可以参考下。希望大家阅读完这篇文章后大有收获,下面让小编带着大家一起了解一下。

【超详细指北】python大作业!

​ 这是笔者最近写python大作业时写的一个实现过程笔记,也就是基本上可以说是本人从0开始上手的一个python练习。程序和本文档从 4.29-5.15日 总共历时17天python动态爱心代码。包含了大部分代码内容。

一、获取数据

(1)user-agent和cookie

user-agent

在这里插入图片描述

Cookie:

在这里插入图片描述

buvid3=11707BB8-8181-70C7-EBE1-FB1609F40FC370555infoc; i-wanna-go-back=-1; _uuid=F4221228-EF95-B7F10-49C1-F710CAC68D109F77140infoc; buvid4=E437889C-0A9F-DEF4-C164-E3F9F456407172347-022032622-MnLxL6Vqo8K/D8N1XzXHLQ%3D%3D; nostalgia_conf=-1; buvid_fp_plain=undefined; blackside_state=1; rpdid=|(J~J|R~m)Jm0J'uYR)Jm~JYR; CURRENT_BLACKGAP=0; hit-dyn-v2=1; LIVE_BUVID=AUTO4316488832212386; bp_article_offset_154100711=649151673891029000; SESSDATA=fbf8b924%2C1666235070%2C5c5a7%2A41; bili_jct=2f4e142aa58387a4ba58d6610a138881; DedeUserID=154100711; DedeUserID__ckMd5=4a5f601a3689140a; sid=7m78ki9o; CURRENT_QUALITY=0; fingerprint=a0d6414c1242c8cb9c9f7b4f70d4d671; b_ut=5; CURRENT_FNVAL=4048; bsource=search_baidu; b_lsid=AB9536C2_1807AC90CF7; _dfcaptcha=0f5ba157af594817171639f2996e0b43; PVID=1; innersign=1; buvid_fp=a0d6414c1242c8cb9c9f7b4f70d4d671; bp_video_offset_154100711=654934739730300900; fingerprint3=5ad9983134e17174abef4db7b440a5ab
(2)commentData类

​ 该类是获取某一视频的所有评论信息,包括一级评论、二级评论,获取了评论用户的基本信息和评论内容。在该类中,设置headersCookie防止反爬,此外还有一个fake_useragent库也可以防止反爬虫,在这里没有使用该库。

写在前面

​ 首先我们来分析一级评论:

一级评论:

在这里插入图片描述

在这里插入图片描述

​ 根据浏览器f12自带的调试中,我们查找存放评论内容的api。这里给出三个不同视频的评论接口:

三个网页的一级评论api及来源
https://api.bilibili.com/x/v2/reply/main?callback=jQuery17208590914915452643_1651207947683&jsonp=jsonp&next=0&type=1&oid=34491719&mode=3&plat=1&_=1651207949390
【https://www.bilibili.com/video/BV1ot411R7SM?spm_id_from=333.999.0.0】

https://api.bilibili.com/x/v2/reply/main?callback=jQuery33102399794496926384_1651209840924&jsonp=jsonp&next=0&type=1&oid=768445836&mode=3&plat=1&_=1651209840925
【https://www.bilibili.com/video/BV11r4y1J7cH?spm_id_from=333.999.0.0】

https://api.bilibili.com/x/v2/reply/main?callback=jQuery17203622673329462698_1651210156500&jsonp=jsonp&next=0&type=1&oid=721394418&mode=3&plat=1&_=1651210156936
【https://www.bilibili.com/video/BV1fQ4y1q7SB/?spm_id_from=333.788.recommend_more_video.16】
  1. https://api.bilibili.com/x/v2/reply/main?callback=jQuery17208590914915452643_1651207947683&jsonp=jsonp&next=0&type=1&oid=34491719&mode=3&plat=1&_=1651207949390

  2. https://api.bilibili.com/x/v2/reply/main?callback=jQuery33102399794496926384_1651209840924&jsonp=jsonp&next=0&type=1&oid=768445836&mode=3&plat=1&_=1651209840925

  3. https://api.bilibili.com/x/v2/reply/main?callback=jQuery17203622673329462698_1651210156500&jsonp=jsonp&next=0&type=1&oid=721394418&mode=3&plat=1&_=1651210156936

    可见在加粗部分是不同的

第一个api中:

https://api.bilibili.com/x/v2/reply/main?callback=jQuery17208590914915452643_1651207947683&jsonp=jsonp&next=0&type=1&oid=34491719&mode=3&plat=1&_=1651207949390

在这里插入图片描述

删除第一个和最后一个参数(因为我们不需要js请求,最后一个参数也没有什么影响),得到

一级评论:https://api.bilibili.com/x/v2/reply/main?jsonp=jsonp&next=0&type=1&oid=34491719&mode=3&plat=1

在这里插入图片描述

  • ​ next:翻页
  • ​ oid:视频编号(aid)
  • ​ mode:1、2表示按热度、时间排序; 0、3表示按热度排序,并显示评论和用户信息
二级评论:

​ 二级评论也就是视频评论的评论,也就是有人回复评论时的评论。

在这里插入图片描述

https://api.bilibili.com/x/v2/reply/reply?callback=jQuery17202729032535004876_1651213886637&jsonp=jsonp&pn=1&type=1&oid=34491719&ps=10&root=1426909940&_=1651213945276

同上删除首尾参数后得到:

二级评论:https://api.bilibili.com/x/v2/reply/reply?jsonp=jsonp&pn=1&type=1&oid=34491719&ps=10&root=1426909940

在这里插入图片描述

  • ​ pn:翻页
  • ​ oid:视频oid
  • ​ ps: 单页显示数量(最大为20)
  • ​ root:楼主的回复的rpid

视频的oid可通过视频BV号获取rpid可以通过一级评论获取(随后我们进行获取)

最后一页评论:

​ 我们自己根据一级评论的api,手动查找到最后一页评论,发现当没有评论时,data下的replies为null,机当前api中next的参数值为最后一页的页码,如果有评论时replies不为空。

因此我们在爬取所有评论时可以将replies是否为null作为循环退出条件。

https://api.bilibili.com/x/v2/reply/main?jsonp=jsonp&type=1&oid=34491719&mode=0&plat=1&next=28

在这里插入图片描述

在这里插入图片描述

1.构造函数init

初始化基本内容:

  • mid:up主的uid,传入参数
  • name:up主的姓名,传输参数
  • BV:爬取视频的BV号,传入参数
  • mode:排序方式(这里笔者所写的类中其实一直默认的0,也就是默认排序,其他自测):1、2表示按热度、时间排序; 0、3表示按热度排序,并显示评论和用户信息,传入参数
  • header:请求时的header,默认值,可自行更改
  • cookies:设置header和cookie防止网站反爬,传入参数
  • page:评论页数,通过爬取时根据api返回的replies是否为空进行判断是否爬取完毕,对self.page进行累加,来达到计算总共评论的总数量的目的。
  • BVName:视频名称,!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  • homeUrl:api的网址开头部分
  • oid:视频的id,通过**oid_get(self, BV)**函数返回oid值。
  • replyUrl:一级评论的api
  • rreplyUrl:二级评论的api
  • q:创建的队列,将content_get方法返回爬取内容并存入队列,通过csv_writeIn方法从q队列中进行取出存取,方便多线程工作,是一个生产着消费者模式。
  • count:当前评论楼数,指定主楼数,区别是评论还是评论的评论

因为在获取BVName和oid时,需要homeUrl,所以我们讲homeUrl放置在BVName和oid之前

    def __init__(self, mid, name, BV, mode, cookies):

        self.mid = mid          #up主的uid
        self.name = name        #up主的账号名称
        self.BV = BV            # BV:视频id号
        self.mode = mode        # mode:1、2表示按热度、时间排序; 0、3表示按热度排序,并显示评论和用户信息
        self.headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36 Edg/100.0.1185.50'
        }
        self.cookies = cookies  # 设置headers和Cookie防止反爬,还有一个fake_useragent库也可以用
        self.page = 0           # page:评论页数,出最后一页每页20条

        self.homeUrl = "https://www.bilibili.com/video/"
        self.BVName = self.BVName_get(self.BV)
        self.oid = self.oid_get(self.BV)

        #一级评论和二级评论
        self.replyUrl="https://api.bilibili.com/x/v2/reply/main?jsonp=jsonp&type=1&oid={oid}&mode={mode}&plat=1&next=".format(oid=self.oid,mode=mode)#next=0
        self.rreplyUrl = "https://api.bilibili.com/x/v2/reply/reply?jsonp=jsonp&type=1&oid={oid}&ps=20&root={root}&pn=".format(oid=self.oid, root="{root}")#pn=1

        self.q = queue.Queue()  # 用来存放爬取的数据,通过队列可以按顺序,使用多线程存入数据库或csv文件中
        # 这里我们用到了队列,好处在于,可以用多线程边爬边存,按顺序先进先出
        self.count = 1  # count变量指定主楼数,区别是评论还是评论的评论
2.获取视频oid和获取视频名称方法

​ 方法一:通过正则从response中选择以字符串aid开头的值并将其进行返回。

​ 方法二:通过BeautifulSoup4类获取视频名称,获取含有视频名称的标签,从而通过自带大string方法获取名称

(78条消息) Python中BeautifulSoup库的用法_阎_松的博客-CSDN博客_beautifulsoup库的作用

	# 获取视频 oid
    def oid_get(self, BV):
        # 请求视频页面
        response = requests.get(url=self.homeUrl + BV).text
        # 用正则表达式 通过视频 bv 号获取 oid
        oid = re.findall("\"aid\":([0-9]*),", response)[0]#寻找以字符串aid开头的值
        print("oid:" + oid)
        return oid

    def BVName_get(self,BV):
        # 请求视频页面
        response = requests.get(url=self.homeUrl + BV).text
        soup = BeautifulSoup(response, "html.parser", from_encoding="utf-8")
        nameResultSet = soup.find_all(attrs={'class': 'tit'})  # [<span class="tit">城市与山里的差距,真正体验过,我来告诉你!</span>]
        result = nameResultSet[0].string                       #城市与山里的差距,真正体验过,我来告诉你!
        print("BVName:" + result)
        return result
3.评论内容获取

​ 首先我们请求函数传递url,page(最大页面数,最终代码会删掉这个page参数,因为通过判断replies是否为空来获取所有页码的评论,就不需要指定获取页码的内容了),通过requests库请求数据,需要的数据都在data->replies里面,将该内容用一个列表保存。

在这里插入图片描述

在这里插入图片描述

​ 评论内容详细分析:其中是该视频的主要评论(也就是一级评论),其下有部分回复该评论的子评论,详细内容包含了评论的id、视频的id、时间戳、评论内容等等,其中主要信息为

  1. rpid:评论id
  2. oid:该视频的oid
  3. mid:账户的uid
  4. rcount :回复数
  5. ctime:时间戳
  6. like:点赞数
  7. member–>sign:用户标签,即用户的个性签名
  8. content–>message:评论内容
  9. replies:评论列表
  10. replies–>rpid:子评论的id
  11. replies–>level :用户等级

在这里插入图片描述

​ 获取一级评论的数据:

    #获取当前页面的评论
    def content_get(self, url, page):
        now = 0    # 当前页面
        while now<=page:
            print("page : <{now}>/<{page}>".format(now=now, page=page))
            response = requests.get(url=url+str(now), cookies=self.cookies, headers=self.headers, timeout=10).json()        # 把response解析为json格式,通过字典获取
            replies = response['data']['replies']     # 评论数据在data->replies 里面,每页有 20 条
            now += 1
            for reply in replies:                    # 遍历获取每一条,用reply_clean函数提取数据
                line = self.reply_clean(reply)
                self.count += 1

​ 因为一二级评论格式基本一致,所以将上面获取一级评论的数据的代码修改一下,增加复用性。

​ 这里新增了level_1来判断是否是一级评论,如果是则进行请求下一级,否则不请求。

​ 此外,这里将page参数进行了删除,通过之前分析的,通过判断replies是否为空来判断是否到达评论的最后一页。

    #数据获取:获取当前页面的评论
    def content_get(self, url, level_1=True):
        # level_1判断是否为一级评论。如果为二级评论,则不请求下一级评论(评论的评论)
        now = 1
        while True:
            if level_1:
                print("page : <{now}>".format(now=now))

            response = requests.get(url=url + str(now), cookies=self.cookies, headers=self.headers).json()
            print(url + str(now))
            replies = response['data']['replies']  # 评论数据在data->replies 里面,一共有 20 条

            if (replies == None)and(now == 1):
                #因为当next==0时和next==1时的评论内容是一样的,所以单独写出来一种情况:该视频没有任何评论
                self.page=0
                print("该页没有评论......")
                return
            elif replies == None:
                self.page = now - 1
                print("评论信息获取完成......")
                return
            elif replies != None:
                now += 1
                for reply in replies:
                    # 一级评论则去请求下一级评论
                    if level_1:
                        line = self.reply_clean(reply, self.count)
                        self.count += 1
                    else:
                        line = self.reply_clean(reply)
                    self.q.put(line)
                    # 这儿我们可以筛选一下,如果有二级评论,调用函数请求二级评论
                    if level_1 == True and line[-2] != 0:#如果是一级评论且 回复数 不为零 则去请求二级评论
                        self.content_get(url=self.rreplyUrl.format(root=str(line[-1])), level_1=False)  # 递归获取二级评论
4.数据清洗

​ 因为replies下的数据过多而且繁杂,而我们不需要这么多的数据,所以我们进行一下数据的“清洗”,只返回我们需要的数据信息。

​ 将评论时间的时间戳通过time库转换成正常格式。通过之前分析的含义,将需要的信息保存并且返回为列表类型。为了使程序更具用复用性,这里兼容清洗二级评论数据,增加count参数,默认为false,表示是否是二级评论。

​ 如果是二级评论,则返回数据第一个为"回复",否则为楼号。

​ 二级评论没有回复数rcount,三级评论都显示为 回复xxx @谁谁谁

    # 数据清洗,将我们需要的数据进行筛选返回
    def reply_clean(self, reply, count=False):
        # 这个函数可以爬一级评论也能爬二级评论
        # count 参数,看看是不是二级评论。
        name = reply['member']['uname']  # 名字
        sex = reply['member']['sex']    # 性别:男/女/保密
        mid = reply['member']['mid']    # 帐号的uid
        sign = reply['member']['sign']  # 个性签名
        rpid = reply['rpid']            # 评论的id,爬二级评论要用到
        rcount = reply['rcount']        # 回复数
        level = reply['member']['level_info']['current_level']  # 用户等级
        like = reply['like']            # 点赞数
        content = reply['content']['message'].replace("\n", "")  # 评论内容
        t = reply['ctime']              #时间戳
        timeArray = time.localtime(t)
        otherStyleTime = time.strftime("%Y-%m-%d %H:%M:%S", timeArray)  # 评论时间,时间戳转为标准时间格式,2022-05-05 19:15:14
        # 如果是二级评论,则返回数据第一个为"回复",否则为楼号
        # 二级评论没有回复数rcount,三级评论都显示为 回复xxx @谁谁谁
        if count:
            return [count, name, sex, level, mid, sign, otherStyleTime, content, like, rcount, rpid]
        else:
            return ["回复", name, sex, level, mid, sign, otherStyleTime, content, like, ' ', rpid]
5.存储评论内容

​ 将信息存放在dirname的文件夹下,在该文件夹下细分为up主自己的文件夹和视频的文件夹。每次写入一行数据,即将line的列表信息进行写入。不断从队列q中取出内容并保存。最后恢复到开始的工作目录。

完整代码:

    #csv文件保存数据
    def csv_writeIn(self, mid, name, BV, BVName ):
        dirname = '视频评论信息'
        begin = os.getcwd()  # 保存开始文件工作路径
        # 如果没有该文件夹则创建一个
        if not os.path.isdir(dirname):
            os.mkdir(dirname)
        os.chdir(dirname)  # 改变当前工作目录到指定的路径

        fileName = str(mid) + "-" + str(name)  # up主的文件夹:uid-name
        if not os.path.isdir(fileName):
            os.mkdir(fileName)
        os.chdir(fileName)

        fileName = str(BV) + "-" + str(BVName)  # BV视频的文件夹:BV-BVname
        if not os.path.isdir(fileName):
            os.mkdir(fileName)
        os.chdir(fileName)

        file = open("bilibili评论_" + BV + ".csv", "w", encoding="utf-8", newline="")
        f = csv.writer(file)
        line1 = ['楼层', '姓名', '性别', '等级', 'uid', '个性签名', '评论时间', '评论内容', '点赞数', '回复数', 'rpid']
        f.writerow(line1)
        file.flush()
        while True:
            try:
                line = self.q.get(timeout=10)
            except:
                break
            f.writerow(line)
            file.flush()
        file.close()

        os.chdir(begin)  # 恢复文件工作路径
6.commentData类代码
import os
import time
import requests
import re
import queue
import csv
from threading import Thread
from bs4 import BeautifulSoup

#该类实现爬取保存一个视频的评论信息。
class commentData:
    #构造函数__init__,设置基础信息
    def __init__(self, mid, name, BV, mode, cookies):

        self.mid = mid          #up主的uid
        self.name = name        #up主的账号名称
        self.BV = BV            # BV:视频id号
        self.mode = mode        # mode:1、2表示按热度、时间排序; 0、3表示按热度排序,并显示评论和用户信息
        self.headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36 Edg/100.0.1185.50'
        }
        self.cookies = cookies  # 设置headers和Cookie防止反爬,还有一个fake_useragent库也可以用
        self.page = 0           # page:评论页数,出最后一页每页20条

        self.homeUrl = "https://www.bilibili.com/video/"
        self.BVName = self.BVName_get(self.BV)
        self.oid = self.oid_get(self.BV)

        #一级评论和二级评论
        self.replyUrl="https://api.bilibili.com/x/v2/reply/main?jsonp=jsonp&type=1&oid={oid}&mode={mode}&plat=1&next=".format(oid=self.oid,mode=mode)#next=0
        self.rreplyUrl = "https://api.bilibili.com/x/v2/reply/reply?jsonp=jsonp&type=1&oid={oid}&ps=20&root={root}&pn=".format(oid=self.oid, root="{root}")#pn=1

        self.q = queue.Queue()  # 用来存放爬取的数据,通过队列可以按顺序,使用多线程存入数据库或csv文件中
        # 这里我们用到了队列,好处在于,可以用多线程边爬边存,按顺序先进先出
        self.count = 1  # count变量指定主楼数,区别是评论还是评论的评论

    # 获取视频 oid
    def oid_get(self, BV):
        # 请求视频页面
        response = requests.get(url=self.homeUrl + BV).text
        # 用正则表达式 通过视频 bv 号获取 oid
        oid = re.findall("\"aid\":([0-9]*),", response)[0]#寻找以字符串aid开头的值
        print("oid:" + oid)
        return oid

    def BVName_get(self,BV):
        # 请求视频页面
        response = requests.get(url=self.homeUrl + BV).text
        soup = BeautifulSoup(response, "html.parser", from_encoding="utf-8")
        nameResultSet = soup.find_all(attrs={'class': 'tit'})  # [<span class="tit">城市与山里的差距,真正体验过,我来告诉你!</span>]
        BVName = nameResultSet[0].string                       #城市与山里的差距,真正体验过,我来告诉你!
        print("BVName:" + BVName)
        return BVName

    #数据获取:获取当前页面的评论
    def content_get(self, url, level_1=True):
        # level_1判断是否为一级评论。如果为二级评论,则不请求下一级评论(评论的评论)
        now = 1
        while True:
            if level_1:
                print("page : <{now}>".format(now=now))

            response = requests.get(url=url + str(now), cookies=self.cookies, headers=self.headers).json()
            print(url + str(now))
            replies = response['data']['replies']  # 评论数据在data->replies 里面,一共有 20 条

            if (replies == None)and(now == 1):
                #因为当next==0时和next==1时的评论内容是一样的,所以单独写出来一种情况:该视频没有任何评论
                self.page=0
                print("该页没有评论......")
                return
            elif replies == None:
                self.page = now - 1
                print("评论信息获取完成......")
                return
            elif replies != None:
                now += 1
                for reply in replies:
                    # 一级评论则去请求下一级评论
                    if level_1:
                        line = self.reply_clean(reply, self.count)
                        self.count += 1
                    else:
                        line = self.reply_clean(reply)
                    self.q.put(line)
                    # 这儿我们可以筛选一下,如果有二级评论,调用函数请求二级评论
                    if level_1 == True and line[-2] != 0:#如果是一级评论且 回复数 不为零 则去请求二级评论
                        self.content_get(url=self.rreplyUrl.format(root=str(line[-1])), level_1=False)  # 递归获取二级评论


    # 数据清洗,将我们需要的数据进行筛选返回
    def reply_clean(self, reply, count=False):
        # 这个函数可以爬一级评论也能爬二级评论
        # count 参数,看看是不是二级评论。
        name = reply['member']['uname']  # 名字
        sex = reply['member']['sex']    # 性别:男/女/保密
       
  • 8
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值