志在指尖
用双手敲打未来

python编码(python代码加密)

python编码

我用的是python3,错误在对htmlresponse的decode时抛出,代码原样为:
response=urllib.urlopen(dsturl)
content=response.read().decode(‘utf-8’)
抛出错误为
File”./unxingCrawler_p3.py”,line50,ingetNewPhones
content=response.read().decode()
UnicodeDecodeError:’utf8’codeccan’tdecodebyte0xb2inposition24137:invalidstartbyte
之前运行都没问题,经过一晚上就出现了。。。。最不明白的是在它声明为utf-8编码的网页中为什么会出现utf-8无法解析的字符?
后来经过热心网友的提醒,才发现需要使用decode(‘utf-8′,’ignore’)
为了彻底闹明白python的编码问题,特分享下文,希望对大家熟悉python的编码问题带来些帮助
1.从字节说起:
一个字节包括八个比特位,每个比特位表示0或1,一个字节即可表示从00000000到11111111共2^8=256个数字。一个ASCII编码使用一个字节(除去字节的最高位作为作奇偶校验位),ASCII编码实际使用一个字节中的7个比特位来表示字符,共可表示2^7=128个字符。比如ASCII编码中的01000001(即十进制的65)表示字符’A’,01000001加上32之后的01100001(即十进制的97)表示字符’a’。现在打开Python,调用chr和ord函数,我们可以看到Python为我们对ASCII编码进行了转换。如图
第一个00000000表示空字符,因此ASCII编码实际上只包括了字母、标点符号、特殊符号等共127个字符。因为ASCII是在美国出生的,对于由字母组成单词进而用单词表达的英文来说也是够了。但是中国人、日本人、韩国人等其他语言的人不服了。中文是一个字一个字,ASCII编码用上了浑身解数256个字符都不够用。
因此后来出现了Unicode编码。Unicode编码通常由两个字节组成,共表示256*256个字符,即所谓的UCS-2。某些偏僻字还会用到四个字节,即所谓的UCS-4。也就是说Unicode标准也还在发展。但UCS-4出现的比较少,我们先记住:最原始的ASCII编码使用一个字节编码,但由于语言差异字符众多,人们用上了两个字节,出现了统一的、囊括多国语言的Unicode编码。
在Unicode中,原本ASCII中的127个字符只需在前面补一个全零的字节即可,比如前文谈到的字符‘a’:01100001,在Unicode中变成了0000000001100001。不久,美国人不开心了,吃上了世界民族之林的大锅饭,原本只需一个字节就能传输的英文现在变成两个字节,非常浪费存储空间和传输速度。
人们再发挥聪明才智,于是出现了UTF-8编码。因为针对的是空间浪费问题,因此这种UTF-8编码是可变长短的,从英文字母的一个字节,到中文的通常的三个字节,再到某些生僻字的六个字节。解决了空间问题,UTF-8编码还有一个神奇的附加功能,那就是兼容了老大哥的ASCII编码。一些老古董软件现在在UTF-8编码中可以继续工作。
注意除了英文字母相同,汉字在Unicode编码和UTF-8编码中通常是不同的。比如?汉字的‘中’字在Unicode中是0100111000101101,而在UTF-8编码中是111001001011100010101101。
我们祖国母亲自然也有自己的一套标准。那就是GB2312和GBK。当然现在挺少看到。通常都是直接使用UTF-8。
2.Python3中的默认编码
Python3中默认是UTF-8,我们通过以下代码:
importsys
sys.getdefaultencoding()
可查看Python3的默认编码。?
3.Python3中的?encode和decode
Python3中字符编码经常会使用到decode和encode函数。特别是在抓取网页中,这两个函数用的熟练非常有好处。encode的作用,使我们看到的直观的字符转换成计算机内的字节形式。decode刚好相反,把字节形式的字符转换成我们看的懂的、直观的、“人模人样”的形式。
Python客栈送红包、纸质书
\x表示后面是十六进制,\xe4\xb8\xad即是二进制的111001001011100010101101。也就是说汉字‘中’encode成字节形式,是111001001011100010101101。同理,我们拿111001001011100010101101也就是\xe4\xb8\xad来decode回来,就是汉字‘中’。完整的应该是b’\xe4\xb8\xad’,在Python3中,以字节形式表示的字符串则必须加上前缀b,也就是写成上文的b’xxxx’形式。
前文说的Python3的默认编码是UTF-8,所以我们可以看到,Python处理这些字符的时候是以UTF-8来处理的。因此从上图可以看到,就算我们通过encode(‘utf-8′)特意把字符encode为UTF-8编码,出来的结果还是相同:b’\xe4\xb8\xad’。
明白了这一点,同时我们知道?UTF-8兼容ASCII,我们可以猜想大学时经常背诵的‘A’对应ASCII中的65,在这里是不是也能正确的decode出来呢。十进制的65转换成十六进制是41,我们尝试下:
b’\x41′.decode()
结果如下。果然是字符‘A’
4.Python3中的?编码转换
据说字符在计算机的内存中统一是以Unicode编码的。只有在字符要被写进文件、存进硬盘或者从服务器发送至客户端(例如网页前端的代码)时会变成utf-8。但其实我比较关心怎么把这些字符以Unicode的字节形式表现出来,露出它在内存中的庐山正面目的。这里有个照妖镜:
xxxx.encode/decode(‘unicode-escape’)
b’\\u4e2d’还是b’\u4e2d,一个斜杠貌似没影响。同时可以发现在shell窗口中,直接输’\u4e2d’和输入b’\u4e2d’.decode(‘unicode-escape’)是相同的,都会打印出汉字‘中’,反而是’\u4e2d’.decode(‘unicode-escape’)会报错。说明说明Python3不仅支持Unicode,而且一个‘\uxxxx’格式的Unicode字符可被辨识且被等价于str类型。
如果我们知道一个Unicode字节码,怎么变成UTF-8的字节码呢。懂了以上这些,现在我们就有思路了,先decode,再encode。代码如下:
?xxx.decode(‘unicode-escape’).encode()
?最后的扩展
还记得刚刚那个ord吗。时代变迁,老大哥ASCII被人合并,但ord还是有用武之地。试试ord(‘中’),输出结果是20013。20013是什么呢,我们再试试hex(ord(‘中’)),输出结果是’0x4e2d’,也就是20013是我们在上文见面了无数次的x4e2d的十进制值。这里说下hex,是用来转换成十六进制的函数,学过单片机的人对hex肯定不会陌生。
最后的扩展,在网上看到的他人的问题。我们写下类似于’\u4e2d’的字符,Python3知道我们想表达什么。但是让Python读取某个文件的时候出现了’\u4e2d’,是不是计算机就不认识它了呢?后来下文有人给出了答案。如下:
importcodecs
file=codecs.open(“a.txt”,”r”,”unicode-escape”)
u=file.read()
print(u)python

