20253202 2025-2026-2 《Python程序设计》实验四报告

《Python程序设计》实验四报告

课程:《Python程序设计》
班级:2532
姓名:吴江浩
学号:20253202
实验教师:王志强
实验日期:2026年5月25日
必修/选修:公选课

1. 实验内容

Python综合应用:爬虫、数据处理、可视化、机器学习、神经网络、游戏、网络安全等。

本次Python实践我开发了一款网络热梗对决游戏,通过爬虫技术从B站获取热门视频数据,将数据转化为游戏角色属性,实现梗与梗之间的回合制对战。游戏包含梗图鉴、实时对战、赔率系统、礼物榜单等核心功能,全程采用模块化设计,代码结构相对清晰、功能可以说是完整、运行大部分时候稳定。


2. 实验过程及结果

(一)第一阶段:B站搜索爬虫开发

一开始我先构思编写了B站视频搜索的爬虫,来实现从B站API获取视频数据的功能,

核心代码详解:

import requests

def search(kw, max_n=100):
    u = "https://api.bilibili.com/x/web-interface/search/all"
    h = {"User-Agent": "Mozilla/5.0"}
    v = []
    seen = set()
    p = 1
    low = 0
    while len(v) < max_n:
        par = {"keyword": kw, "page": p, "limit": 20}
        try:
            r = requests.get(u, headers=h, params=par, timeout=10)
            d = r.json()
            if d["code"] != 0:
                break
            res = d.get("data", {}).get("result", {})
            if "video" not in res or not isinstance(res["video"], list):
                break
            pv = res["video"]
            if not pv:
                break
            for it in pv:
                b = it.get("bvid", "")
                if b and b in seen:
                    continue
                t = it.get("title", "")
                t = t.replace("<em class=\"keyword\">", "").replace("</em>", "").replace("\xa0", " ")
                vw = it.get("play") or 0
                vd = {
                    "title": t,
                    "bvid": b,
                    "view": vw,
                    "like": it.get("like") or 0,
                    "comment": it.get("video_review") or 0,
                    "author": it.get("author", "")
                }
                v.append(vd)
                if b:
                    seen.add(b)
                if vw < 1000:
                    low += 1
                    if low >= 5:
                        return v
                else:
                    low = 0
            p += 1
        except Exception:
            break
    return v[:max_n]

功能说明:

  • 通过B站搜索API获取关键词相关视频数据
  • 最多获取100个视频
  • 去重处理:通过bvid避免重复视频
  • 质量过滤:连续5个播放量低于1000的视频则停止搜索
  • 数据清洗:去除标题中的HTML标签和特殊字符

数据汇总函数:

def agg(v):
    if not v:
        return None
    tv = sum(x["view"] for x in v)
    tl = sum(x["like"] for x in v)
    tc = sum(x["comment"] for x in v)
    c = len(v)
    return {
        "count": c,
        "total_view": tv,
        "total_like": tl,
        "total_comment": tc,
        "avg_view": int(tv / c),
        "avg_like": int(tl / c),
        "avg_comment": int(tc / c),
        "videos": v
    }

(二)第二阶段:梗战斗游戏开发

基于获取的视频数据,我产生了为了全方面的对比互联网热梗的热度,开发将视频数据转化为游戏角色属性的对战游戏的思路,然后经过推敲确定回合制对战游戏(其他非数值对碰的战斗机制太难写了,但是直接判胜负出结果的话又太无聊)。在开发过程中,我遇到了模块导入的问题。最初是导入Bsarch模块,但由于文件名使用了中文命名(B站搜索.py),直接使用 from b站搜索 import 会导致一些问题。后来我将 b站搜索.py 中的 fmt 函数统一重命名为 format_num ,保持了模块间接口的一致性,方便调用。

核心代码详解:

1. 角色属性计算类(MF)

import random
from b站搜索 import search_videos, format_num

class MF:
    def __init__(self, kw, vs):
        self.kw=kw
        p=sum(v["view"] for v in vs)
        l=sum(v["like"] for v in vs)
        c=sum(v["comment"] for v in vs)
        tv=sorted(vs,key=lambda x:x["view"],reverse=True)[:100]
        pa=int(sum(v["view"] for v in tv)/len(tv)) if tv else 0
        la=int(sum(v["like"] for v in tv)/len(tv)) if tv else 0
        ca=int(sum(v["comment"] for v in tv)/len(tv)) if tv else 0
        hp=0.6*p+0.3*l+0.1*c
        atk=0.5*pa+0.5*la
        df=(l/p*1000) if p>0 else 0
        sp=ca
        k1=(pa*100)/p if p>0 else 0
        k2=(la*100)/l if l>0 else 0
        if k1<0.85 and k2<0.85: job,jen="洪流巨兽","TANK"
        elif k1>1.15 and k2>1.15: job,jen="巅峰剑客","ASSASSIN"
        else: job,jen="均衡战神","WARRIOR"
        r=random.uniform(0.92,1.08)
        self.hp_r,self.atk_r,self.df_r,self.sp_r=hp*r,atk*r,df*r,sp*r
        self.ihp=self.hp_r

属性转换逻辑:

  • HP(生命值):0.6×总播放 + 0.3×总点赞 + 0.1×总评论
  • ATK(攻击力):0.5×平均播放 + 0.5×平均点赞
  • DEF(防御力):(点赞/播放)×1000,反映内容质量
  • SPD(速度):平均评论数,反映话题活跃度
  • 职业判定:根据K1/K2系数判断(洪流巨兽/TANK、巅峰剑客/ASSASSIN、均衡战神/WARRIOR)

2. 战斗系统类(BS)

