之前我们已经系统的了解过了requests库了,但是愈发觉得这个三方库真是太完美了,利用python可以http请求发送soap报文(xml数据格式)进行webservice接口调用。
本章内容:

1.python的占位符%s,%d,%r,%f
2.进制转换
3.bytes与str之间的转换
4.python的运算符☆☆
5.python通过http请求发送soap报文进行webservice接口调用
6.python的编码与解码
7.python的各种加密:base64加密,md5,RSA…
8.python压缩打包文件为zip
9.python类的继承和多态

1.python的占位符

  • %s代表字符串占位符
  • %d代表数字占位符,但只能是十进制整数
  • %f默认保留6为小数位,而第7位根据四舍五入取值

2.进制转换

  • bin(number) 将十进制转换为二进制
  • oct(number) 将十进制转换为八进制
  • hex(number) 将十进制转换为十六进制
  • bytes(string) 将字符串字节化
  • ord(string) 将字符转换为ASCII码
  • chr(number) 将ASCII码转换为字符

二,八,十六进制转换为十进制:

1
2
3
4
5
6
>>> int('0b1101',2)  
13
>>> int('0o226',8) #00226 0:阿拉伯数字零 o:小写英文字母 o 226:八进制数
150
>>> int('0x96',16)
150

2020-10-29 新增:传入数值,转换为目标进制(2、8、10、16、32…)

1
2
3
4
5
6
7
8
9
10
# -*- coding:utf-8 -*-


