网络爬虫-使用requests上传multipart/form-data格式文件

由于以前没有使用requests上传过文件,所以今天在使用它上传文件的时候遇见了一个坑,接下来我们就来一层一层解析这个坑

科大讯飞官网上传音频文件为例

首先是喜闻乐见地打开Fiddler进行抓包操作,流程也很简单,很快就抓下来了上传文件的这个包,见下图

在这里插入图片描述

然后就进入了懵逼模式,content-type里面这个boundary是啥,以前咋没见过呢,还有data里面的这些个东西又是啥,还来乱码了,奇怪了奇怪了,于是去翻阅了资料。

根据http/1.1 rfc 2616的协议规定,我们的请求方式只有OPTIONS、GET、HEAD、POST、PUT、DELETE、TRACE等,那为为何我们还会有multipart/form-data请求之说呢?这就要从头来说了。

http协议规定以ASCII码传输,建立在tcp,ip协议智商的引用规范,规范内容把http请求分成3个部分,状态行,请求头,请求体。所有的方法,实现都是围绕如何使用和组织这三部分来完成了,万变不离其宗,http的知识大家可以问度娘。

既然上面请求方式里面没有multipart/form-data那这个请求又是怎么回事呢,其实是一回事,multipart/form-data也是在post基础上演变而来的,具体如下:

1.multipart/form-data的基础方式是post,也就是说通过post组合方式来实现的。
2.multipart/form-data于post方法的不同之处在于请求头和请求体。
3.multipart/form-data的请求头必须包含一个特殊的头信息:Content-Type,其值也必须为multipart/form-data,同时还需要规定一个内容分割用于分割请求提中多个post的内容,如文件内容和文本内容是需要分隔开来的,不然接收方就无法解析和还原这个文件了,具体的头信息如下:

Content-Type: multipart/form-data; boundary=${bound}

参考 什么是multipart/form-data请求

然后美滋滋地直接用requests去上传了一波文件

import requests
 
url = 'https://www.iflyrec.com/XFTJService/web/audio/upload?folder=1416861992900653'
files = {'file': open('video.wav', 'rb')}
 
r = requests.post(url, files=files)
print(r.text)

好的 然后毫无疑问地报错

在这里插入图片描述

话说这不应该啊 不是在我想象中这样就应该OK了么 于是硬着头皮再面向百度了一波–

具体参考的这篇博文 使用python的requests 发送multipart/form-data 请求

然后参考了我抓的包,发现multipart/form-data 请求在requests里面其实是有实例的,使用元组形式上传files,于是完成了以下代码

import requests

headers = {
    "Host": "www.iflyrec.com",
    "Connection": "keep-alive",
    "Content-Length": "137110",
    "Origin": "https://www.iflyrec.com",
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.26 Safari/537.36 Core/1.63.6776.400 QQBrowser/10.3.2601.400",
    "Accept": "*/*",
    "Referer": "https://www.iflyrec.com/html/addArtificialOrder.html",
    "Accept-Encoding": "gzip, deflate, br",
    "Accept-Language": "zh-CN,zh;q=0.9",
    # "Content-Type": "multipart/form-data; boundary=----WebKitFormBoundaryZjPRjN0wAzGytw34",
    "Cookie": "login_err=0; from=baidu; keywords=%25e8%25ae%25af%25e9%25a3%259e+%25e8%25af%25ad%25e9%259f%25b3%25e8%25af%2586%25e5%2588%25ab; Hm_lvt_aee4c3bed3d9924f2f184904ecb37065=1542615755; Hm_lvt_c711619f2461980a3dbceed5874b0c6a=1542615755; storage=QsIwv8WBIrqRiBa62wvKbo8oswgQSz4Wr4bjQk8jm+scRW7Z6rVZZv1WwElHU0BN+ZAmvzlXvxc2gaeHLi2yHQ==; ec_im_local_status=0; CUSTOM_INVITE_CONTENT=; ec_invite_state=0; Hm_lpvt_aee4c3bed3d9924f2f184904ecb37065=1542615766; ec_im_tab_num=1; ec_invite_state_time=1542615765582; Hm_lpvt_c711619f2461980a3dbceed5874b0c6a=1542615766"
}

# files = {'file': open('333.wav', 'rb')}

files = {'id': (None, 'WU_FILE_0'), 
         'name':  (None, '333.wav'), 
         'type': (None, 'audio/wav'),
         'lastModifiedDate': (None, 'Tue Aug 21 2018 17:22:12 GMT+0800 (中国标准时间)'),
         'size': (None,'136380'), 
         'file': ('333.wav', open('333.wav', 'rb'), 'audio/wav')} # 

r = requests.post('https://www.iflyrec.com/XFTJService/web/audio/upload?folder=1416861992900653', headers=headers, files=files)

print(r.text)
print(r.headers)
print(r.status_code)

运行成功图如下

在这里插入图片描述

需要注意的是,我将headers请求头里面的content-type属性注释了,如果加上了,则会报错,然后我把这个模拟请求抓包下来看了看,他自动加上了Content-Type: multipart/form-data; boundary=${bound},所以这个boundary应该是上传文件的标识,上传文件的时候content-type会有一个默认值,我们不去指定,也就没问题了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章