· 7 min read · 1326 words · Journal

记一次python大作业

bro这么久不更新,不练题,是去做什么去了,原来是去做beyond python大作业去了,罢了罢了,来看看成果吧

第一题,百度图片爬虫,这个喷不了,只要在框架上改改就可以(因为懒,一直没写多线程)

import requests
import re
import os
from bs4 import BeautifulSoup
from PIL import Image,ImageFont,ImageDraw
def get_url(page,key_word):
    original_url="https://image.baidu.com/search/acjson"
    body={'tn':'resultjson_com',
          'word':key_word,
          'ie':'utf-8',
          'fp':'result',
          'fr':'',
          'ala':'0',
          'applid':'',
          'pn':30*page,
          'rn':30,
          'nojc':0,
          'gsm':hex(page*30)[2:],
          'newReq':1,
         }
# 按照上次搜狗的规律,不加header头强打,发现触发百度的反爬机制,于是得在这里补上一个header头,cookie直接F12抄下来就可以了,ua头网上一大堆,再次强打仍被反爬,查询资料后加上host
    header={
        "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36",
        "Cookie":"BAIDUID_BFESS=E806634726C41BE45E14B222E8C48E10:FG=1;H_WISE_SIDS=62325_62865_62968_63034_63161;",
        "Host":"image.baidu.com",
        "Referer": "https://image.baidu.com/",
    }
    r=requests.get(url=original_url,params=body,headers=header)
    soup=BeautifulSoup(r.text,"html.parser").prettify()
#用美丽汤来美化一下爬取下来的内容,看一下图片标题和url对应的键是什么,直接正则搜图片的标题和对应的url
    title=r'"titleShow":\s*"((?:\\"|[^"])*)"'
    picUrl=r'"objurl":\s*"((?:\\"|[^"])*)"'
#这里我也修改过了,我原先写的正则表达式(例如:itle=r'"titleShow":\s*"([^"]+)"')不够健壮
#后面试运行的时候发现还是不够健壮,有的广告链居然也用objurl,这里为了不发生这种错误,我还是直接进行正则过滤,只匹配url末尾是jpg或png的内容,失败了,换回原来的正则表达式,看来这里的广告比我想象的要顽强
    pic_url=re.findall(picUrl,soup)
    title1=re.findall(title,soup)
    dict={k:v for k,v in zip(pic_url,title1)}
    return dict
def shuiyin(path,text,x1,y1,font_path=None,font_size=36,opacity=128,margin=10):
    img=Image.open(path).convert("RGBA")#按照手册上的,先转换为RGBA模式
    txt=Image.new('RGBA',img.size,(255,255,255,0))#然后创建与原图同尺寸的透明画布,再初始化
    draw=ImageDraw.Draw(txt)
    if font_path and os.path.exists(font_path):
        font=ImageFont.truetype(font_path,font_size)#这里给用户一个自定义字体的选择,要是不自定义的话就直接进入else的try语句执行,用默认字体库
    else:
        try:
            font=ImageFont.truetype(r"C:\Windows\Fonts\msyh.ttc",font_size)#这里用支持中文的微软雅黑,不然我的姓名班级写不上去
        except IOError:
                font=ImageFont.load_default()
    draw.text((x1,y1),text,font=font,fill=(255,0,0,opacity))#红色波长最长,就用红色好了,这里可以自己选择想要的水印的位置的x,y坐标
    watermarked=Image.alpha_composite(img,txt)#将水印和原图合成,变为带水印的图
    watermarked=watermarked.convert('RGB')#这里从rgba变为rgb,去掉透明模式
    watermarked.save(path)#直接覆盖原图,原图留着也没什么用
cnt=0
def single_download(url,title,dir_saving,watertxt,x1,y1,font_path=None):
    global cnt
    url=url.encode().decode("unicode_escape")
    print(url)
    title=title
    dir_saving=dir_saving
    header={
        "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36",
    }
    try:
        r=requests.get(url,headers=header)
        if r.status_code==200:#一般来说是只有通的时候可以下载,但是我在实操的时候,也会遇到一些响应码不是200但仍然成功下载的(内容为乱码)
            with open (f"{dir_saving}/{title}.png","wb") as f:
                cnt=cnt+1
                f.write(r.content)
            print(f"第{cnt + 1}张图片正在下载")
            shuiyin(f"{dir_saving}/{title}.png",watertxt,font_path,x1,y1)#这里直接添加水印
    except Exception:
        print("重试ing")
