问题总结
1.django用post传文件,如何接收和下载?
data= request.FILES.get('file')#接收到的数据类型是<class 'django.core.files.uploadedfile.InMemoryUploadedFile'> # print(data,type(data)) #<class 'django.core.files.uploadedfile.InMemoryUploadedFile'> with open(r'C:\Users\33101\Desktop\12\新建1111.txt','wb') as p:#这样可以写进文件,不能直接p.write(chunks()) for chunk in data.chunks(): p.write(chunk) #读取发送过来的文件,并用base64加密 a=request.FILES.get("file").read() print("传过来的文件:",a) b=base64.b64encode(a) print('加密后的文件:',b) #接收多个文件: files=request.FILES.getlist('up_file') print(files,type(files)) for i in files: print(i.read())#读文件,得到二进制 # print('*******************') print(i.name)#获取文件名字 i.size#获取文件大小的数字(单位是B)
注:如果要查看自己请求发出的所有信息就发送到http://httpbin.org/post,这个url能返回给你你刚才发送的所有请求中的信息。
2.阿里云oss上传/删除图片
#阿里云oss上传图片 import oss2,datetime data = request.FILES.get('file') # 获取post传过来的文件,得到<class 'django.core.files.uploadedfile.InMemoryUploadedFile'> print(data.file) #这个就是你传过来的文件内容 #一下四项都是在阿里云获取的 OSS_URL = '' OSS_NAME = '' ALI_KEY_ID ='' ALI_KEY = '' OSS_URL_HTTPS = 'https://'+OSS_NAME+'.'+OSS_URL+'.com' #拼接个路径,是存放在oss服务器上的位置,注意要带上文件名字 #特别注意:在windows环境拼接的路径和linux上的路径不同,要注意区别。 oss_path = os.path.join('ele_seal', 'test', datetime.datetime.now().strftime('%Y%m%d'),'wwdf.png')#如果在windows机器上就会拼接成windows识别的路径,放到服务器上就不好使了 # oss_path = 'ele_seal/test/20200904/110.png'#手动拼接一个适合linux服务器上的路径 # 上传文件 # auth = oss2.Auth(ALI_KEY_ID, ALI_KEY) # bucket = oss2.Bucket(auth, OSS_URL, OSS_NAME) # result = bucket.put_object(oss_path,data.file)#oss_path就是你文件存放在oss服务器的位置(包含文件名),data.file就是你post传过来的文件的内容(.file是固定用法) # print(result.status)#如果返回200就证明上传成功 #访问上传的图片(固定写法) OSS_URL_HTTPS +'/'+ oss_path #删除已上传的文件 auth = oss2.Auth(ALI_KEY_ID, ALI_KEY) bucket = oss2.Bucket(auth, OSS_URL, OSS_NAME) result = bucket.delete_object('ele_seal/test/20200904/110.png') print(result.status)#返回参数204就删除成功,如果一直卡着,那就证明找不到该文件
3.正匹配手机号码:
# 判断手机号码格式是否正确 regular = '^((13[0-9])|(14[5|7])|(15([0-3]|[5-9]))|(166)|(17[2|8])|(18[0,5-9])|(19[8|9]))\d{8}$' regular_obj = re.compile(regular) check_phone = re.match(regular_obj, phone)
4.获取http请求头内容
用request.META获取的是个大字典,就是请求头所有内容,剩下的就用get取值 a=request.META.get("CONTENT_TYPE") #如果是固定的请求头就直接变成大写,所有的-都变成——就可以获取值了 b=request.META.get("HTTP_APPID")#如果是手动加的就必须以HTTP_开头,再加你写的键(全部大写,遇到-就变成_)即可 c=request.META.get("HTTP_TIME") d=request.META.get("HTTP_SIGN")
5.AES加密
from Crypto.Cipher import AES from binascii import b2a_hex, a2b_hex import time #token加密信息 CRYPTO_KEY = 'A@G#X*NHA@G#X*No'#必须16位,这里是字符串 CRYPTO_OFFSET = b'qqqqqqqqqqqqqqpq'#必须16位,这里是二进制 class HeaderCrypto(object): ''' token 信息的加密与解密 ''' def __init__(self, crypto_key, crypto_offset): ''' :param crypto_key=加密需要的key :param crypto_offset=加密需要的偏移量 crypto_model=crypto采用的加密模式 ''' self.crypto_key = crypto_key.encode('utf-8') self.crypto_offset = crypto_offset self.crypto_model = AES.MODE_CBC def add_to_16(self, cry_con): ''' :param cry_con=需要加密的json字符串进行16位倍数处理 :return: 16位倍数的字符串 不足16位倍数的用0进行填充 ''' zero_num = 16 - (len(cry_con.encode('utf-8')) % 16) if len(cry_con.encode('utf-8')) % 16 else 0 res_cry_con = cry_con + ('\0' * zero_num) return res_cry_con.encode('utf-8') def encrypt(self, cry_con): ''' :param cry_con=需要加密的字符串信息 :return: 加密后的字符串信息 因为AES加密后的字符串不一定是ascii字符集的,输出保存可能存在问题,所以这里转为16进制字符串 ''' res_cry_con = self.add_to_16(cry_con) cryptos = AES.new(self.crypto_key, self.crypto_model, self.crypto_offset) cipher_text = cryptos.encrypt(res_cry_con) return b2a_hex(cipher_text) def decrypt(self, cry_con): ''' :param cry_con=需要解密的字符串信息 :return: 解密后的json字符串 解密后,去掉补足的空格用strip() 去掉 ''' cryptos = AES.new(self.crypto_key, self.crypto_model, self.crypto_offset) plain_text = cryptos.decrypt(a2b_hex(cry_con)) return bytes.decode(plain_text).rstrip('\0') crypto_dict = { 'req_server': 'self.req_server', 'source_sign': 'self.source_sign', 'unique_sign': 'self.unique_sign', 'phonenum': 'phonenum', 'user_id': 'user_id', 'user_type': 0, 'datetime': int(time.time()), } obj=HeaderCrypto(CRYPTO_KEY,CRYPTO_OFFSET) a=obj.encrypt(str(crypto_dict)) print(a)#加密后的值 # c=b'722501109bdd032f0ff9b4090dce0ce028803780ce695910b927ef646c8e3329c07a6b6d589a3ad72c1bca451360fd8cb3cd9d84682bd85d9066d1fd56cca66a8a63a60c2e483a7ccac5018401683d220459dfd1bd9ad4a60a6ead38ff637f7765143aa7d732c0372a5cdb3e460726f00e51961d650a19b57bf1f495d0b13a5c0353746f10cca0531bd5ce73dba790a475c572c363eeaaede6d0564f69de1ef0a2ac858013ed4bd281084496a9b11401bb8a95700782a0139eb4de6d680eb3ed' # # d=obj.decrypt(c)#解密时传的参数是二进制还是字符串均可。 # print(d,type(d))#解密后的值,是字符串 # {'req_server': 'self.req_server', 'source_sign': 'self.source_sign', 'unique_sign': 'self.unique_sign', 'phonenum': 'phonenum', 'user_id': 'user_id', 'user_type': 0, 'datetime': 1599530672}
6.字符串与二进制互转
# 字符串转二进制 a='我是谁' # 法一 # b=a.encode() # print(b,type(b)) # b'\xe6\x88\x91\xe6\x98\xaf\xe8\xb0\x81' <class 'bytes'> # 法二 # c=bytes(a,'utf-8')#utf-8不可省略 # print(c,type(c)) # b'\xe6\x88\x91\xe6\x98\xaf\xe8\xb0\x81' <class 'bytes'> # 二进制转字符串 e=b'\xe6\x88\x91\xe6\x98\xaf\xe8\xb0\x81' # 法一 c=e.decode() print(c,type(c)) # 我是谁 <class 'str'> # 法二 f=str(e,'utf-8')#正确的写法,结果是 我是谁 <class 'str'> # f=str(e) #错误的写法,结果是 b'\xe6\x88\x91\xe6\x98\xaf\xe8\xb0\x81' <class 'str'> print(f,type(f))
7.字符串转字典(eval和ast.literal_eval)
a='{"r":113}' print(a,type(a)) b=eval(a)#用eval很危险 print(b,type(b)) # {"r": 113} <class 'dict'> # eval()函数功能强大,但也很危险,若程序中有以下语句: s=input(‘please input:’) print (eval(s)) # 下面举几个被恶意用户使用的例子: # 1、运行程序,如果用户恶意输入: # eval(“import(‘os’).system(‘ls -l’)”) # 2、运行程序,如果用户恶意输入: # eval(“open(‘a.txt’).read()”) # 如果,当前目录中恰好有一个文件,名为a.txt,则恶意用户变读取到了文件中的内容。 # 3、运行程序,如果用户恶意输入 # 如果,当前目录中恰好有一个文件,名为a.txt,则恶意用户删除了该文件。/q :指定静音状态。不提示您确认删除 # eval(“import(‘os’).system(‘rm -rf a.txt’)”) # 解决方法 import ast c=ast.literal_eval(a) print(c,type(c)) # {"r": 113} <class 'dict'>
8.读图片给图片进行base64加密
import base64 with open(r'C:\Users\33101\Desktop\234.jpg','rb') as f: m = base64.b64encode(f.read()) print(m)#加密后的结果
9.requests接收文件
import requests req = requests.get("http://www.baidu.com/") //发起GET请求 print(req.text) //打印响应内容 req.ok // 检查返回码是不是 '200 OK',如果是则返回True,否则返回False req.url // 查看请求的URL,也就是'http://www.baidu.com/' req.text // 查看返回的响应内容,返回的是Unicode数据,一般用于返回文本数据 req.content // 查看返回的响应内容,返回的是二进制数据,一般用于返回图片,文件等二进制数据 req.status_code // 查看返回的HTTP状态码,如 200,404,502 等 req.reason // 查看返回的HTTP状态码文本原因,如 'Not Found', 'OK' 等 req.cookies // 查看返回的cookies信息 req.header // 查看返回的头部信息 #带参数的get请求: import requests params = { "wd": "hello", "rsv_spt": 1 } req = requests.get("http://www.baidu.com/", params=params) //相当于 requests.get("http://www.baidu.com/s?wd=hello&rsv_spt=1") print(req.text) #伪造请求头信息,发起GET请求: import requests headers = { //定义请求头信息,通常只定义 User-Agent,其他请求头信息可以通过 F12 界面查看,参考:https://www.cnblogs.com/pzk7788/p/10500101.html "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36" } req = requests.get("http://www.baidu.com/", headers=headers) print(req.text)
10.二进制生成图片BytesIO
from PIL import Image from io import BytesIO i = Image.open(BytesIO(二进制内容))#二进制可以是读的图片或者是requests获取的网络图片 i.save(r'C:\Users\33101\Desktop\12\1222223.png') #例: from PIL import Image from io import BytesIO r=requests.get('https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1599671244609&di=101c0cc3ab7c6ceb6a7e39433a1f2e94&imgtype=0&src=http%3A%2F%2Fa2.att.hudong.com%2F36%2F48%2F19300001357258133412489354717.jpg') i = Image.open(BytesIO(r.content)) i.save(r'C:\Users\33101\Desktop\12\2230000.png')
11.用requests模块上传一个或者多个文件
需要用python的MultipartEncoder模块
借鉴文档:https://requests.readthedocs.io/zh_CN/latest/user/quickstart.html#json
注意要用POST请求发送文件
#上传文件分两种,一种是本地文件读成二进制上传,另一种是直接给个url可以下载文件或者是直接在网页上查看的url。 from requests_toolbelt.multipart.encoder import MultipartEncoder import requests # 举例:没有相同的键时 # payload = {'key1': 'value1', 'key2': 'value2'} # r = requests.post("http://httpbin.org/post", data=payload) # print(r.text) #你发送的请求是这样的: # { # ... # "form": { # "key2": "value2", # "key1": "value1" # }, # ... # } # 举例:有相同的键时 # payload = (('key1', 'value1'), ('key1', 'value2')) # r = requests.post('http://httpbin.org/post', data=payload) # print(r.text) #你发送的请求是这样的: # { # ... # "form": { # "key1": [ # "value1", # "value2" # ] # }, # ... # } # 上传文件代码: #请求的url url = 'http://httpbin.org/post' #携带的参数 # MultipartEncoder里面的fields是固定参数不要变,fields里面装的就是post请求携带的表单form里面的键值对,如果键都不同,就把fields写成字典, # 如果有相同的键,就把fields写成大元组,大元组里面每个小元组都有两个值,第一个原来字典的键,第二个就是原来字典的值,这样有相同的键也能传值了 # 当没有重复的键时: multipart_encoder = MultipartEncoder( fields={ "key1": 'value1', "key2": 'value2', "key3": 'value3', #下面doc_file和file_url是两种传文件的方式,二选一,而字段名称doc_file和file_url是服务器那边规定的键的名称 'doc_file': ('12012.docx', open(r'C:\Users\33101\Desktop\合同二.docx', 'rb'), 'application/msword'),#传文件(以二进制形式传) #'12012.docx'表示文件名(带后缀),open(r'C:\Users\33101\Desktop\合同二.docx', 'rb')是读出的本地文件(二进制格式), # 'application/msword'是指明该文件的格式(具体指代需要参考MIME手册) # 注意:值里面不要出现数字(int,float等格式),如果有就换成字符串 'file_url':'https://agxn.oss-cn-beijing.aliyuncs.com/original_files/1599609/18063609.docx?file_name=18063609.docx',#传url #规定:值是url+?+file_name=文件名.后缀(这个规定看服务器那边自己怎么接,你这边url传的时候就怎么传,这里只是举个例子) } ) # 请求头 headers = { "Content-Type": multipart_encoder.content_type, "token": 'token1', "appid": 'asd', "time": '12342123' } #如果写 "Content-Type":'multipart/form-data',发送会失败, # 因为MultipartEncoder实例化对象点出 # 来的content_type是"Content-Type": "multipart/form-data; boundary=538863300a764a09b03121d6ed73ee7e", 的 r = requests.post(url, data=multipart_encoder,headers=headers) print(r.text)#对http://httpbin.org/post网站发送请求能看见自己发送的请求信息 # 当有重复的键时(需要将fields整体改成元组格式,这里是传url): multipart_encoder = MultipartEncoder( fields = (("key1", 'value1'), ("key2", 'value2'), ("key3", 'value3'), ('file_url','https://agxn.oss-cn-beijin683/ece0b_86163683.docx?file_name=ece8f05a_063683.docx'), ('file_url','https://agxn.oss-cn-beijin683/ece0b_1123445.docx?file_name=ece8f1123445.docx'), ('file_url','https://agxn.oss-cn-beijin683/ece0b_7832434534.docx?file_name=7832434534.docx') )) #r.text返回的结果如下(一定要往'http://httpbin.org/post'这个url发请求,才能返回你发的请求内容) { "args": {}, "data": "", "files": {}, "form": { "file_url": [ "https://agxn.oss-cn-beijin683/ece0b_86163683.docx?file_name=ece8f05a_063683.docx", #这里是你传的三个url,直接发过去,不用解析成二进制 "https://agxn.oss-cn-beijin683/ece0b_1123445.docx?file_name=ece8f1123445.docx", "https://agxn.oss-cn-beijin683/ece0b_7832434534.docx?file_name=7832434534.docx" ], "key1": "value1", "key2": "value2", "key3": "value3" }, "headers": { "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "Appid": "asd", "Content-Length": "811", "Content-Type": "multipart/form-data; boundary=b10788d23abb4461b93f308eb8a37a2a", "Host": "httpbin.org", "Time": "12342123", "Token": "token1", "User-Agent": "python-requests/2.24.0", "X-Amzn-Trace-Id": "Root=1-5f59bec0-3609d3e014c21ecbce886f12" }, "json": null, "origin": "124.65.120.250", "url": "http://httpbin.org/post" } # 当有重复的键时(需要将fields整体改成元组格式,这里是传文件的二进制): multipart_encoder = MultipartEncoder( fields = (("key1", 'value1'), ("key2", 'value2'), ("key3", 'value3'), ('doc_file', ('111.docx', open(r'C:\Users\33101\Desktop\合同二.docx', 'rb'), 'application/msword')), ('doc_file', ('222.docx', open(r'C:\Users\33101\Desktop\合同一.docx', 'rb'), 'application/msword')), ('doc_file', ('333.docx', open(r'C:\Users\33101\Desktop\合同三.docx', 'rb'), 'application/msword')), ) ) ) #r.text返回的结果如下(一定要往'http://httpbin.org/post'这个url发请求,才能返回你发的请求内容) { "args": {}, "data": "", "files": { "doc_file": "data:application/msword;base64,UEsDBBQABgAIAAAAIQBKvAJlNWxQSwECLQAUAAYAAODIAAAAA"#这里会很长,是3个文档的所有二进制加到了一起,这里删减了 }, "form": { "key1": "value1", "key2": "value2", "key3": "value3" }, "headers": { "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "Appid": "asd", "Content-Length": "41971", "Content-Type": "multipart/form-data; boundary=7ce811908b004b56985fc17305928f89", "Host": "httpbin.org", "Time": "12342123", "Token": "token1", "User-Agent": "python-requests/2.24.0", "X-Amzn-Trace-Id": "Root=1-5f59bd37-f5abd7a0b50ef630460962f0" }, "json": null, "origin": "124.65.120.254", "url": "http://httpbin.org/post" }
12.如果独立在项目之外,从一个py文件要用orm访问数据库
#在运行代码最上面加上这三行即可
import os,django os.environ.setdefault("DJANGO_SETTINGS_MODULE", "elec_seal.settings")# elec_seal是django的项目名称 django.setup()
#这样下面的orm运行就不会报错
from api import models
a=models.ElectronicSeal.objects.filter(userid='lele')
print(a)
13.将一个文件夹压缩成zip文件(shutil)
import shutil shutil.make_archive( base_name=r'C:\Users\33101\Desktop\11111' ,format='zip', root_dir=r'C:\Users\33101\Desktop\123' )
#base_name是压缩包生成的路径(11111是生成的压缩包的名字,没后缀)
#format是生成的压缩包的文件后缀
#root_dir是你要压缩的文件夹(整个文件夹的内容都被压缩到压缩包中)
14.os删除文件,文件夹
import os import shutil os.remove(path) #删除文件 os.removedirs(path) #删除空文件夹 shutil.rmtree(path) #递归删除文件夹
15.跨域问题
需要先安装模块: pip3 install django-cors-headers 在settings.py文件中增加以下内容 INSTALLED_APPS = [ ... 'corsheaders',#新注册个app(要先安装django-cors-headers) ... ] MIDDLEWARE_CLASSES = ( ... 'corsheaders.middleware.CorsMiddleware',#这个是新加的,一定要在下面这一行的上面 'django.middleware.common.CommonMiddleware', # 这一行原来就有 ... ) #跨域增加忽略(以下内容全是新加的) CORS_ALLOW_CREDENTIALS = True CORS_ORIGIN_ALLOW_ALL = True CORS_ORIGIN_WHITELIST = ('*')#这是白名单,如果有报错就就把这一行注掉 CORS_ALLOW_METHODS = ( #允许的请求方法 'DELETE', 'GET', 'OPTIONS', 'PATCH', 'POST', 'PUT', 'VIEW', ) CORS_ALLOW_HEADERS = (#允许的请求头,全部都写在下面,如果有请求头不在这里就会拦截请求,可以手动进行添加 'XMLHttpRequest', 'X_FILENAME', 'accept-encoding', 'authorization', 'content-type', 'dnt', 'origin', 'user-agent', 'x-csrftoken', 'x-requested-with', 'Pragma', 'token', )
16.Python压缩多个文件成zip
Python接收多个网络文件,将多个二进制文件写入一个zip文件中
from elec_seal import settings url1='https://tester/api/document/original/1301810724183494656'#找三个可以获取到文件的url,
#图片其实也行(百度找三张图片的url放进来也行) url2='https://test.erver/api/document/original/1301810724183494657' url3='https://test/' lst=[url1,url2,url3] headers = { # "Content-Type": settings.CONTENT_TYPE1, "appid": settings.APPID, #自己定义的请求头 # "sign": settings.SIGN, # "time": cur_time } import requests import zipfile zip1=zipfile.ZipFile('C:\\Users\\33101\\Desktop\\456\\wezipppp.zip','w') #第一个参数是你要生成的zip文件放到
#哪里(需要加上生成的zip文件名字和后缀),w是写入的意思 for key,u in enumerate(lst): a=requests.get(u,headers=headers)#发送get请求获取到文件,a.content是固定写法,
#获取到文件的二进制,直接把他写成文件其实就可以看见了 zip1.writestr(f'w{key}e.pdf',a.content,zipfile.ZIP_DEFLATED)#zip1是zipfile.ZipFile实例化的对
#象,writestr是固定方法,这里循环的是多个url, #参数f''就是自己给放到zip压缩包中的每一个文件命名,循环一次命名一个,
#而a.content就是每个url获取到的文件的二进制,最后DEFAULT是固定写法。 zip1.close() #必须关闭对象,否则写不出来zip,他不保存,zip就出不来
17.linux部署Python代码,中文+英文路径报错
from urllib.parse import quote import string path='/wwe/合同.docx' #这样的路径在linux系统下(python3.5)运行报错 #报错UnicodeEncodeError: 'ascii' codec can't encode characters in position 8-20: ordinal not in range(128) #解决方式 new_path = quote(path, safe=string.printable) #这样处理一下path,后面直接调用new_path 即可,不会影响windows下的Python代码