HTTP请求和Requests

HTTP请求方式:get和post

get和post是HTTP的两个常用方法。 
什么是HTTP? 
超文本传输协议(HyperText Transfer Protocol – HTTP)是一个设计来使客户端和服务器顺利进行通讯的协议。 
HTTP在客户端和服务器之间以request-response protocol(请求-回复协议)工作。

  • get - 从指定的服务器中获取数据
  • post - 提交数据给指定的服务器处理

get请求

get是获取信息,而不是修改信息,类似数据库查询功能一样,数据不会被修改。 
get请求的参数会跟在url后进行传递,请求的数据会附在URL之后,以?分割URL和传输数据,参数之间以&相连,%XX中的XX为该符号以16进制表示的ASCII,如果数据是英文字母/数字,原样发送,如果是空格,转换为+,如果是中文/其他字符,则直接把字符串用BASE64加密。 
get传输的数据有大小限制,因为get是通过URL提交数据,那么get可提交的数据量就跟URL的长度有直接关系了,不同的浏览器对URL的长度的限制是不同的。 
get请求的数据会被浏览器缓存起来,用户名和密码将明文出现在URL上,其他人可以查到历史浏览记录,数据不太安全。 
在服务器端,用Request.QueryString来获取get方式提交来的数据 
表单也可以通过get方法发送,下面是个例子:

GET /foo.php?first_name=John&last_name=Doe&action=Submit HTTP/1.1

你可以将表单输入通过附加进查询字符串的方式发送至服务器。

post请求

post请求发送数据至服务器,数据放置在HTML Header内提交,post没有限制提交的数据。 
尽管你可以通过get方法将数据附加到url中传送给服务器,但在很多情况下使用post发送数据给服务器更加合适。通过get发送大量数据是不现实的,它有一定的局限性。 
post比get安全,当数据是中文或者不敏感的数据,则用get,因为使用get,参数会显示在地址,对于敏感数据和不是中文字符的数据,则用post。 
post可能修改服务器上的资源,在服务器端,用post方式提交的数据只能用Request.Form来获取。 
可以把上面的例子改造成post请求的方式:

POST /foo.php HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 (.NET CLR 3.5.30729)
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Referer: http://localhost/test.php
Content-Type: application/x-www-form-urlencoded
Content-Length: 43
first_name=John&last_name=Doe&action=Submit

 

这里有三个需要注意的地方:

  1. 第一行的路径已经变为简单的 /foo.php , 已经没了查询字符串。
  2. 新增了 Content-Type 和 Content-Lenght 头部,它提供了发送信息的相关信息。
  3. 所有数据都在headers之后,以查询字符串的形式被发送。

requests库

Python的requests库提供了http所有的基本请求方式。例如

r = requests.post("http://httpbin.org/post")
r = requests.put("http://httpbin.org/put")
r = requests.delete("http://httpbin.org/delete")
r = requests.head("http://httpbin.org/get")
r = requests.options("http://httpbin.org/get")

get请求

r = requests.get("http://httpbin.org/get")

如果想要加参数,可以利用 params 参数:

import requests

payload = {'key1': 'value1', 'key2': 'value2'}
r = requests.get("http://httpbin.org/get", params=payload)
print r.url

运行结果:

http://httpbin.org/get?key2=value2&key1=value1

如果想添加 headers,可以传 headers 参数以增加请求头中的headers信息:

import requests

payload = {'key1': 'value1', 'key2': 'value2'}
headers = {'content-type': 'application/json'}
r = requests.get("http://httpbin.org/get", params=payload, headers=headers)
print r.url

post请求

post 请求一般需要一些参数。最基本的传参方法是利用 data 这个参数。

import requests

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

运行结果:

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

上传文件

如果想要上传文件,那么直接用 file 参数即可,例如新建一个 a.txt 的文件,内容写上 Hello World!

import requests

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

可以看到运行结果如下:

