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应用,包括:
- 梗图鉴系统:浏览和搜索热梗,查看详细数据
- 对战系统:完整的回合制对战界面
- 赔率系统:较完善的数值规划
- 礼物榜单:实时显示玩家礼物变化
- 规则说明:详细的游戏规则介绍
(四)运行效果
游戏实现了完整的对战流程:
- 玩家选择热梗进行对战
- 系统自动爬取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,数据解析老是出错。但每次解决一个问题,就觉得进一点。
关于课程的建议,我觉得可以多推荐自学资料。抽零碎时间做,应该能学到更多东西。
最后,感谢王老师,上课特别有意思,经常会举一些好玩的例子,更容易理解。这学期能学到这么多东西,多亏了您的教导。最后祝愿王老师工作顺利,身体健康!
浙公网安备 33010602011771号