def down_load_image(keyword,page,dir_saving,watertxt,x1,y1,font_path=None):
    if not os.path.exists(dir_saving):
        os.makedirs(dir_saving)
    dict=get_url(page,keyword)
    for key,value in dict.items():
        single_download(key,value,dir_saving,watertxt,font_path,x1,y1)#这个就是最终的结合体函数了,将以上那么多内容都囊括进来
if __name__=='__main__':
    cnt=0
    keyword=input("keyword:")
    page=int(input("page:"))
    dir_saving=input("dir you want to save:")
    water_text = input("请输入水印文字: ")
    font_path = input("请输入字体文件路径(可选,支持中文,不想用直接回车就按默认的输出):")
    x1=int(input("水印的x坐标"))
    y1=int(input("水印的y坐标"))
    down_load_image(keyword,page,dir_saving,water_text,font_path,x1,y1)

第二题GUI库编写图形化界面实现猜字谜小游戏(这个是我最想喷的,密码的,那么多内容,硬写是吧,有点意思)

import tkinter as tk
from tkinter import messagebox, simpledialog
#这个是用于弹出提示框和输入框
import hashlib
import json
#数据储存使用json的格式更加方便(其实在百度那题我就想着不用美丽汤了,因为百度的返回格式为json,直接json读取就可以了,但是题目要求必须要用bs4)
import random
from collections import deque
#这里是因为排行榜只保留前5名使用deque(maxlen=5)可以自动在超出长度时丢弃最老元素,这里用库,否则自己写就会写爆炸(python大作业太多了)
#感谢baozongwi,感谢ziantt,感谢拉蒙特徐,看了他们的博客,查了很多资料,才有这份写完的作业,这题是真的难
riddles="riddles.json"
rank="leaderboard.json"
#定义两个json文件,这里也很容易理解这两个都是干什么的,一个是存谜语,另外一个存排行榜
class RiddleGame:
    #我直接定义一个类,用于初始化这个猜灯谜游戏界面
    def __init__(self,root):
        self.root=root#传入的root保存为实例属性self.root
        self.root.title("猜灯谜游戏")#设置标题,后续会用tkinter的title方法来进行修改
        #初始化游戏数据,这里我要把谜题通过gui界面输入,这里就全部初始化为None
        self.score=10
        self.current_riddle=None
        self.timer=None#题目里说的,这里以时间作为区分难度的关键
        self.time_left=0#定义玩这个猜字谜的游戏的剩余时间,就是类的初始化
        self.difficulty=1#定义难度的等级
        #这里拉一下谜题库和排行榜库,后续会定义load_riddles和load_leaderboard 
        self.riddles=self.load_riddles()
        self.leaderboard=self.load_leaderboard()
        #创建界面,构造gui组件和界面显示
        self.create_widgets()#后续也会一起定义的,这里先对功能有一个想法
        self.update_display()

    def create_widgets(self):
        #这个函数用于界面的构建,接下来创建一个frame容器,可以拿来水平布局两个标签,一个为时间,一个为分数
        self.info_frame=tk.Frame(self.root)
        self.info_frame.pack(pady=10)#这里我就直接用默认的pack(最简单也最好用的布局方式)10像素垂直间距
        self.score_label=tk.Label(self.info_frame,text="当前分数:10")#这里建立一个标签显示分数
        self.score_label.pack(side=tk.LEFT,padx=20)#左右留20像素间距
        self.time_label=tk.Label(self.info_frame,text="剩余时间:0")
        self.time_label.pack(side=tk.LEFT,padx=20)
        #跟上面一样,Label方法在主窗口创建一个用来显示灯谜文字的多行标签,宽度400像素(防止文字,就是题目太长,給爆了)
        self.riddle_label=tk.Label(self.root,text="",wraplength=400)
        self.riddle_label.pack(pady=20)
        #答案输入,用一个单行文本框输入答案,而且只要按回车就可以回答答案(check_answer方法后续也会定义)
        self.answer_entry=tk.Entry(self.root,width=30)
        self.answer_entry.pack(pady=10)
        self.answer_entry.bind("<Return>",self.check_answer)
        #按钮区域
        self.button_frame=tk.Frame(self.root)
        self.button_frame.pack(pady=10)
        self.start_btn=tk.Button(self.button_frame,text="开始游戏",command=self.start_game)
        self.start_btn.pack(side=tk.LEFT,padx=5)
        self.add_btn=tk.Button(self.button_frame,text="添加谜题",command=self.add_riddle)
        self.add_btn.pack(side=tk.LEFT,padx=5)
        self.leaderboard_btn=tk.Button(self.button_frame,text="排行榜",command=self.show_leaderboard)
        self.leaderboard_btn.pack(side=tk.LEFT,padx=5)
        self.quit_btn=tk.Button(self.button_frame,text="退出游戏",command=self.quit_game)
        self.quit_btn.pack(side=tk.LEFT,padx=5)
        #建立四个按钮,用于四种功能
    #接下来定义一个载入函数,用于加载谜语文件
    def load_riddles(self):
        try:
            with open(riddles,'r') as f:
                return json.load(f)
        except FileNotFoundError:
            return []
    #可以写入谜语
    def save_riddles(self):
        with open(riddles,'w') as f:
            json.dump(self.riddles,f,ensure_ascii=False, indent=2)
