这里主要是解决multipart/form-data这种格式的文件上传,基本现在http协议上传文件基本上都是通过这种格式上传
1 思路
一般情况下,如果我们往一个地址上传文件,则必须要登陆,登陆成功后,拿到cookies,然后在上传文件的请求携带这个cookies。
然后我们就需要通过浏览器在网站上传文件,这个时候我们需要打开浏览器的开发者工具或者fiddler,然后按照抓到包组装我们的上传文件的post请求
大家把握一个原则就是:在post请求中,用files参数来接受文件对象相关的参数,通过data/json参数接受post请求体的其他参数即可。
2 实现
2.1 登陆网站
使用requests.session()对象登陆网站,这里主要为了方便,下次直接用这个对象发送post上传文件的请求即可,不需要我们在请求体中添加cookies
查找登录的URL
查找请求头
查找登录参数
代码如下:
import requests s = requests.session() res1 = s.post( url=\"http://127.0.0.1:5000/login\", headers={ \'Host\': \'127.0.0.1:5000\', \'Connection\': \'keep-alive\', \'Content-Length\': \'28\', \'Cache-Control\': \'max-age=0\', \'sec-ch-ua\': \'\" Not A;Brand\";v=\"99\", \"Chromium\";v=\"90\", \"Google Chrome\";v=\"90\"\', \'sec-ch-ua-mobile\': \'?0\', \'Upgrade-Insecure-Requests\': \'1\', \'Origin\': \'http://127.0.0.1:5000\', \'Content-Type\': \'application/x-www-form-urlencoded\', \'User-Agent\': \'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36\', \'Accept\': \'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9\', \'Sec-Fetch-Site\': \'same-origin\', \'Sec-Fetch-Mode\': \'navigate\', \'Sec-Fetch-User\': \'?1\', \'Sec-Fetch-Dest\': \'document\', \'Referer\': \'http://127.0.0.1:5000/login\', \'Accept-Encoding\': \'gzip, deflate, br\', \'Accept-Language\': \'zh-CN,zh;q=0.9\' }, data={ \"account\": \"admin\", \"password\": \"admin\" } )
2.2 手动上传文件,分析http请求的参数
由于谷歌浏览器无法查看上传文件时http请求的参数,故使用fiddler来进行抓包
抓包情况如下:
说明:
上图中第一个红框中参数后面全是乱码,这里就是我们上传的文件二进制格式的表现,这里的数据就是通过files参数接收
第二个红框中name的值就是k,比如cid就是k值,下一行的值 7 就是v,这里的参数就是要通过data参数接收
上面是http请求的raw格式,我们一般会看webForms格式的http请求
分
析完成后,可以看下代码:
res2 = s.post( url=\"http://127.0.0.1:5000/upload\", headers={ \'Host\': \'127.0.0.1:5000\', \'Connection\': \'keep-alive\', \'Content-Length\': \'28\', \'Cache-Control\': \'max-age=0\', \'sec-ch-ua\': \'\" Not A;Brand\";v=\"99\", \"Chromium\";v=\"90\", \"Google Chrome\";v=\"90\"\', \'sec-ch-ua-mobile\': \'?0\', \'Upgrade-Insecure-Requests\': \'1\', \'Origin\': \'http://127.0.0.1:5000\', # \'Content-Type\': \'application/x-www-form-urlencoded\', \'User-Agent\': \'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36\', \'Accept\': \'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9\', \'Sec-Fetch-Site\': \'same-origin\', \'Sec-Fetch-Mode\': \'navigate\', \'Sec-Fetch-User\': \'?1\', \'Sec-Fetch-Dest\': \'document\', \'Referer\': \'http://127.0.0.1:5000/login\', \'Accept-Encoding\': \'gzip, deflate, br\', \'Accept-Language\': \'zh-CN,zh;q=0.9\' }, files={ \"filename_list\": open(\"./test\", \"rb\"), \"Content-Type\": \"text/plain\", \"Content-Disposition\": \"form-data\", \"filename\": \"test\" }, data={ \"cid\": \"7\" } )
3 三个关键点
3.1 data参数
注意看k值和抓包中的对比
3.2 files参数
这里很关键,这里就是我们上传的文件对象了。filename_list 这个参数就代表文件文件对象,filename 这个值一般就是上传后的文件的名称(可以不写)
3.3 content-type参数
如果我们通过form-data的方式上传文件,我们组装post请求的时候,headers这个参数中一定不能要包括这个值,由requests库帮添加这个元素
如果我们自作聪明,会导致上传失败的,这里非常重要!!!
大家可以看到,我在代码中没有传递content-type这个参数,但是抓包是有这个参数的,所以这个参数我们一定不能加
实际抓包有这个参数
实际上传抓包验证即可,和浏览器上传略有不同,但是不影响上传
暂无评论内容