python代码加密

去年11月在PyConChina2018杭州站分享了Python源码加密,讲述了如何通过修改Python解释器达到加解密Python代码的目的。然而因为笔者拖延症发作,一直没有及时整理成文字版,现在终于战胜了它,才有了本文。
本系列将首先介绍下现有源码加密方案的思路、方法、优点与不足,进而介绍如何通过定制Python解释器来达到更好地加解密源码的目的。
由于Python的动态特性和开源特点,导致Python代码很难做到很好的加密。社区中的一些声音认为这样的限制是事实,应该通过法律手段而不是加密源码达到商业保护的目的;而还有一些声音则是不论如何都希望能有一种手段来加密。于是乎,人们想出了各种或加密、或混淆的方案,借此来达到保护源码的目的。
常见的源码保护手段有如下几种:
发行.pyc文件
代码混淆
使用py2exe
使用Cython
下面来简单说说这些方案。
1发行.pyc文件
1.1思路
大家都知道,Python解释器在执行代码的过程中会首先生成.pyc文件,然后解释执行.pyc文件中的内容。当然了,Python解释器也能够直接执行.pyc文件。而.pyc文件是二进制文件,无法直接看出源码内容。如果发行代码到客户环境时都是.pyc而非.py文件的话,那岂不是能达到保护Python代码的目的?
1.2方法
把.py文件编译为.pyc文件,是件非常轻松地事情,可不需要把所有代码跑一遍,然后去捞生成的.pyc文件。
事实上,Python标准库中提供了一个名为compileall的库,可以轻松地进行编译。
执行如下命令能够将遍历<src>目录下的所有.py文件,将之编译为.pyc文件:
python-mcompileall<src>然后删除<src>目录下所有.py文件就可以打包发布了:
$find<src>-name’*.py’-typef-print-execrm{}\;
1.3优点
简单方便,提高了一点源码破解门槛
平台兼容性好,.py能在哪里运行,.pyc就能在哪里运行
1.4不足
解释器兼容性差,.pyc只能在特定版本的解释器上运行
有现成的反编译工具,破解成本低
python-uncompyle6就是这样一款反编译工具,效果出众。
执行如下命令,即可将.pyc文件反编译为.py文件:
$uncompyle6*compiled-python-file-pyc-or-pyo*
2代码混淆
如果代码被混淆到一定程度,连作者看着都费劲的话,是不是也能达到保护源码的目的呢?
2.1思路
既然我们的目的是混淆,就是通过一系列的转换,让代码逐渐不让人那么容易明白,那就可以这样下手:-移除注释和文档。没有这些说明,在一些关键逻辑上就没那么容易明白了。-改变缩进。完美的缩进看着才舒服,如果缩进忽长忽短,看着也一定闹心。-在tokens中间加入一定空格。这就和改变缩进的效果差不多。-重命名函数、类、变量。命名直接影响了可读性,乱七八糟的名字可是阅读理解的一大障碍。-在空白行插入无效代码。这就是障眼法,用无关代码来打乱阅读节奏。
2.2方法
方法一:使用oxyry进行混淆
http://pyob.oxyry.com/是一个在线混淆Python代码的网站,使用它可以方便地进行混淆。
假定我们有这样一段Python代码,涉及到了类、函数、参数等内容:
#coding:utf-8
classA(object):
“””
Description
“””
def__init__(self,x,y,default=None):
self.z=x+y
self.default=default
defname(self):
return’NoName’
defalways():
returnTrue
num=1
a=A(num,999,100)
a.name()
always()
经过Oxyry的混淆,得到如下代码:
classA(object):#line:4
“”#line:7
def__init__(O0O0O0OO00OO000O0,OO0O0OOOO0000O0OO,OO0OO00O00OO00OOO,OO000OOO0O000OOO0=None):#line:9
O0O0O0OO00OO000O0.z=OO0O0OOOO0000O0OO+OO0OO00O00OO00OOO#line:10
O0O0O0OO00OO000O0.default=OO000OOO0O000OOO0#line:11
defname(O000O0O0O00O0O0OO):#line:13
return’NoName’#line:14
defalways():#line:17
returnTrue#line:18
num=1#line:21
a=A(num,999,100)#line:22
a.name()#line:23
always()
混淆后的代码主要在注释、参数名称和空格上做了些调整,稍微带来了点阅读上的障碍。
方法二:使用pyobfuscate库进行混淆
pyobfuscate算是一个颇具年头的Python代码混淆库了,但却是“老当益壮”了。
对上述同样一段Python代码,经pyobfuscate混淆后效果如下:
#coding:utf-8
if64-64:i11iIiiIii
if65-65:O0/iIii1I11I1II1%OoooooooOO-i1IIi
classo0OO00(object):
if78-78:i11i.oOooOoO0Oo0O
if10-10:IIiI1I11i11
if54-54:i11iIi1-oOo0O0Ooo
if2-2:o0*i1*ii1IiI1i%OOooOOo/I11i/Ii1I
def__init__(self,x,y,default=None):
self.z=x+y
self.default=default
if48-48:iII111i%IiII+I1Ii111/ooOoO0o*Ii1I
defname(self):
return’NoName’
if46-46:ooOoO0o*I11i-OoooooooOO
if30-30:o0-O0%o0-OoooooooOO*O0*OoooooooOO
defOo0o():
returnTrue
if60-60:i1+I1Ii111-I11i/i1IIi
if40-40:oOooOoO0Oo0O/O0%ooOoO0o+O0*i1IIi
I1Ii11I1Ii1i=1
Ooo=o0OO00(I1Ii11I1Ii1i,999,100)
Ooo.name()
Oo0o()#dd678faae9ac167bc83abf78e5cb2f3f0688d3a3
相比于方法一,方法二的效果看起来更好些。除了类和函数进行了重命名、加入了一些空格,最明显的是插入了若干段无关的代码,变得更加难读了。
2.3优点
简单方便,提高了一点源码破解门槛
兼容性好,只要源码逻辑能做到兼容,混淆代码亦能
2.4不足
只能对单个文件混淆,无法做到多个互相有联系的源码文件的联动混淆
代码结构未发生变化,也能获取字节码,破解难度不大
3使用py2exe
3.1思路
py2exe是一款将Python脚本转换为Windows平台上的可执行文件的工具。其原理是将源码编译为.pyc文件,加之必要的依赖文件,一起打包成一个可执行文件。
如果最终发行由py2exe打包出的二进制文件,那岂不是达到了保护源码的目的?
3.2方法
使用py2exe进行打包的步骤较为简便。
1)编写入口文件。本示例中取名为hello.py:
print’HelloWorld’
2)编写setup.py:
fromdistutils.coreimportsetup
importpy2exe
setup(console=[‘hello.py’])
3)生成可执行文件
pythonsetup.pypy2exe
生成的可执行文件位于dist\hello.exe。
3.3优点
能够直接打包成exe,方便分发和执行
破解门槛比.pyc更高一些
3.4不足
兼容性差,只能运行在Windows系统上
生成的可执行文件内的布局是明确、公开的,可以找到源码对应的.pyc文件,进而反编译出源码
4使用Cython
4.1思路
虽说Cython的主要目的是带来性能的提升,但是基于它的原理:将.py/.pyx编译为.c文件,再将.c文件编译为.so(Unix)或.pyd(Windows),其带来的另一个好处就是难以破解。
4.2方法
使用Cython进行开发的步骤也不复杂。
1)编写文件hello.pyx或hello.py:
defhello():
print(‘hello’)
2)编写setup.py:
fromdistutils.coreimportsetup
fromCython.Buildimportcythonize
setup(name=’HelloWorldapp’,
ext_modules=cythonize(‘hello.pyx’))
3)编译为.c,再进一步编译为.so或.pyd:
pythonsetup.pybuild_ext–inplace
执行python-c”fromhelloimporthello;hello()”即可直接引用生成的二进制文件中的hello()函数。
4.3优点
生成的二进制.so或.pyd文件难以破解
同时带来了性能提升
4.4不足
兼容性稍差,对于不同版本的操作系统,可能需要重新编译
虽然支持大多数Python代码,但如果一旦发现部分代码不支持,完善成本较高
下文我们将重点介绍一种新的保护源码的方法。
相关文章:如何保护你的Python代码(二)——定制Python解释器
0前言
考虑前文所述的几个方案,均是从源码的加工入手,或多或少都有些不足。假设我们从解释器的改造入手,会不会能够更好的保护代码呢?
由于发行商业Python程序到客户环境时通常会包含一个Python解释器,如果改造解释器能解决源码保护的问题,那么也是可选的一条路。
假定我们有一个算法,能够加密原始的Python代码,这些加密后代码随发行程序一起,可被任何人看到,却难以破解。另一方面,有一个定制好的Python解释器,它能够解密这些被加密的代码,然后解释执行。而由于Python解释器本身是二进制文件,人们也就无法从解释器中获取解密的关键数据。从而达到了保护源码的目的。
要实现上述的设想,我们首先需要掌握基本的加解密算法,其次探究Python执行代码的方式从而了解在何处进行加解密,最后禁用字节码用以防止通过.pyc反编译。
1加解密算法
1.1对称密钥加密算法
对称密钥加密(Symmetric-keyalgorithm)又称为对称加密、私钥加密、共享密钥加密,是密码学中的一类加密算法。这类算法在加密和解密时使用相同的密钥,或是使用两个可以简单地相互推算的密钥。
对称加密算法的特点是算法公开、计算量小、加密速度快、加密效率高。
常见的对称加密算法有:DES、3DES、AES、Blowfish、IDEA、RC5、RC6等。

未经允许不得转载:IT技术网站 » python编码(python代码加密)
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!

 

志在指尖 用双手敲打未来

登录/注册IT技术大全

热门IT技术

C#基础入门   SQL server数据库   系统SEO学习教程   WordPress小技巧   WordPress插件   脚本与源码下载