#为了保持中文字符,此处要ensure_ascii=False,还有就是文档中讲的设置indent,据说是为了增加可读性   
    def load_leaderboard(self):
        try:
            with open(rank,'r') as f:
                return deque(sorted(json.load(f),key=lambda x: x['score'], reverse=True),maxlen=5)
        except FileNotFoundError:
            return deque(maxlen=5)
    
    def save_leaderboard(self):
        with open(rank,'w') as f:
            json.dump(list(self.leaderboard),f,indent=2)
    #定一个启动游戏的的函数,最低难度为1,最高难度为3
    def start_game(self):
        self.difficulty=simpledialog.askinteger(
            "选择难度", 
            "请选择难度(1-简单 2-中级 3-困难)",
            minvalue=1,maxvalue=3
        )
        if self.difficulty:
            self.prepare_new_question()
    def prepare_new_question(self):
        available=[r for r in self.riddles if r['difficulty']==self.difficulty]
        if not available:
            messagebox.showerror("错误","该难度下没有可用题目")
            return
        self.current_riddle=random.choice(available)
        self.riddle_label.config(text=self.current_riddle['riddle'])
        #在这里设置倒计时
        self.time_left=30-(self.difficulty-1)*10
        self.update_timer()
    def update_timer(self):
        self.time_label.config(text=f"剩余时间:{self.time_left}")
        if self.time_left>0:
            self.timer=self.root.after(1000,self.update_timer)
            self.time_left-=1
        else:
            self.handle_timeout()
    def handle_timeout(self):
        messagebox.showwarning("时间到", "答题时间已用完!")
        self.score-=self.difficulty
        self.update_display()
        self.check_game_over()
        if self.score>=0:
            self.prepare_new_question()
    def check_answer(self,event=None):#哈希比较,我这里都是用sha256,目前安全系数很高
        if self.time_left<=0 or not self.current_riddle:
            return
        answer=self.answer_entry.get().strip().lower()
        self.answer_entry.delete(0,tk.END)
        if self.timer:
            self.root.after_cancel(self.timer)
            self.timer=None
        hashed=hashlib.sha256(answer.encode()).hexdigest()
        if hashed==self.current_riddle['answer']:
            self.score+=self.difficulty
            messagebox.showinfo("正确", "回答正确!")
        else:
            self.score-=self.difficulty
            messagebox.showerror("错误", f"回答错误!正确答案是:{self.current_riddle['answer_plain']}")
        self.update_display()
        self.check_game_over()
        if self.score>=0:
            self.prepare_new_question()
    def add_riddle(self):
        add_window=tk.Toplevel(self.root)
        add_window.title("添加新谜题")
        #在这里谜面输入
        tk.Label(add_window, text="谜面:").grid(row=0,column=0,padx=5,pady=5)
        riddle_entry = tk.Entry(add_window,width=30)
        riddle_entry.grid(row=0,column=1,padx=5,pady=5)
        #这里是答案输入
        tk.Label(add_window, text="答案:").grid(row=1,column=0,padx=5,pady=5)
        answer_entry=tk.Entry(add_window,width=30)
        answer_entry.grid(row=1,column=1,padx=5,pady=5)
        #选择难度
        tk.Label(add_window,text="难度:").grid(row=2,column=0,padx=5,pady=5)
        difficulty=tk.IntVar(value=1)
        tk.Radiobutton(add_window,text="简单",variable=difficulty,value=1).grid(row=2,column=1,sticky="w")
        tk.Radiobutton(add_window,text="中级",variable=difficulty,value=2).grid(row=3,column=1,sticky="w")
        tk.Radiobutton(add_window,text="困难",variable=difficulty,value=3).grid(row=4,column=1,sticky="w")
        def save():
            answer_plain=answer_entry.get().strip().lower()
            if not riddle_entry.get() or not answer_plain:
                messagebox.showerror("错误","谜面和答案不能为空")
                return
            hashed=hashlib.sha256(answer_plain.encode()).hexdigest()
            new_riddle={
                'riddle':riddle_entry.get(),
                'answer':hashed,
                'difficulty':difficulty.get(),
                'answer_plain':answer_plain
            }
            self.riddles.append(new_riddle)
            self.save_riddles()
            add_window.destroy()
            messagebox.showinfo("成功","谜题添加成功!")
        save_btn=tk.Button(add_window,text="保存",command=save)
        save_btn.grid(row=5,columnspan=2,pady=10)
    
    def show_leaderboard(self):
        lb_text="排行榜\n"
        if not self.leaderboard:
            lb_text+="暂无记录"
        else:
            for i,entry in enumerate(sorted(self.leaderboard,key=lambda x:x['score'],reverse=True)):
                lb_text+=f"第{i+1}名: {entry['name']}-{entry['score']}\n"
        messagebox.showinfo("排行榜",lb_text)
    
    def check_game_over(self):
        if self.score<0:
            messagebox.showinfo("游戏结束","挑战失败!")
            if self._check_leaderboard_qualify():
                name=simpledialog.askstring("记录","恭喜进入前五!请输入姓名:")
                if name:
                    self.leaderboard.append({'name':name,'score':self.score})
                    self.save_leaderboard()
            self.root.destroy()
    
    def _check_leaderboard_qualify(self):
        if len(self.leaderboard)<5:
            return True
        return self.score>min(entry['score'] for entry in self.leaderboard)
    #一个方法一个方法慢慢定义下去吧,遇到不会的就问问学长他们,好累,终于要写完了
    def quit_game(self):
        if self.score>0 and self._check_leaderboard_qualify():
            name=simpledialog.askstring("记录","恭喜进入前五!请输入姓名:")
            if name:
                self.leaderboard.append({'name':name,'score':self.score})
                self.save_leaderboard()
        self.root.destroy()
    def update_display(self):
        self.score_label.config(text=f"当前分数:{self.score}")
        self.time_label.config(text=f"剩余时间:{self.time_left}")