def BaseCovert(num, b):
return ((num == 0) and "0") or (BaseCovert(num // b, b).lstrip("0") +
"0123456789abcdefghijklmnopqrstuvwxyz"[num % b])


if __name__ == '__main__':
print(BaseCovert(1603940678816, 32)) # 1elp50v50

3.bytes与str之间的转换

bytes 和 str 的区别:
bytes 存储字节( 通常值在 range(0, 256))
str 存储unicode字符( 通常值在0~65535)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# bytes object
b = b"example"

# str object
s = "example"

解码(decode)
bytes ----------> str: 存在两种方式
1. str(b, encoding = "utf-8")
2. bytes.decode(b)

编码(encode)
str ----------> bytes:存在两种方式
1. bytes(s, encoding = "utf8")
2. str.encode(s)

bytes 与 str 的转换
编码(encode)
str ———-> bytes
b = s.encode(encoding=’utf-8’)

解码(decode)
bytes ———-> str
s = b.decode(encoding=’utf-8’)

4.python的运算符

位运算符:

运算符 描述
& 按位与运算符:参与运算的两个值,如果两个相应位都为1,则该位的结果为1,否则为0
竖线 按位或运算符:只要对应的二个二进位有一个为1时,结果位就为1
^ 按位异或运算符:当两对应的二进位相异时,结果为1
~ 按位取反运算符:对数据的每个二进制位取反,即把1变为0,把0变为1
<< 左移动运算符:运算数的各二进位全部左移若干位,由 << 右边的数字指定了移动的位数,高位丢弃,低位补0
>> 右移动运算符:把”>>”左边的运算数的各二进位全部右移若干位,>> 右边的数字指定了移动的位数

举例说明:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
a = 60            # 60 = 0011 1100 
b = 13 # 13 = 0000 1101
c = 0

c = a & b; # 12 = 0000 1100
print "1 - c 的值为:", c

c = a | b; # 61 = 0011 1101
print "2 - c 的值为:", c

c = a ^ b; # 49 = 0011 0001
print "3 - c 的值为:", c

c = ~a; # -61 = 1100 0011
print "4 - c 的值为:", c

c = a << 2; # 240 = 1111 0000
print "5 - c 的值为:", c

c = a >> 2; # 15 = 0000 1111
print "6 - c 的值为:", c

逻辑运算符

运算符 描述
+ 两个对象相加
- 两个对象相减
* 两个对象相乘
/ 两个对象相除
% 返回触发的余数
** x的y次幂
// 返回商的整数部分,向下取整

逻辑运算符

运算符 描述
and 逻辑与,“一假则假”
or 逻辑或,“一真为真,都假则假”
not 逻辑非,取反义

成员运算符

运算符 描述
in 如果在指定的序列中找到值返回 True,否则返回 False
not in 如果在指定的序列中没有找到值返回 True,否则返回 False

比较运算符

运算符 描述 实例
== 等于 比较对象是否相等
!= 不等于 比较两个对象是否不相等 (a != b) 返回 True
> 大于 返回x是否大于y (a > b) 返回 False
< 小于 返回x是否小于y。这分别与特殊的变量True和False等价。(a < b)返回True
>= 大于等于 返回x是否大于等于y。 (a >= b) 返回 False
<= 小于等于 返回x是否小于等于y。 (a <= b) 返回 True

拓:身份运算符is:is 与 == 区别

is用于判断两个变量引用对象是否为同一个,== 用于判断引用变量的值是否相等

5.python通过http请求发送soap报文进行webservice接口调用

什么是xml?

摘自百度百科:扩展标记语言 (Extensible Markup Language, XML) ,用于标记电子文件使其具有结构性的标记语言,可以用来标记数据、定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言。 XML使用DTD(document type definition)文档类型定义来组织数据;格式统一,跨平台和语言,早已成为业界公认的标准。
XML是非常适合 Web 传输。XML 提供统一的方法来描述和交换独立于应用程序或供应商的结构化数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?xml version="1.0" encoding="utf-8" ?>
<country>
<name>中国</name>
<province>
<name>广东</name>
<citys>
<city>广州</city>
<city>深圳</city>
<city>珠海</city>
</citys>   
</province>
<province>
<name>台湾</name>
<citys>
 <city>台北</city>
 <city>高雄</city>
</citys> 
</province>
</country>

什么是SoapUI?

soapui提供一个工具通过soap/http协议来检查,调用,实现web service和web service的功能/负载/符合性测试。该工具既可作为一个桌面应用软件使用,也可利用插件集成到Eclipse,maven2.X,netbeans 和intellij中使用。
即SoapUI是一款测试工具,你可以等同于Postman

什么是soap,http协议?

http是标准超文本传输协议。使用对参数进行编码并将参数作为键值对传递,还使用关联的请求语义。
SOAP(Simple Object AccessProtocol)简单对象访问协议。它是轻型协议,用于分散的、分布式计算环境中交换信息。SOAP有助于以独立于平台的方式访问对象、服务和服务器。它借助于XML,提供了HTTP所需的扩展。

SOAP与HTTP的区别:

  • 都是底层的通信协议,请求包的格式不同,soap包是XML格式,http纯文本格式
  • soap可以传递结构化的数据,http只能传输纯文本数据;
  • soap:简单对象访问协议;http是标准超文本传输协议
  • soap相对http(post/get)由于要进行xml解析,速度可能会有所降低。

总结:HTTPService基于http协议,而WebService基于soap协议。soap 就是xml 的格式传输,Http是传输协议,soap不是传输协议,只是按照约定的方式封装消息

————————————————

python通过http请求发送soap报文进行webservice接口调用

webservice的接口长什么样? 很多api接口的后缀需要加 ?wsdl
api: http://www.webxml.com.cn/WebServices/ValidateCodeWebService.asmx?wsdl

我们要明确知道,发送的soap报文也是xml,webservice也是xml数据格式

★★★★ 要调用webservice接口的前提必须是请求头有如下三个值:

  • Content-type:指定数据类型
  • Content-length:传入数据长度
  • SOAPAction:soap协议的动作或叫做方法(把webservice的api接口在浏览器输入并访问,文本内容中就有SoapAction)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import requests


# 发送给webservice的请求体数据
send_webservice_data = '''
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://service.inf.oa.ztesoft.com">
<soapenv:Header/>
<soapenv:Body>
<ser:Login>
<ser:UserName>username</ser:UserName>
<ser:Password>password</ser:Password>
</ser:Login>
</soapenv:Body>
</soapenv:Envelope>
'''

url = "http://127.0.0.1:8088/mockOaOrderServicePortSoapBinding"
# 构造响应头
headers = {
"User-Agent": "Python Post",
"Content-type": "text/xml; charset=UTF-8",
"Content-length": "%d" % len(send_webservice_data),
"SOAPAction": "UFIDA.U9.Cust.DoubleRing.ProjectSV/ICreateProject/Do"
}


"""发送webservice请求,获取响应信息"""
response = requests.post(url, headers=headers, data=send_webservice_data, verify=False)
xml_data = response.text
print(xml_data)

6.python的编码与解码

python3默认编码为unicode(utf-8是其的一种扩展,两者本质相同,只是收集字数不同),由str类型进行表示。二进制数据使用byte类型表示,所以不会将str和byte混在一起。在实际应用中我们经常需要将两者进行互转.

encode和decode分别指编码和解码。在python中,Unicode类型是作为编码的基础类型,即:

1
2
3
4
5
6
7
8
9
10
11
        decode                 encode
bytes ---------> str(Unicode) ---------> bytes

u = '中文' #指定字符串类型对象u
str = u.encode('gb2312') #以gb2312编码对u进行编码,获得bytes类型对象str
u1 = str.decode('gb2312') #以gb2312编码对字符串str进行解码,获得字符串类型对象u1
u2 = str.decode('utf-8') #如果以utf-8的编码对str进行解码得到的结果,将无法还原原来的字符串内容

with open('text.text','r+',encoding='utf-8') as f: #必须事先知道文件的编码格式,这里文件编码是使用的utf-8
content = f.read()#如果open时使用的encoding和文件本身的encoding不一致的话,那么这里将将会产生错误
f.write('你想要写入的信息')

关于一些奇奇怪怪的字符编码处理😓😓😓

  1. strings.encode(‘raw_unicode_escape’).decode()

用来处理形如这种反人类字符:é‡ç»„äººè¡¨çš®ç”Ÿé•¿å› å­å‡èƒ¶(易孚

  1. strings.encode(“utf-8”).decode(“unicode_escape”)

用来处理形如这种的Unicode字符:\u002F

1
2
3
slashUStr = "https:\u002F\u002Fm.dhgate.com\u002Fproduct\u002F427954156.html"
decodedUniChars = slashUStr.encode('utf-8').decode("unicode_escape")
print("decodedUniChars=", decodedUniChars)
  1. urllib包中parse模块的quote和unquote

用来处理url编码/解码,功能类似于js的encodeURIComponent/decodeURIComponent

1
2
3
4
5
6
7
8
from urllib import parse

# 这个是js的结果
# encodeURIComponent('中国')
# "%E4%B8%AD%E5%9B%BD"
jsRet='%E4%B8%AD%E5%9B%BD'
print(parse.unquote(jsRet)) #输出:中国
print(jsRet==parse.quote('中国')) #输出:True

7.python的各种加密

7.1 背景

关于对称加密与非对称加密,参考文章:https://blog.csdn.net/yangxiaodong88/article/details/80801278

7.2 base64加密

  • python3 输入的都是 二进制 / byte类型,注意:用于base64编码的,要么是ASCII包含的字符,要么是二进制数据
  • base64 是对称加密,即这种加密方式是可以被破解的

base64 是 一种用64 个字符来表示任意的二进制数据的方法。base64 可以成为密码学的基石。可以将任意二进制数据进行Base64 编码。 所有的数据都能被编码为并只有64个字符就能表示的文本文件。( 64字符:A~Z a~z 0~9 + / )编码后的数据~=编码前数据的4/3,会大1/3左右。

1
2
3
4
5
6
7
8
9
10
11
12
13
import base64

s = 'hello, world'

# 加密
bs = base64.b64encode(s.encode("utf-8")) # base64加密参数要求是字节型的
print(bs.decode("utf-8"))

# 解密
decode = base64.b64decode("target_string") # 解密后为byte类型
print(decode)
# 解码:由byte转化为string
print(decode.decode("utf-8"))

说明:像出现这样的字段“aHR0cXXXXX…” 这类的字符串就是url进行base64编码后的样式

1
2
3
4
5
6
7
aHR0cHM6Ly94aWFwaS54aWFwaWJ1eS5jb20vc2VhcmNoP2tleXdvcmQ9JUU3JTk0JUI3JUU3JUFCJUE1JUU0JUI4JThBJUU4JUExJUEz
⬇ base64解密
https://xiapi.xiapibuy.com/search?keyword=男童上衣

https://AhriLove.top
⬇ base64加密
aHR0cHM6Ly9BaHJpTG92ZS50b3A=

7.3 md5加密

在python3中使用hashlib模块进行md5操作(md5不可逆向破解)

1
2
3
4
5
6
7
8
9
10
11
12
import hashlib

strs = "我真帅"

# 创建一个md5 对象,初始化字符串
h1 = hashlib.md5()
# 此处必须声明encode
# 若写法为hl.update(str) 报错为: Unicode-objects must be encoded before hashing
h1.update(strs.encode("utf-8")) # 用提供的字节串更新此哈希对象(hash object)的状态
print("加密前", strs)
print("加密后", h1.hexdigest()) # 返回摘要值,以十六进制数字字符串的形式
print("加密后", h1.digest()) # 返回摘要值,以二进制字节串的形式

拓展:

  1. 信息摘要算法

message-digest algorithm 5(信息-摘要算法)。经常说的“MD5加密”,就是它→信息-摘要算法。

md5,其实就是一种算法。可以将一个字符串,或文件,或压缩包,执行md5后,就可以生成一个固定长度为128bit的串。这个串,基本上是唯一的。

md5特点:

  • 压缩性:任意长度的数据,算出的MD5值长度都是固定的。
  • 容易计算:从原数据计算出MD5值很容易。
  • 抗修改性:对原数据进行任何改动,哪怕只修改1个字节,所得到的MD5值都有很大区别。
  • 强抗碰撞:已知原数据和其MD5值,想找到一个具有相同MD5值的数据(即伪造数据)是非常困难的

md5的长度:md5的长度,默认为128bit,也就是128个0和1的二进制串。这样表达是很不友好的。所以将二进制转成了16进制,每4个bit表示一个16进制,所以128/4 = 32 换成16进制表示后,为32位了。

为什么网上还有md5是16位的呢?其实16位的长度,是从32位md5值来的。是将32位md5去掉前八位,去掉后八位得到的

  1. 关于hexdigest与digest说明

之前我们已经提到过了,hexdigest返回是16进制的字符串,而digest返回二进制byte类型(注意!有一种加密方式是:digest加密的md5结果,然后在经过base64编码)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import base64
import hashlib


b = "hello,world"
md5 = hashlib.md5()
md5.update(b.encode('utf-8'))
b = md5.digest()
print(u"digest的md5加密结果:%s" % b)
print(u"hexdigest的md5加密结果:%s" % md5.hexdigest())
print(u"digest的md5加密结果再进行base64编码:%s" % base64.b64encode(b).decode('utf-8'))

"""
digest的md5加密结果:b'<\xb9\\\xfb\xe1\x03[\xce\x8cD\x8f\xca\xf8\x0f\xe7\xd9'
hexdigest的md5加密结果:3cb95cfbe1035bce8c448fcaf80fe7d9
digest的md5加密结果再进行base64编码:PLlc++EDW86MRI/K+A/n2Q==
"""

7.4 sha系列加密

常见的sha系列加密有:sha1,sha224,sha256,sha512

1
2
3
4
5
6
7
8
import hashlib
def str_encrypt(str):
"""
使用sha1加密算法,返回str加密后的字符串
"""
sha = hashlib.sha1(str.encode("utf-8"))
encrypts = sha.hexdigest()
return encrypts

7.5 RSA加密☆☆

典型的非对称加密,如RSA等,常见方法,使用openssl ,keytools等工具生成一对公私钥对,使用被公钥加密的数据可以使用私钥来解密,反之亦然(被私钥加密的数据也可以被公钥解密) 。

在实际使用中私钥一般保存在发布者手中,是私有的不对外公开的,只将公钥对外公布,就能实现只有私钥的持有者才能将数据解密的方法。 这种加密方式安全系数很高,因为它不用将解密的密钥进行传递,从而没有密钥在传递过程中被截获的风险,而破解密文几乎又是不可能的。

但是算法的效率低,所以常用于很重要数据的加密,常和对称配合使用,使用非对称加密的密钥去加密对称加密的密钥。

前端RSA加密,后端RSA解密使用 PKCS1_v1_5,不要用 PKCS1_OAEP,使用 PKCS1_OAEP 的话,前端 jsencrypt.js 加密的数据解密不了

  • RSA生成公钥私钥
1
2
3
4
5
6
7
8
9
10
11
12
13
14
from Crypto.PublicKey import RSA

# rsa算法对象生成
rsa_obj = RSA.generate(1024)
# pem格式输出私钥
private_pem = rsa_obj.exportKey()
print(private_pem.decode("utf-8"))
print("=========================")

# 生成公钥
public_key = rsa_obj.publickey()
# 将公钥输出成pem格式
public_pem = public_key.exportKey()
print(public_pem.decode("utf-8"))
  • RSA实现加密解密
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
import base64
from Crypto import Random
from Crypto.Cipher import PKCS1_v1_5 as Cipher_pkcs1_v1_5
from Crypto.PublicKey import RSA

message = b"this is test" # 必须为byte型

rsa_private_key = b'-----BEGIN RSA PRIVATE KEY-----\n私钥内容\n-----END RSA PRIVATE KEY-----\n'

rsa_public_key = b'-----BEGIN PUBLIC KEY-----\n公钥内容\n-----END PUBLIC KEY-----\n'

# 加密
rsakey = RSA.importKey(rsa_public_key)
cipher = Cipher_pkcs1_v1_5.new(rsakey)
cipher_text = base64.b64encode(cipher.encrypt(message))
print(cipher_text)

# 解密
rsakey = RSA.importKey(rsa_private_key)
cipher = Cipher_pkcs1_v1_5.new(rsakey)
random_generator = Random.new().read
text = cipher.decrypt(base64.b64decode(cipher_text), None)
print(text.decode('utf-8'))


def encrypt(message, public_key):
"""
公钥加密字符串
:param message: string 待加密字符串
:param public_key: string 公钥
:return:
"""
# 加密
rsa_key = RSA.importKey(public_key)
cipher = Cipher_pkcs1_v1_5.new(rsa_key)
cipher_text = base64.b64encode(cipher.encrypt(message.encode("utf-8")))
print(cipher_text.decode("utf-8"))


if __name__ == '__main__':
pub = '\n'.join([
'-----BEGIN PUBLIC KEY-----',
'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCp0wHYbg/NOPO3nzMD3dndwS0M',
'ccuMeXCHgVlGOoYyFwLdS24Im2e7YyhB0wrUsyYf0/nhzCzBK8ZC9eCWqd0aHbdg',
'OQT6CuFQBMjbyGYvlVYU2ZP7kG9Ft6YV6oc9ambuO7nPZh+bvXH0zDKfi02prknr',
'ScAKC0XhadTHT3Al0QIDAQAB',
'-----END PUBLIC KEY-----'
])
encrypt("this is a test", public_key=pub)

简介
RSA加密算法是一种非对称加密算法。在公开密钥加密和电子商业中RSA被广泛使用。

该算法基于一个十分简单的数论事实:将两个大素数相乘十分容易,但那时想要对其乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥,即公钥,而两个大素数组合成私钥。公钥是可发布的供任何人使用,私钥则为自己所有,供解密之用

几个知识点:

  1. 密匙格式:其实就是报文格式不同的区别
  • PKCS#8 格式公钥
  • PKCS#1 格式私钥

PEM格式包含几种报文头:

1
2
3
4
5
"-----BEGIN PUBLIC KEY-----": PKCS#8 格式公钥
"-----BEGIN PRIVATE KEY-----": PKCS#8 格式私钥

"-----BEGIN RSA PUBLIC KEY-----": PKCS#1 格式公钥
"-----BEGIN RSA PRIVATE KEY-----": PKCS#1 格式私钥
  1. 公钥加密、私钥解密、私钥签名、公钥验签 :https://www.cnblogs.com/pcheng/p/9629621.html

  2. 私钥密码

  3. 密匙长度

1
2
3
4
- 512bit
- 1024bit
- 2048bit
- 4096bit
  1. RSA1,RSA2
开放平台签名算法名称 标准签名算法名称 备注
RSA2 SHA256WithRSA 强制要求 RSA 密钥的长度至少为 2048
RSA SHA1WithRSA 对 RSA 密钥的长度不限制,推荐使用 2048 位以上

8.python压缩打包文件为zip

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# -*- coding:utf-8 -*-
# 使用zipfile做目录压缩,解压缩功能
import os
import os.path
import zipfile


class Zip(object):
def __init__(self, dirname, zipfilename):
self.dirname = dirname
self.zipfilename = zipfilename

# 压缩功能
def zip_dir(self):
filelist = []
if os.path.isfile(self.dirname):
filelist.append(self.dirname)
else:
for root, dirs, files in os.walk(self.dirname):
for name in files:
filelist.append(os.path.join(root, name))

zf = zipfile.ZipFile(self.zipfilename, "w", zipfile.zlib.DEFLATED)
for tar in filelist:
arc_name = tar[len(self.dirname):]
zf.write(tar, arc_name)
zf.close()


if __name__ == '__main__':
zip = Zip(dirname=r'D:\data\demo\weavercapture\static\images\workflow', zipfilename="./workflow.zip")
zip.zip_dir()

9.python类的继承和多态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# -*- coding:utf-8 -*-


class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age

def eat(self):
print(self.name + "正在吃:{}岁的海子".format(self.age))

def run(self):
print(self.name + "已经跑了:{}公里".format(self.age))


class Man(Person):
def __init__(self, name, age, gender):
# 在创建子类的过程中,你需要手动调用父类的构造函数__init__来完成子类的构造函数
super().__init__(name, age)
self.gender = gender

def ak(self):
print(self.gender)

def ab(self):
# 当你使用Python super()关键字调用父类方法时时,注意去掉括号里self这个参数
super().run()
print("正在调用父类的" + self.name)

def eat(self, types="千米"):
# 重写父类的方法,即多态
print("多态子类"+self.name + ":已经跑了{}-{}".format(self.age, types))


if __name__ == '__main__':
a = Man("chd", "18", "man")
a.eat()
a.run()
print(a.gender)
a.ak()
print("=====================")
a.ab()
print("=====================")
a.eat()

参考文章


 评论

联系我 | Contact with me

Copyright © 2019-2020 谁知你知我,我知你知深。此恨经年深,比情度日久

博客内容遵循 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 协议