class BS:
    def __init__(self,a,b): self.a,self.b,self.rnd=a,b,0
    
    def start(self):
        a,b=self.a,self.b
        fst,sec=(a,b) if a.sp_r>=b.sp_r else (b,a)
        atk,dfn=fst,sec
        while True:
            self.rnd+=1
            db=dfn.buff()
            bd=atk.atk_r-dfn.df_r*0.4
            if bd<10: bd=10
            rmap={"洪流巨兽":{"巅峰剑客":1.2,"均衡战神":0.85},
                  "巅峰剑客":{"均衡战神":1.2,"洪流巨兽":0.85},
                  "均衡战神":{"洪流巨兽":1.2,"巅峰剑客":0.85}}
            rm=1.0 if atk.job==dfn.job else rmap.get(atk.job,{}).get(dfn.job,1.0)
            d1=bd*rm
            cr=atk.sp_r>=dfn.sp_r*1.1
            dmg=d1*(1.7 if cr else 1)
            dfn.hurt(dmg)
            if dfn.hp_r<=0:
                winner,loser=atk,dfn.kw
                break
            atk,dfn=dfn,atk
            if self.rnd>=100: 
                print("\n战斗超过100回合,平局!")
                return
        return winner

为了增强游戏趣味性,我推敲出了一套相对有些意思的战斗系统,灵感来源于网络游戏;同时为了在延缓游戏时间的同时不至于太过无聊,我增添了战斗日志功能,并汲取洛克王国、宝可梦等游戏的描述,让战斗描写更灵活有趣。

战斗机制详解:

  • 先手判定:速度值高者先手
  • 伤害公式:(攻击力 - 防御力×0.4) × 职业克制系数 × 暴击系数
  • 职业克制:洪流巨兽克制巅峰剑客,巅峰剑客克制均衡战神,均衡战神克制洪流巨兽
  • 暴击判定:速度差超过10%时触发1.7倍暴击
  • 残血Buff:HP低于30%时防御力提升15%

(三)第三阶段:热梗对决整合版

在完成基础爬虫和战斗系统后,我借助大模型的帮助,将功能整合为完整的GUI应用,包括:

  1. 梗图鉴系统:浏览和搜索热梗,查看详细数据
  2. 对战系统:完整的回合制对战界面
  3. 赔率系统:较完善的数值规划
  4. 礼物榜单:实时显示玩家礼物变化
  5. 规则说明:详细的游戏规则介绍

(四)运行效果

游戏实现了完整的对战流程:

  • 玩家选择热梗进行对战
  • 系统自动爬取B站数据生成角色属性
  • 回合制战斗,包含暴击、职业克制等机制
  • 结算时显示礼物变化榜单

代码仓库如下:
b站搜索
战斗系统
最终整合版

3. 实验过程中遇到的问题和解决过程

问题一:模块导入失败,程序无法启动

现象:运行梗战斗.py时提示找不到format_num函数,程序直接崩溃。

解决:一开始我以为是缺少AIserver.py文件,后来发现其实是b站搜索.py中的函数命名不一致——定义的是fmt函数,但梗战斗.py导入时找的是format_num。最后把b站搜索.py里的fmt统一改成了format_num,所有调用的地方也一起改了,程序就能正常运行了。

问题二:爬虫返回的数据质量参差不齐

现象:搜索某些冷门梗时,会返回大量播放量低于1000的低质量视频,导致生成的角色属性数值特别低。

解决:在爬虫里加了个质量过滤机制——连续遇到5个播放量低于1000的视频就停止搜索。这样既能保证数据量,又能过滤掉那些没什么热度的视频,让角色属性更有参考价值。

问题三:GUI界面按钮被遮挡

现象:在最终版的功能“梗详情”页面,返回按钮有时候会被内容区域挡住,点不到。

解决:询问了AI一下,发现是有关Tkinter的组件层级问题,是创建顺序的问题,先创建的组件会被后创建的覆盖。后来调整了创建顺序,先建内容区域,再建按钮,这样按钮就显示在最上层了。

4.课程总结

上Python课学到了:
基础语法方面:比如 for 循环,while 循环等语句,输入输出
字符串:切片,字符串的转化等等
数据结构:列表,set等等
socket:协议传输,握手等等
爬虫:robots的含义,request库的用法,header的作用

5.感悟体会和意见建议

说实话,这学期学Python真的让我收获挺大的。一开始接触的时候,看着那些代码就头大,连个 print 语句都要琢磨半天。但跟着王老师学了一段时间后,慢慢学会了一点。从最基础的变量、循环,到后来的函数、差不多。
感觉最有意思的应该是做热梗对决这个项目。一开始只是想写个爬虫爬B站视频数据,后来越做越复杂,做成一个完整的游戏。第一次成功爬取到视频数据的时候,心里特别激动,感觉能做出点东西来了。
不过过程挺折腾。比如那个战斗系统,属性计算公式改了好几版,数值更是不知道咋填,就是为了让游戏平衡一点。还有UI界面,大模型简直无法理解我的要求,没次小改动一下整个游戏都打不开了,后来慢慢摸索才弄明白怎么让它合理布局、绑定事件。
最大的感悟就是编程其实没想象中那么难。以前总觉得会写代码的人都特别厉害,但自己学了之后发现,确实厉害,尤其是能做出挺有意思的东西的人。做这个热梗对决游戏的时候踩了不少坑。比如爬虫经常被封IP,数据解析老是出错。但每次解决一个问题,就觉得进一点。
关于课程的建议,我觉得可以多推荐自学资料。抽零碎时间做,应该能学到更多东西。
最后,感谢王老师,上课特别有意思,经常会举一些好玩的例子,更容易理解。这学期能学到这么多东西,多亏了您的教导。最后祝愿王老师工作顺利,身体健康!

posted @ 2026-06-02 19:52  YUXI8640  阅读(43)  评论(0)    收藏  举报