if __name__=="__main__":
    root=tk.Tk()
    game=RiddleGame(root)
    root.mainloop()

恶心至极啊,根本没写过这种又臭又长的东西,简直是ex死我了,还没什么作用,这个年代了谁还用tkinter这种基础GUI库(你别杠说你为什么不去用其他库,一共就5天时间写完这么多大作业,我还要去上课,怎么可能学更复杂的)

第三题,西游记画词云图和人物关系图

闲着没事干是不是,画这种玩意,jieba库是给你这么玩的,能不能干点更有意义的事情
还好我借助了东南大学同学开源的人物名称字典,剩下的自己写一个白名单进行过滤即可
感谢东南大学的大力支持
https://github.com/GaoChDemo/xyjnpl/blob/master/source/nr_deal.txt
附上他们的链接
恶心啊

每一题恶心题被写,都有一个学生遭到迫害–拉蒙特徐

import jieba
import wordcloud
import networkx as nx
import matplotlib.pyplot as plt
from collections import defaultdict

def takeSecond(elem):
    return elem[1]

def wordyun(dict):#这里需要用词频生成
    w=wordcloud.WordCloud(
        font_path="msyh.ttc",
        width=1000,
        height=500,
        background_color="white",
    )
    #我这里先设置一下词云的基本参数,调用的和第一题一样都是支持中文的微软雅黑
    #然后就是基本的参数,这些都看个人,爱使用哪个就可以用哪个,反正可以查一下库
    w.generate_from_frequencies(dict)#原先我直接用generate,但是不行,后面查了,用词频作为输入对象,得用另外一种(文中这种)的方法
    w.to_file("词云.jpg")
#看错了题目的要求,是要对人物进行分词,我上github找了现成的词典(xiyouji_dict),然后纳入jieba库里面,我这里再加一句载入jieba库的语句
#在后面我还会进行更改,只对人物名的分词进行统计,不会对例如金箍棒这样子的词进行统计
jieba.load_userdict("xiyouji_dict.txt")
#这里定义一个白名单,只有在字典中的人物名会被统计,其余都会被过滤
white_words=set()
with open("xiyouji_dict.txt", "r", encoding="utf-8") as f:
    for line in f:
        parts = line.strip().split()
        if parts:  #这里要确保非空行
            white_words.add(parts[0])
