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>