{
  "args": {}, 
  "data": "", 
  "files": {
    "file": "Hello World!"
  }, 
  "form": {}, 
  "headers": {
    "Accept": "*/*", 
    "Accept-Encoding": "gzip, deflate", 
    "Content-Length": "156", 
    "Content-Type": "multipart/form-data; boundary=7d8eb5ff99a04c11bb3e862ce78d7000", 
    "Host": "httpbin.org", 
    "User-Agent": "python-requests/2.9.1"
  }, 
  "json": null, 
  "url": "http://httpbin.org/post"
}

 

 

流式传输文件

requests 支持流式上传,这允许你发送大的数据流或文件而无需先把它们读入内存。要使用流式上传,仅需为你的请求体提供一个类文件对象即可:

with open('massive-body') as f:
    requests.post('http://some.url/streamed', data=f)

cookies

Cookies是一种能够让网站服务器把少量数据储存到客户端的硬盘或内存,或是从客户端的硬盘读取数据的一种技术。Cookies是当你浏览某网站时,由Web服务器置于你硬盘上的一个非常小的文本文件,它可以记录你的用户ID、密码、浏览过的网页、停留的时间等信息。当你再次来到该网站时,网站通过读取Cookies,得知你的相关信息,就可以做出相应的动作,如在页面显示欢迎你的标语,或者让你不用输入ID、密码就直接登录等等。 
如果一个响应中包含了cookie,那么我们可以利用 cookies 变量来拿到:

import requests

url = 'http://example.com'
r = requests.get(url)
print r.cookies
print r.cookies['example_cookie_name']

另外可以利用 cookies 变量来向服务器发送 cookies 信息:

import requests

url = 'http://httpbin.org/cookies'
cookies = dict(cookies_are='working')
r = requests.get(url, cookies=cookies)
print r.text

cookies和session的区别

Cookie和Session有很多相似的地方,都是用来临时存储来访者信息,两者的根本区别是Cookie对象将信息存放在客户端,Session对象存放在服务器端;从生存期上讲,Cookie可以长期保存,而Session的生存期仅仅到会话结束
Cookie保存在客户端,用户可以看到Cookie文件,并能对Cookie文件进行类似修改、删除的操作,Cookie数据的安全性很难得到保障;而Session数据保存在服务器端,有较好的安全性,若和数据库配合使用,可以使Session数据长期保持,并得到很好的安全性。

timeout 请求超时

可以利用 timeout 变量来配置最大请求时间:

requests.get('http://github.com', timeout=0.001)

注:timeout 仅对连接过程有效,与响应体的下载无关。

会话对象

在以上的请求中,每次请求都相当于发起了一次新的请求,相当于我们对每个请求都用了不同的浏览器单独打开的效果。它并不是指的一个会话,即使请求的是同一个网址。比如:

import requests

requests.get('http://httpbin.org/cookies/set/sessioncookie/123456789')
r = requests.get("http://httpbin.org/cookies")
print(r.text)

结果是:

{
  "cookies": {}
}

很明显,这不在一个会话中,无法获取 cookies,那么在一些站点中,我们需要保持一个持久的会话怎么办呢?就像用一个浏览器逛淘宝一样,在不同的选项卡之间跳转,这样其实就是建立了一个长久会话。方法如下:

import requests

s = requests.Session()
s.get('http://httpbin.org/cookies/set/sessioncookie/123456789')
r = s.get("http://httpbin.org/cookies")
print(r.text)

在这里我们请求了两次,一次是设置 cookies,一次是获得 cookies,运行结果:

{
  "cookies": {
    "sessioncookie": "123456789"
  }
}

发现可以成功获取到 cookies 了,这就是建立一个会话的作用。 
既然会话是一个全局变量,那么我们可以用来全局的配置了。

import requests

s = requests.Session()
s.headers.update({'x-test': 'true'})
r = s.get('http://httpbin.org/headers', headers={'x-test2': 'true'})
print r.text

通过 s.headers.update 方法设置了 headers 的变量。然后我们又在请求中设置了一个 headers,那么会出现什么结果? 
很简单,两个变量都传送过去了。

运行结果:

{
  "headers": {
    "Accept": "*/*", 
    "Accept-Encoding": "gzip, deflate", 
    "Host": "httpbin.org", 
    "User-Agent": "python-requests/2.9.1", 
    "X-Test": "true", 
    "X-Test2": "true"
  }
}

如果get方法传的headers 同样也是 x-test 呢?

r = s.get('http://httpbin.org/headers', headers={'x-test': 'true'})

它会覆盖掉全局的配置:

{
  "headers": {
    "Accept": "*/*", 
    "Accept-Encoding": "gzip, deflate", 
    "Host": "httpbin.org", 
    "User-Agent": "python-requests/2.9.1", 
    "X-Test": "true"
  }
}

如果不想要全局配置中的一个变量了呢?很简单,设置为 None 即可:

r = s.get('http://httpbin.org/headers', headers={'x-test': None})

运行结果:

{
  "headers": {
    "Accept": "*/*", 
    "Accept-Encoding": "gzip, deflate", 
    "Host": "httpbin.org", 
    "User-Agent": "python-requests/2.9.1"
  }
}

SSL证书验证

Requests可以为HTTPS请求验证SSL证书,就像web浏览器一样。要想检查某个主机的SSL证书,你可以使用 verify 参数:

import requests

r = requests.get('https://github.com', verify=True)
print r.text

如果我们想跳过证书验证,把 verify 设置为 False 即可:

import requests

r = requests.get('https://kyfw.12306.cn/otn/', verify=False)
print r.text

发现就可以正常请求了。在默认情况下 verify 是 True,所以如果需要的话,需要手动设置下这个变量。

代理

如果需要使用代理,你可以通过为任意请求方法提供 proxies 参数来配置单个请求:

import requests

proxies = { "https": "http://41.118.132.69:4433" }
r = requests.post("http://httpbin.org/post",proxies=proxies)
print r.text

响应内容

普通响应内容

我们能读取服务器响应的内容。以Github时间线为例:

import requests
r = requests.get('https://github.com/timeline.json')
r.text
>>>'[{"repository":{"open_issues":0,"url":"https://github.com/...

Requests会自动解码来自服务器的内容。大多数unicode字符集都能被无缝地解码。 
请求发出后,Requests会基于HTTP头部对响应的编码作出有根据的推测。当你访问r.text 之时,Requests会使用其推测的文本编码。你可以找出Requests使用了什么编码,并且能够使用 r.encoding 属性来改变它:

r.encoding
>>>'utf-8'
#改变encoding属性
r.encoding = 'ISO-8859-1'

如果你改变了编码,每当你访问 r.text ,Request都将会使用 r.encoding 的新值。 
在你需要的情况下,Requests也可以使用定制的编码。如果你创建了自己的编码,并使用codecs 模块进行注册,你就可以轻松地使用这个解码器名称作为 r.encoding 的值, 然后由Requests来为你处理编码。

二进制响应内容

你也能以字节的方式访问请求响应体,对于非文本请求:

>>> r.content
b'[{"repository":{"open_issues":0,"url":"https://github.com/...

Requests会自动为你解码 gzip 和 deflate 传输编码的响应数据。 
例如,以请求返回的二进制数据创建一张图片,你可以使用如下代码:

from PIL import Image
from StringIO import StringIO
i = Image.open(StringIO(r.content))

JSON响应内容

Requests中也有一个内置的JSON解码器,助你处理JSON数据:

import requests
r = requests.get('https://github.com/timeline.json')
r.json()
>>>[{u'repository': {u'open_issues': 0, u'url': 'https://github.com/...

如果JSON解码失败, r.json 就会抛出一个异常。

原始响应内容

你可能想获取来自服务器的原始套接字响应,那么你可以访问 r.raw 。 如果你确实想这么干,那请你确保在初始请求中设置了 stream=True 。实例:

r = requests.get('https://github.com/timeline.json', stream=True)
r.raw
>>> <requests.packages.urllib3.response.HTTPResponse object at 0x101194810>
>>> r.raw.read(10)
'\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x03'
posted @ 2017-12-04 18:38  吃柚子的小白  阅读(258)  评论(0)    收藏  举报