def main():
    path="西游记.txt"
    with open(path,"r",encoding="gb18030") as f:
        text=f.read()
    words=jieba.lcut(text)
    count={}
    for word in words:
        if len(word)==1:
            continue#单个字的很明显不是什么人名,直接去掉即可
        #上网查一个西游记里面的人物及其别名大全,直接写下来,合并成同一个词
        elif word in ["大圣","老孙","行者","孙大圣","孙行者","猴王","悟空","齐天大圣","猴子","斗战胜佛","弼马温","美猴王"]:
            uniword="孙悟空"
        elif word in ["师父","三藏","圣僧","金禅子","玄奘","唐三藏","御弟"]:
            uniword="唐僧"
        elif word in ["呆子","八戒","老猪","净坛使者"]:
            uniword="猪八戒"
        elif word in ["妖精","妖魔","妖道"]:
            uniword="妖怪"#这里你就想,西游记里妖怪这个词出现的次数肯定比黄风大王,白骨精那些都要多,统计妖怪即可
        elif word in["沙和尚","悟净","卷帘大将"]:
            uniword="沙僧"
        elif word=="佛祖":
            uniword="如来"
        elif word in ["三太子","八部天龙马"]:
            uniword="白马"
        elif word=="唐王":
            uniword="唐三藏"
        elif word=="观音":
            uniword="观音菩萨"
        elif word=="天王":
            uniword="李天王"
        else:
            uniword=word  #一些主要人物考虑一下不同的称呼,其余的就算了,因为百眼魔君孙悟空叫他妖道,镇元子孙悟空也是这么叫的,这种根本统计不完,这里非特殊词保持原样
        #接下来通过白名单来过滤那些非人名的词
        white_words.update(["唐僧", "孙悟空", "猪八戒", "沙僧", "如来", "白马", "妖怪","唐三藏","观音菩萨","李天王"])#更新一下白名单
        if uniword in white_words:
            count[uniword]=count.get(uniword,0)+1
    items=list(count.items())
    items.sort(key=takeSecond,reverse=True)
    wordyun(count)   
 
    for i in range(24):
        item=items[i]
        keyWord=item[0]
        jishu=item[1]
        print("{0:<10}{1:>5}".format(keyWord,jishu))

    top24=[item[0] for item in items[:24]]#准备一下前24个人物,后续画关系网络的重点
    perduan=[par for par in text.split("\n")]#按段落来区分,准备看人物关系了
    '''
    接下来按道理是要进行像上面那样,分类同义词以及进行分词,然后再判断是不是在top24里面,但是照抄没什么意思,我看直接画关系即可,就是不进行同义词这部分
    '''
    for para in perduan:
        char=set()
        for word in jieba.lcut(para):
            if word in top24:
                char.add(word)
        #把每个人物出现的有限人物都存储下来
        #接下来要确保每个人物在每一段中出现的有效次数只有一次,方便后续计算(不然的话,那很完蛋了,孙悟空在段落里出现一次,猪八戒出现三次,那究竟是要记一次还是三次,为了保险起见,还是只记一次)
    ls=list(char)
    newcount=defaultdict(int)
    for i in range(len(ls)):
        for j in range(i+1,len(ls)):
            #这里要利用元组的特性,例如("孙悟空", "唐僧")和("唐僧", "孙悟空")会被排序后统一为同一个元组
            double=tuple(sorted([char[i],char[j]]))
            #接下来用字典记权重
            newcount[double]+=1
    #创建一个新的无向图,用networkx的Graph方法(注意:区分开头大小写,我就因此中招)
    draw=nx.Graph()
    #将前24位人物都初始化为网络节点
    draw.add_nodes_from(top24)
    for double,value in newcount.items():
        if value>0:
            #很容易理解的,权重为0那就是毫无关系,那就不能加边
            draw.add_edge(double[0],double[1],weight=value)
            #权重weight就是字典的值value
    plt.figure(figsize=(15,15))
    pos=nx.spring_layout(draw, k=0.8)
    nx.draw(draw,pos,with_labels=True, 
           node_size=[count[name]*50 for name in draw.nodes()],
           width=[d['weight']*0.3 for (u,v,d) in draw.edges(data=True)],
           font_family='SimHei')
    #用默认参数即可
    plt.savefig('关系网络.png', dpi=300)
    plt.close()

if __name__=="__main__":
    main()

第四题,GUI界面实现三种加解密

太唐了啊,这种寄吧东西,谁爱写屎谁就去写

#网安2402-24-曹楚涵
import tkinter as tk
from tkinter import ttk, messagebox
#(这里加解密函数我之前选B的时候都写了,这里我直接复制粘贴,就不多说了)
# 凯撒加密函数
def kaisa(text: str, shift: int) -> str:
    def process_char(c):
        if not c.isalpha():
            return c
        base = ord('A') if c.isupper() else ord('a')
        return chr((ord(c) - base + shift) % 26 + base)
    return ''.join(process_char(c) for c in text)
