Python requests发送post请求的一些疑点


Posted in Python onMay 20, 2018

前言

在Python爬虫中,使用requests发送请求,访问指定网站,是常见的做法。一般是发送GET请求或者POST请求,对于GET请求没有什么好说的,而发送POST请求,有很多朋友不是很清楚,主要是因为容易混淆 POST提交的方式 。今天在微信交流群里,就有朋友遇到了这种问题,特地讲解一下。

在HTTP协议中,post提交的数据必须放在消息主体中,但是协议中并没有规定必须使用什么编码方式,从而导致了 提交方式 的不同。服务端根据请求头中的 Content-Type 字段来获知请求中的消息主体是用何种方式进行编码,再对消息主体进行解析。具体的编码方式包括如下:

  1. application/x-www-form-urlencoded:以form表单形式提交数据,最常见也是大家最熟悉的
  2.  application/json :以json串提交数据。

下面使用requests来发送上述三种编码的POST请求。

1.提交Form表单

requests提交Form表单,一般存在于网站的登录,用来提交用户名和密码。以http://httpbin.org/post 为例,在requests中,以form表单形式发送post请求,只需要将请求的参数构造成一个字典,然后传给requests.post()的data参数即可。代码如下:

url = 'http://httpbin.org/post'
d = {'key1': 'value1', 'key2': 'value2'}
r = requests.post(url, data=d)
print r.text

输出效果如下:

{
"args":{},
"data":"",
"files":{},
"form":{"key1":"value1","key2":"value2"},
"headers":{"Accept":"*/*","Accept-Encoding":"gzip, deflate",
"Connection":"close",
"Content-Length":"23",
"Content-Type":"application/x-www-form-urlencoded",
"Host":"httpbin.org",
"User-Agent":"python-requests/2.12.3"},
"json":null,
"origin":"113.140.11.122",
"url":http://httpbin.org/post}

httpbin.org网站可以显示你提交请求的内容,大家注意一下输出的"Content-Type":"application/x-www-form-urlencoded",证明这是提交Form的方式。大家在登录一个网站时,可以观察一下Content-Type是什么。

2.提交json串

对于提交json串,主要是用于发送ajax请求中,动态加载数据。以拼多多网站为例,加载商品的方式为ajax,商品的内容在响应中。

Python requests发送post请求的一些疑点

下面把请求头和请求实体列举一下:

Python requests发送post请求的一些疑点 

一些初学者根据请求头写爬虫,就会犯requests的使用错误。

错误写法

import requests
__author__ = 'qiye'
__date__ = '2018/5/19 21:59'

url = "http://jinbao.pinduoduo.com/network/api/common/goodsList"
data ={"pageSize":60,"pageNumber":1,"withCoupon":0,"sortType":0}
headers = {
  'Content-Type':'application/json; charset=UTF-8',
  'Host':'jinbao.pinduoduo.com',
  'Origin':'http://jinbao.pinduoduo.com',
  'Referer':'http://jinbao.pinduoduo.com/',
  'User-Agent':'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Mobile Safari/537.36',
  'Accept': 'application/json, text/javascript, */*; q=0.01',
}
r = requests.post(url=url,data =data,headers=headers)
print(r.text)

打印的内容如下:

{"success":false,"errorCode":4000000,"errorMsg":"System Error","result":null}

返回出错了,这时候百思不得其解,请求头我都保持一致了呀,'Content-Type':'application/json; charset=UTF-8'都加上了,为什么会出错呀?

答案在于,你的请求实体的格式错了,服务端无法解码。

正确写法1

正确代码是把data进行json编码,再发送。代码如下:

r = requests.post(url=url,data =json.dumps(data),headers=headers)

这个时候再看一下打印内容,已经正确返回商品内容了。

{"success":true,"errorCode":1000000,"errorMsg":null,"result":{"total":2271278,"goodsList":[{"goodsId":998422995,"goodsName":"【4液+1器】皎洁电热蚊香液 孕妇宝宝驱蚊儿童婴无味防蚊液体","goodsImageUrl":"http://t11img.yangkeduo.com/images/2018-04-12/0292b5e75053dfa748b9762d3f3e74ef.jpeg","soldQuantity":175,"minGroupPrice":24890,"categoryId":4,"categoryName":"母婴","hasCoupon":true,"couponMinOrderAmount":5000,"couponDiscount":5000,"couponTotalQuantity":5000,"couponRemainQuantity":3940,"couponStartTime":1526572800,"couponEndTime":1527782399,"promotionRate":280},
...

正确写法2

处理将data主动编码为json发送之外,requests还提供了一个json参数,自动使用json方式发送,而且在请求头中也不用显示声明'Content-Type':'application/json; charset=UTF-8'。完整代码如下:

import requests

__author__ = 'qiye'
__date__ = '2018/5/19 21:59'

url = "http://jinbao.pinduoduo.com/network/api/common/goodsList"
data ={"pageSize":60,"pageNumber":1,"withCoupon":0,"sortType":0}
headers = {
  'Host':'jinbao.pinduoduo.com',
  'Origin':'http://jinbao.pinduoduo.com',
  'Referer':'http://jinbao.pinduoduo.com/',
  'User-Agent':'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Mobile Safari/537.36',
}
r = requests.post(url=url,json =data,headers=headers)
print(r.text)

3.上传文件

上传文件在爬虫中使用的很少,不过还是使用requests讲解一下使用方式。Content-Type类型为multipart/form-data,以multipart形式发送post请求,只需将一文件传给requests.post()的files参数即可。还是以http://httpbin.org/post 为例,代码如下:

url = 'http://httpbin.org/post'
files = {'file': open('upload.txt', 'rb')}
r = requests.post(url, files=files)
print(r.text)

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python操作列表的常用方法分享
Feb 13 Python
详解Python的Django框架中的templates设置
May 11 Python
python实现根据主机名字获得所有ip地址的方法
Jun 28 Python
解决Python二维数组赋值问题
Nov 28 Python
解决Django no such table: django_session的问题
Apr 07 Python
python shapely.geometry.polygon任意两个四边形的IOU计算实例
Apr 12 Python
用python实现名片管理系统
Jun 18 Python
Python实现定时监测网站运行状态的示例代码
Sep 30 Python
pytorch加载语音类自定义数据集的方法教程
Nov 10 Python
如何利用Matlab制作一款真正的拼图小游戏
May 11 Python
Python实现天气查询软件
Jun 07 Python
Python爬虫网络请求之代理服务器和动态Cookies
Apr 12 Python
python中virtualenvwrapper安装与使用
May 20 #Python
django静态文件加载的方法
May 20 #Python
django中静态文件配置static的方法
May 20 #Python
Python中跳台阶、变态跳台阶与矩形覆盖问题的解决方法
May 19 #Python
Python利用公共键如何对字典列表进行排序详解
May 19 #Python
Python中一些不为人知的基础技巧总结
May 19 #Python
Python + selenium自动化环境搭建的完整步骤
May 19 #Python
You might like
php获取文件大小的方法
2014/02/26 PHP
php+html5使用FormData对象提交表单及上传图片的方法
2015/02/11 PHP
PHP+apc+ajax实现的ajax_upload上传进度条代码
2016/01/25 PHP
php批量转换文件夹下所有文件编码的函数类
2017/08/06 PHP
javascript的字符串按引用复制和传递,按值来比较介绍与应用
2012/12/28 Javascript
ZeroClipboard插件实现多浏览器复制功能(支持firefox、chrome、ie6)
2014/08/30 Javascript
谷歌浏览器不支持showModalDialog模态对话框的解决方法
2014/09/22 Javascript
JavaScript中的关联数组问题
2015/03/04 Javascript
jquery ajax 如何向jsp提交表单数据
2015/08/23 Javascript
基于JavaScript创建动态Dom
2015/12/08 Javascript
理解javascript中的MVC模式
2016/01/28 Javascript
js操作浏览器的参数方法
2017/01/21 Javascript
JavaScript的for循环中嵌套一个点击事件的问题解决
2017/03/03 Javascript
jQuery DOM节点的遍历方法小结
2017/08/15 jQuery
解决vue点击控制单个样式的问题
2018/09/05 Javascript
jQuery实现评论模块
2020/08/19 jQuery
[35:44]2014 DOTA2华西杯精英邀请赛 5 24 iG VS VG
2014/05/26 DOTA
跟老齐学Python之让人欢喜让人忧的迭代
2014/10/02 Python
Django 视图层(view)的使用
2018/11/09 Python
Django视图、传参和forms验证操作
2020/07/15 Python
Html5 web本地存储实例详解
2016/07/28 HTML / CSS
前端实现打印图像功能
2019/08/27 HTML / CSS
美国高级音响品牌:Master&Dynamic
2018/07/05 全球购物
HEMA英国:荷兰原创设计
2018/08/28 全球购物
职称评定自我鉴定
2014/03/18 职场文书
师德师风承诺书
2014/05/23 职场文书
同志主要表现材料
2014/08/21 职场文书
2014年度党员自我评议
2014/09/13 职场文书
学习保证书怎么写
2015/02/26 职场文书
基石观后感
2015/06/12 职场文书
基层工作经历证明
2015/06/19 职场文书
认识实习感想
2015/08/10 职场文书
不会写演讲稿,快来看看这篇文章!
2019/08/06 职场文书
多属性、多分类MySQL模式设计
2021/04/05 MySQL
Java 超详细讲解ThreadLocal类的使用
2022/04/07 Java/Android
mysql5.5中文乱码问题解决的有用方法
2022/05/30 MySQL