导读:
demo内容来源网课贪心科技AI学社的网课《人工智能Python编程特训营》
本篇博客的主要内容是简单的加密解密,主要是利用了编码。
先附上了我自己写的中英文加密的demo,将加密规则保存到了本地。
然后附上了课堂上的几个小案例。
还有随手写的一个爬取常见中文的小爬虫。
作业
自己写一个加密程序,能够加密的内容是英文和汉字。同时加密并且解密
就是说,一段话中既有中文又有英文,标点符号不用处理。
加密规则,获取ascii码数字,中间用|分割
我没有严格按照这个作业来,因为作业是源自课堂的demo。我最后实现的是一个中英文包括常用英文字符的加密解密,并把密码本存到本地,加密规则见后文。
其实这个作业意义不是很大,因为正常加密不会这么用,之后会给出现在的比较常用的加密函数。
实现效果如下:
其实代码很简单,主要是了解了一下关于ASCII和Unicode编码规则。
有两个重要的函数ord()
和chr()
可以分别将字符转化为Unicode编码和将Unicode编码转化为字符。
先定义我们加密的信息范围,一个是ASCII从33-126的可显示字符,包含了英文、英文标点、数字,但是这里不包含中文的标点符号。另一个是4E00-9FA5是Unicode编码中常用汉字的范围,当然还有其他不常用的汉字,但是这个是个demo就没必要去做了。
# ASCII有符号显示的从33 - 126
ASCII_START = 33
ASCII_END = 126
# 常用汉字的Unicode从4E00 - 9FA5
HAN_START = int('0x4E00', 16) # 19968
HAN_END = int('0x9FA5', 16) # 40869
ord()
函数在Python3之后就支持Unicode(万国码)而不仅仅支持ASCII,虽然0-127是一样的,但是127-255的扩展ASCII码和Unicode是不同的。
Unicode(统一码、万国码、单一码)是计算机科学领域里的一项业界标准,包括字符集、编码方案等。Unicode 是为了解决传统的字符编码方案的局限而产生的,它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。
我这里加密的想法是先将所有需要转换的字符存储到一个密码本中,然后用下标去当做密码,课程上老师的做法也是这么做的,但是他用到了|作为分隔符,但是我们这个demo中|是可以进行加密的,所以不合适。
DEMO的加密规则
因此我就决定用两个密码本,读取一个句子,在A密码本中找到下标,然后下标在B密码本的文字就是原来文字的加密状态。解密同理,将加密后的文字在B密码本中找到下标,下标对应的文字在A密码本中的文字就是原来文字的加密状态。
因此我们用init_codebook_A()
生成A密码本,用init_codebook_B()
函数生成B密码本。
import random
# 生成初始状态的密码本A
def init_codebook_A():
codebook_A = []
# 将ASCII加入密码本
for i in range(ASCII_START, ASCII_END + 1):
codebook_A += chr(i)
# 将汉字加入密码本
for i in range(HAN_START, HAN_END + 1):
codebook_A += chr(i)
print("A密码本长度:" + str(len(codebook_A)))
print(codebook_A)
save_codebook("codebook_A", codebook_A) # 保存密码本
return codebook_A
# 生成随即打乱后的密码本B
def init_codebook_B(codebook):
random.shuffle(codebook) # 随机打乱顺序
print(codebook)
save_codebook("codebook_B", codebook) # 保存密码本
return codebook
在生成密码本的时候我们必须将密码本也保存下来,这里使用了空格作为保存进文本的状态,因为空格没有在我们的加密范围内。
# 保存密码本
def save_codebook(filename, codebook):
with codecs.open(filename + '.txt', 'w', 'utf-8') as f:
for code in codebook:
code = code + ' '
f.write(code, ) # 遍历循环,写入文件
print("保存密码本" + filename + "成功")
# 加载密码本
def load_codebook():
with codecs.open('codebook_A.txt', 'r', 'utf-8') as f_A: # 读取A密码本
codebook_A = f_A.read().split(" ")
codebook_A.remove("")
print("A密码本长度:" + str(len(codebook_A)))
with codecs.open('codebook_B.txt', 'r', 'utf-8') as f_B: # 读取B密码本
codebook_B = f_B.read().split(" ")
codebook_B.remove("")
print("B密码本长度:" + str(len(codebook_A)))
print("加载密码本成功")
return codebook_A, codebook_B
加密和解密的程序写法类似,本质上是一个程序,只是加密和解密的过程传入的值是不一样的。
# 加密/解密,传入文本信息和两个密码本
# 第一个密码本获取索引,第二个密码本根据第一个密码本的索引获取字符
def code_process(message, codebook_first, codebook_second):
coded_message = ""
for char in message:
if char in codebook_first:
index = codebook_first.index(char)
# print(index)
coded_char = codebook_second[index]
# print(coded_char)
coded_message += coded_char
else:
coded_message += char
return coded_message
最后我们直接调用上面封装好的函数就可以了。、
首先是初始化A和B两个密码本,这时候两个密码本已经写入本地了。
接着是加载密码本。
然后就可以输入文字,同时给出了解密后的语句和解密后的语句。
import os
# 先判断文件是否存在,若不存在就创建密码本,若存在就用以前的密码本就好了
if os.path.exists("codebook_A.txt") and os.path.exists("codebook_B.txt"):
pass
else:
codebook_A = init_codebook_A()
codebook_B = init_codebook_B(codebook_A)
new_codebook_A, new_codebook_B = load_codebook()
while (True): # 多输入
message = input("请输入文本信息:")
coded_message = code_process(message, new_codebook_A, new_codebook_B)
print("加密: " + coded_message)
print("解密: " + code_process(coded_message, new_codebook_B, new_codebook_A))
其实这是一个挺无聊的DEMO。大家可以随便看看。搞定了作业之后,再来回顾下课堂内容,然后再讨论一下现在的加密技术。
回顾课堂
利用对称加密的方法对英文进行加密,大致的加密规则就是利用ASCII的移位,大小写英文字母循环移动13位进行加密。直接贴一下代码,具体的实现很好懂,就不解释了,也没有封装成函数。
# 输入一段话
message = input("please input your message >>>>")
# 定义一个结果,这个结果加密后的结果
result = ""
for char in message:
value = ord(char)
# 大写ascii 65 - 90
# 小写ascii 97 - 122
if 64 < value < 78 or 96 < value < 110:
result_char = chr(value + 13)
result += result_char
elif 77 < value < 91 or 109 < value < 123:
result_char = chr(value - 13)
result += result_char
else:
result += char
print("加密后的结果:" + result)
# 解密过程
after_result = ""
for r in result:
value = ord(r)
# 大写ascii 65 - 90
# 小写ascii 97 - 122
if 64 < value < 78 or 96 < value < 110:
result_char = chr(value + 13)
after_result += result_char
elif 77 < value < 91 or 109 < value < 123:
result_char = chr(value - 13)
after_result += result_char
else:
after_result += r
print("解密后的结果:" + after_result)
另一个demo是利用爬虫爬取3500个常用字进行加密。爬取网站上3500个汉字,利用正则表达式获取所有的汉字并存到数组。具体的代码解释都在注释里面,这里只做记录。
import requests
import re
# 抓取网页源代码
html_result = requests.get("https://www.zdic.net/zd/zb/cc1/")
# 书写正则表达式来获取网页源代码中的所有汉字
reg = "href='//www.greatytc.com/hans/(.*)' "
hans_list = re.findall(reg, html_result.text)
print(hans_list)
# 加密的字符串
input_message = "我来贪心学院学习"
# 我要存储加密完成的字符串
result = ""
# 加密规则
# 到hans_list 这个变量中寻找我输入的汉字,并将其位置取出来,作为加密后的编号
# 并且我们用|把这些组的数字分开
# 例子: 我爱中国 加密后 变成 29|30|12|24|
for hans in input_message:
for index, element in enumerate(hans_list):
if hans == element:
# print(index)
# print(element)
result += str(index) + "|"
print("加密后的数据>>>"+result)
# 这里使用|将字符串进行分割,结果是一个数组
index_list = result.split("|")
print(index_list)
# 移除数据中的空数据
index_list.remove("")
print(index_list)
#声明一个变量来存放解密后的结果
response_result = ""
# 遍历我的数组
for index in index_list:
# 数组中的字符串转上int值
int_index = int(index)
response_result += hans_list[int_index]
print("解密后的数据>>>>"+response_result)
中文小爬虫
后来呢,我又觉得3500个词太少了,就写了一个小爬虫想爬取多一点的汉字(事实证明直接用ascii就可以了,这种做法特别愚蠢,但是可以扩展,比如之后可以做成汉字字典就需要爬虫的方法)。同样,代码部分就不解释了,应该都看得懂,这里也只是用来保存。
import requests
from bs4 import BeautifulSoup
import codecs
import time
import re
# 该网站http://www.cnpoem.net/hz/一共收录了16159个汉字
# 获取共41页的url
def getURL():
# 抓取网页源代码
url_head = "http://www.cnpoem.net/hz/index.asp?page="
url_end = "&cate=&key="
# 定义数据存储所有URL
url_list = []
for i in range(41):
url = url_head + str(i + 1) + url_end
print(url)
url_list.append(url)
# print(len(url_list))
# print(url_list)
return url_list
# 传入URL,解析获取所有网页中所有汉字,并存入数组
def HtmlParser(url):
html_result = requests.get(url)
html_result.encoding = 'gbk'
soup = BeautifulSoup(html_result.text, "html.parser")
# print(soup.prettify())
# 找到所有<a>标签
for a in soup.find_all('a'):
# 筛选所有<a>标签,当href中包含了detail时才是我们所需要的
href = a.get("href")
if (href.find("detail") >= 0):
# print(href)
word_list.append(a.text) # 符合条件,补充在数组中
# print(a.text)
print(len(word_list))
# 保存数组到字典,采用追加的形式,如果不需要追加请确保本地无该文件
def saveDictionary(word_list):
with codecs.open('ChineseDictionary.txt', 'a', 'utf-8') as f:
for word in word_list:
word = word + ' '
f.write(word, )
# 从本地中加载字典存入本地数组
def loadDictionary():
with codecs.open('ChineseDictionary.txt', 'r', 'utf-8') as f:
f_read = f.read()
word_list = f_read.split(" ")
# print(word_list)
word_list.remove("")
print(f"字典内的个数:{len(word_list)}")
return word_list
# 获取特定范围的URL,从1到41
def getSpecifyURL(start=1, end=41):
for url in url_list[start - 1:end]:
print(url)
HtmlParser(url)
word_list = [] # 存储字集
url_list = getURL()
getSpecifyURL(1,3)
saveDictionary(word_list)
dict = loadDictionary()
print(dict)
print(len(dict))
以上就是一小点小的回顾,其实没什么用可以直接略过。