morse_code = {
        'A':'.-','B':'-...','C':'-.-.','D':'-..','E':'.',
        'F':'..-.','G':'--.','H':'....','I':'..','J':'.---',
        'K':'-.-','L':'.-..','M':'--','N':'-.','O':'---',
        'P':'.--.','Q':'--.-','R':'.-.','S':'...','T':'-',
        'U':'..-','V':'...-','W':'.--','X':'-..-','Y':'-.--',
        'Z':'--..','1':'.----','2':'..---','3':'...--',
        '4':'....-','5':'.....','6':'-....','7':'--...',
        '8':'---..','9':'----.','0':'-----',' ':'/'
    }
# 摩斯加密函数
def mose1(text: str) -> str:
    morse_code = {
        'A':'.-','B':'-...','C':'-.-.','D':'-..','E':'.',
        'F':'..-.','G':'--.','H':'....','I':'..','J':'.---',
        'K':'-.-','L':'.-..','M':'--','N':'-.','O':'---',
        'P':'.--.','Q':'--.-','R':'.-.','S':'...','T':'-',
        'U':'..-','V':'...-','W':'.--','X':'-..-','Y':'-.--',
        'Z':'--..','1':'.----','2':'..---','3':'...--',
        '4':'....-','5':'.....','6':'-....','7':'--...',
        '8':'---..','9':'----.','0':'-----',' ':'/'
    }
    return ' '.join(morse_code.get(c.upper(), c) for c in text)
baconian = {
        'A':'AAAAA','B':'AAAAB','C':'AAABA','D':'AAABB',
        'E':'AABAA','F':'AABAB','G':'AABBA','H':'AABBB',
        'I':'ABAAA','J':'ABAAB','K':'ABABA','L':'ABABB',
        'M':'ABBAA','N':'ABBAB','O':'ABBBA','P':'ABBBB',
        'Q':'BAAAA','R':'BAAAB','S':'BAABA','T':'BAABB',
        'U':'BABAA','V':'BABAB','W':'BABBA','X':'BABBB',
        'Y':'BBAAA','Z':'BBAAB',' ':'BBBBB'
    }
# 培根加密函数
def peigen(text: str) -> str:
    baconian = {
        'A':'AAAAA','B':'AAAAB','C':'AAABA','D':'AAABB',
        'E':'AABAA','F':'AABAB','G':'AABBA','H':'AABBB',
        'I':'ABAAA','J':'ABAAB','K':'ABABA','L':'ABABB',
        'M':'ABBAA','N':'ABBAB','O':'ABBBA','P':'ABBBB',
        'Q':'BAAAA','R':'BAAAB','S':'BAABA','T':'BAABB',
        'U':'BABAA','V':'BABAB','W':'BABBA','X':'BABBB',
        'Y':'BBAAA','Z':'BBAAB',' ':'BBBBB'
    }
    return ''.join(baconian.get(c.upper(), c) for c in text)
# 凯撒解密函数
def jiemikaisa(text:str,shift:int)->str:
    def jiemi(c):
        if not c.isalpha():
            return c
        if c.isupper():
            yuan=ord('A')
        else:
            yuan=ord('a')
        return chr((ord(c)-yuan-shift)%26+yuan)
    return ''.join(jiemi(c) for c in text)
# 摩斯解密函数
def jiemimose(text:str)->str:
    mose={
    '.-':'A','-...':'B','-.-.':'C','-..':'D','.':'E',
    '..-.':'F','--.':'G','....':'H','..':'I','.---':'J',
    '-.-':'K','.-..':'L','--':'M','-.':'N','---':'O',
    '.--.':'P','--.-':'Q','.-.':'R','...':'S','-':'T',
    '..-':'U','...-':'V','.--':'W','-..-':'X','-.--':'Y',
    '--..':'Z',
    '.----':'1','..---':'2','...--':'3','....-':'4','.....':'5',
    '-....':'6','--...':'7','---..':'8','----.':'9','-----':'0',
    '/':' '
}
    fenjie=text.split(' ')
    result=[]
    for i in fenjie:
        result.append(mose[i])
    return ''.join(result)
# 培根解密函数
def jiemipeigen(text:str)->str:
    peigen={
    'AAAAA':'A','AAAAB':'B','AAABA':'C','AAABB':'D',
    'AABAA':'E','AABAB':'F','AABBA':'G','AABBB':'H',
    'ABAAA':'I','ABAAB':'J','ABABA':'K','ABABB':'L',
    'ABBAA':'M','ABBAB':'N','ABBBA':'O','ABBBB':'P',
    'BAAAA':'Q','BAAAB':'R','BAABA':'S','BAABB':'T',
    'BABAA':'U','BABAB':'V','BABBA':'W','BABBB':'X',
    'BBAAA':'Y','BBAAB':'Z','BBBBB':' ' 
}
    result=[]
    for i in range(0,len(text),5):
        chunk=text[i:i+5]
        result.append(peigen[chunk])
    return ''.join(result)
class CryptoApp(tk.Tk):
    #跟上一份一样,定一个类来做gui组件,需要什么部分上网查一下
    def __init__(self):
        super().__init__()
        self.title("ATFlags加解密工具v1.1")
        self.geometry("680x500")
        # 创建界面组件
        self.create_widgets()
        self.check_environment()
    def create_widgets(self):
        """创建所有界面组件"""
        # 输入区域
        input_frame = ttk.LabelFrame(self, text="输入区", padding=10)
        input_frame.grid(row=0, column=0, padx=10, pady=5, sticky="nsew")
        self.input_text = tk.Text(input_frame, height=8, width=60, font=('Consolas', 10))
        self.input_text.pack(fill=tk.BOTH, expand=True)
        # 控制面板
        control_frame = ttk.Frame(self)
        control_frame.grid(row=1, column=0, padx=10, pady=5, sticky="ew")
        # 模式选择
        self.mode_var = tk.StringVar(value="凯撒加密")
        mode_menu = ttk.OptionMenu(
            control_frame, self.mode_var,
            "凯撒加密",
            "凯撒加密", "凯撒解密",
            "摩斯加密", "摩斯解密",
            "培根加密", "培根解密",
            command=self.update_ui
        )
        mode_menu.pack(side=tk.LEFT, padx=5)
        # 位移量输入
        self.shift_frame = ttk.Frame(control_frame)
        ttk.Label(self.shift_frame, text="位移量:").pack(side=tk.LEFT)
        self.shift_spin = ttk.Spinbox(
            self.shift_frame, 
            from_=0, 
            to=25, 
            width=5,
            validate="key",
            validatecommand=(self.register(self.validate_shift), '%P')
        )
        self.shift_spin.set(3)
        self.shift_spin.pack(side=tk.LEFT)
        self.shift_frame.pack(side=tk.LEFT, padx=10)
        self.shift_frame.pack_forget()
        # 执行按钮
        ttk.Button(
            control_frame, 
            text="执 行", 
            command=self.process, 
            style="Accent.TButton"
        ).pack(side=tk.RIGHT)
        # 结果输出
        output_frame = ttk.LabelFrame(self, text="输出区", padding=10)
        output_frame.grid(row=2, column=0, padx=10, pady=5, sticky="nsew")
        self.output_text = tk.Text(
            output_frame, 
            height=8, 
            width=60, 
            state=tk.DISABLED,
            font=('Consolas', 10)
        )
        self.output_text.pack(fill=tk.BOTH, expand=True)
        # 配置行列权重
        self.grid_rowconfigure(0, weight=1)
        self.grid_rowconfigure(2, weight=1)
        self.grid_columnconfigure(0, weight=1)
    def validate_shift(self, value):
        """验证位移量输入"""
        if value == "":
            return True
        try:
            return 0 <= int(value) <= 25
        except ValueError:
            return False
    def update_ui(self, *args):
        """根据选择的模式更新界面"""
        mode = self.mode_var.get()
        if mode in ["凯撒加密", "凯撒解密"]:
            self.shift_frame.pack(side=tk.LEFT, padx=10)
        else:
            self.shift_frame.pack_forget()
    def process(self):
        """执行加解密操作"""
        try:
            # 获取输入内容
            input_content = self.input_text.get("1.0", tk.END).strip()
            if not input_content:
                raise ValueError("输入内容不能为空")

            # 执行对应操作
            mode = self.mode_var.get()
            if mode in ["凯撒加密", "凯撒解密"]:
                shift = int(self.shift_spin.get())
                result = kaisa(input_content, shift) if mode == "凯撒加密" else jiemikaisa(input_content, shift)
            elif mode == "摩斯加密":
                result = mose1(input_content)
            elif mode == "摩斯解密":
                result = jiemimose(input_content)
            elif mode == "培根加密":
                result = peigen(input_content)
            elif mode == "培根解密":
                result = jiemipeigen(input_content)

            # 显示结果
            self.output_text.config(state=tk.NORMAL)
            self.output_text.delete("1.0", tk.END)
            self.output_text.insert(tk.END, result)
            self.output_text.config(state=tk.DISABLED)

        except Exception as e:
            messagebox.showerror("错误", f"操作失败: {str(e)}")
            self.output_text.config(state=tk.NORMAL)
            self.output_text.delete("1.0", tk.END)
            self.output_text.insert(tk.END, "出现错误,请检查输入!")
            self.output_text.config(state=tk.DISABLED)
    def check_environment(self):
        """检查运行环境"""
        try:
            # 测试Tkinter组件是否正常工作
            test_button = ttk.Button(self, text="环境测试")
            test_button.destroy()
        except Exception as e:
            messagebox.showerror("环境错误", 
                f"GUI环境初始化失败:{str(e)}\n"
                "请确认:\n"
                "1. 正在使用Python标准环境\n"
                "2. 安装了Tkinter支持\n"
                "3. 显示器配置正确(服务器环境需要虚拟显示)"
            )
            self.destroy()

if __name__=="__main__":
    app=CryptoApp()
    app.mainloop()

我写个蛋的GUI,我早密码

过时的加密和技术,FJUT,你稳了

第五题,LSB隐写,这个我不会,没话说

#网安2402-24-曹楚涵
#LSB隐写在misc中很常见,但是一般都是当作最简单的签到题,我们也一般是用工具一把梭,但是这里得自己写一个脚本
from PIL import Image
#先讲一下LSB隐写术吧
'''
图片中的图像像素一般是由RGB三原色(红绿蓝)组成,每一种颜色占用8位,取值范围为0x00~0xFF,即有256种颜色,一共包含了256的3次方的颜色,即16777216种颜色。而人类的眼睛可以区分约1000万种不同的颜色,这就意味着人类的眼睛无法区分余下的颜色大约有6777216种。
LSB隐写就是修改RGB颜色分量的最低二进制位也就是最低有效位(LSB),而人类的眼睛不会注意到这前后的变化,每个像数可以携带3比特的信息。
#做这个方向的题目,经常用的就是stegsolve,后面我也会用这个来看一下我生成的隐写图是不是正确的
'''
def message_to_bits(message):
    #这里是将字符串消息转换成比特流,然后用一个列表来储存0/1比特
    bits=[]
    for char in message:
        binval=format(ord(char),'08b')#按照LSB的原理,每个字符都要编成8位二进制字符串,不会产生过多或过少的情况
        bits.extend([int(bit) for bit in binval])
    bits.extend([0]*8)#这里是要添加一个结束的标志
    return bits
def bits_to_message(bits):
    #就是第一个函数反过来,比特流转字节,遇到八个0的时候自动停止
    chars=[]
    for i in range(0,len(bits),8):
        byte=bits[i:i+8]
        if len(byte)<8:
            break
        value=int(''.join(str(bit) for bit in byte),2)
        if value==0:
            break
        chars.append(chr(value))
    return ''.join(chars)

def encode_image(input_image_path,output_image_path,message):
    #我这个函数就是用RGB模式打开图片,然后获取所有的像素,后面用列表来保存,然后检查消息能不能写入图片,最后修改最低位,一个一个像素和通道的写入比特流,然后保存
    img=Image.open(input_image_path)
    if img.mode!='RGB':
        img=img.convert('RGB')
    pixels=list(img.getdata())
    bits=message_to_bits(message)
    if len(bits)>len(pixels)*3:
        raise ValueError("Message too large to encode in image.")
    new_pixels=[]
    bit_idx=0
    for pixel in pixels:
        r,g,b=pixel
        if bit_idx<len(bits):
            r=(r&~1)|bits[bit_idx]
            bit_idx+=1
        if bit_idx<len(bits):
            g=(g&~1)|bits[bit_idx]
            bit_idx+=1
        if bit_idx<len(bits):
            b=(b&~1)|bits[bit_idx]
            bit_idx+=1
        new_pixels.append((r,g,b))
    img.putdata(new_pixels)
    img.save(output_image_path)
    print(f"Encoded message and saved to{output_image_path}")

def decode_image(input_image_path):
    #这个就是一个很简单的解码脚本,提取每个通道的最低位,拼成比特流,然后还原成字符串
    img=Image.open(input_image_path)
    if img.mode!='RGB':
        img=img.convert('RGB')
    pixels=list(img.getdata())
    bits=[]
    for pixel in pixels:
        for channel in pixel[:3]:
            bits.append(channel&1)
    return bits_to_message(bits)
if __name__=="__main__":
    #主函数就不多说了
    original_img='关系网络.png'#西游记的关系图是png而且也在这个目录下,我就直接抓过来用了
    stego_img='LSB隐写.png'
    secret_message='flag{KFC crazy Thursday vivo50}'
    encode_image(original_img,stego_img,secret_message)
    extracted_message=decode_image(stego_img)
    print("提取的隐藏信息:",extracted_message)

<参考博客https://blog.csdn.net/qq_38154820/article/details/122694645>

总结:最近屎吃多了,不太会说话了