从Request库理解HTTP消息

背景

requests库官方文档地址

http://docs.python-requests.org/en/master/

作者博客

http://www.kennethreitz.org

github地址

https://github.com/requests/requests

环境搭建

基本环境

python、pip

注:pip freeze -- 查看当前已经安装的pip包

安装其他必须软件

virtualenv

作用

初始化一个空环境(也可以不初始化)

使用 pip / easy_install 是为了能够良好的管理起来你的包,这类似deb之流。

之所以需要用 VirtualEnv,关键的目的是把你当前开发/生产的 Python 环境和其他的 Python 环境隔离开来。例如你的 Proj1 需要用到 LibA 的版本1.0,而你的 Proj2 需要用到LibA的2.0,如果不加以区分,那么就会可能造成冲突。

在 VirtualEnv 中,每一个 VirtualEnv 的环境,都是隔离的,需要的包等都是单独的,你可以认为这是一个沙盒(SandBox),这时候 pip / easy_install 等运行时候依赖的 Python 也是隔离的,既 $VENV_HOME/bin/python 而非 /usr/bin/python。

一般的,yum / apt 安装的会安装在系统的路径中,针对 Python, 则是 Global 的 PYTHONPATH。很难做到隔离。

而从源代码安装的,一般的会根据你的运行时 Python 命令进行隔离。也就是如果你启用了 VirtualEnv (source $VENV_HOME/bin/activate)后,从源码安装的也会在这个 venv 下。

安装virtualenv

pip install virtualenv

使用virtualenv初始化当前文件夹

virtualenv .env

激活当前文件夹的virtualenv

windows:.env/Script/activate

linux:source .env/bin/activate

注:deactivate可以退出虚拟环境

requests库

pip install requests

httpbin.org

测试用,由于http://httpbin.org/服务器在美国,所以可以在本地搭建个类似环境测试

pip install gunicorn httpbin

gunicorn httpbin:app

注:windows上无法安装gunicorn

HTTP协议

概念

HyperText Transfer Protocol超文本传输协议

The Hypertext Transfer Protocol is a stateless(无状态的), application-level protocol(应用层协议) for distributed(分布式), collaborative(协作式), hepertext information system(超文本信息系统)

显示一次http通信的整个过程

curl -v https://www.imooc.com/ >/data01/yc_files/http_contact_demo.log

显示分析

urllib

概念

python原生网络库

urllib、urllib2、urllib3的关系

urllib和urllib2是独立的模块,并没有直接的关系,两者相互结合实现复杂的功能

urllib和urllib2在python2中才可以使用

requests库中使用了urllib3(多次请求重复使用一个socket)

urllib和request区别

urlib_demo

# -*- coding:utf-8 -*-
import urllib2
import urllib

URL_simple="http://httpbin.org/ip"
URL_get="http://httpbin.org/get"

def urllib_simple_use():
    response = urllib2.urlopen(URL_simple)
    print( ‘>>>>Response Headers:‘)
    print( response.info())
    print( ‘>>>>Response Status Code:‘)
    print( response.getcode())
    print( ‘>>>>Response :‘)
    print( ‘‘.join([line for line in response]))

def urllib_params_use():
    params = urllib.urlencode({‘param1‘:‘hello‘,‘param2‘:‘world‘})
    response = urllib2.urlopen(‘?‘.join([URL_get,params]))
    print( ‘>>>>Response Headers:‘)
    print( response.info())
    print( ‘>>>>Response Status Code:‘)
    print( response.getcode())
    print( ‘>>>>Response :‘)
    print( ‘‘.join([line for line in response]))

if __name__ == ‘__main__‘:
    print( ‘>>>>Urllib Simple Use:‘)
    urllib_simple_use()
    print( ‘>>>>Urllib Params Use:‘)
    urllib_params_use()

urllib simple demo

requests_demo

quick start: http://docs.python-requests.org/en/latest/user/quickstart/

# -*- coding:utf-8 -*-
import requests

URL_simple="http://httpbin.org/ip"
URL_get="http://httpbin.org/get"

def requests_simple_use():
    response = requests.get(URL_simple)
    print( ‘>>>>Request Headers:‘)
    print( response.request.headers)
    print( ‘>>>>Request body:‘)
    print( response.request.body)
    print( ‘>>>>Response url:‘)
    print( response.url)
    print( ‘>>>>Response Headers:‘)
    print( response.headers)
    print( ‘>>>>Response Status Code:‘)
    print( response.status_code)
    print( ‘>>>>Response Status Code Reason:‘)
    print( response.reason)
    print( ‘>>>>Response :‘)
    print( response.text)
    print( response.json())

def requests_params_use():
    params = {‘param1‘:‘hello‘,‘param2‘:‘world‘}
    response = requests.get(URL_get,params=params)
    print( ‘>>>>Request Headers:‘)
    print( response.request.headers)
    print( ‘>>>>Request body:‘)
    print( response.request.body)
    print( ‘>>>>Response url:‘)
    print( response.url)
    print( ‘>>>>Response Headers:‘)
    print( response.headers)
    print( ‘>>>>Response Status Code:‘)
    print( response.status_code)
    print( ‘>>>>Response Status Code Reason:‘)
    print( response.reason)
    print( ‘>>>>Response :‘)
    print( response.text)
    print( response.json())

if __name__ == ‘__main__‘:
    print( ‘>>>>Requests Simple Use:‘)
    requests_simple_use()
    print( ‘>>>>Requests Params Use:‘)
    requests_params_use()

requests simple demo

扩展

RFC7230 -> RFC7235阅读

https://tools.ietf.org/html/

发送请求

import requests
import json
from requests.exceptions import RequestException 

ROOT_URL=‘https://api.github.com‘

def better_print(src_json):
    ‘‘‘
        格式化打印json
    ‘‘‘
    return json.dumps(src_json,indent=4)

def get_simple_use():
    ‘‘‘
        API获得指定用户的用户信息
    ‘‘‘
    response = requests.get(‘/‘.join([ROOT_URL,‘users/wahaha‘]))
    print(‘>>>>Response text:‘)
    print(better_print(response.json()))

def get_auth_use():
    ‘‘‘
        API获得指定用户的email信息--明文,不建议方法。
        当然,123456是错误的密码。
        建议通过简易oauth认证。
    ‘‘‘
    # response = requests.get(‘/‘.join([ROOT_URL,‘user/emails‘]))
    response = requests.get(‘/‘.join([ROOT_URL,‘user/emails‘]),auth=(‘wahaha‘,‘123456‘))
    print(‘>>>>Response text:‘)
    print(better_print(response.json()))

def get_params_use():
    ‘‘‘
        get + 带参URL 获得11号之后的user信息
    ‘‘‘
    response = requests.get(‘/‘.join([ROOT_URL,‘users‘]),params={‘since‘:11})
    print( ‘>>>>Request Headers:‘)
    print( response.request.headers)
    print( ‘>>>>Request body:‘)
    print( response.request.body)
    print( ‘>>>>Response url:‘)
    print( response.url)
    print(‘>>>>Response text:‘)
    print(better_print(response.json()))

def patch_json_use():
    ‘‘‘
        json参数 + patch 修改用户邮箱
    ‘‘‘
    response = requests.patch(‘/‘.join([ROOT_URL,‘user‘]),auth=(‘wahaha‘,‘123456‘),json={‘name‘:‘test_name‘,‘email‘:‘[email protected]‘})
    print( ‘>>>>Request Headers:‘)
    print( response.request.headers)
    print( ‘>>>>Request body:‘)
    print( response.request.body)
    print( ‘>>>>Response url:‘)
    print( response.url)
    print(‘>>>>Response text:‘)
    print(better_print(response.json()))

def request_exception_use():
    ‘‘‘
        设定超时时间 + 异常处理
        timeout = x 握手+发送response超时时间-x
        timeout = ( x, y) 握手超时时间-x, 发送response超时时间-y
    ‘‘‘
    try:
        response = requests.get(‘/‘.join([ROOT_URL,‘users‘]),timeout=(0.1,0.2),params={‘since‘:11})
    except RequestException as e:
        print(e)
    else:
        print( ‘>>>>Request Headers:‘)
        print( response.request.headers)
        print( ‘>>>>Request body:‘)
        print( response.request.body)
        print( ‘>>>>Response url:‘)
        print( response.url)
        print(‘>>>>Response text:‘)
        print(better_print(response.json()))

def my_request_use():
    ‘‘‘
        简单模拟requests库底层实现发送requset方法
    ‘‘‘
    # 导库
    from requests import Request,Session
    # 初始化session
    my_session = Session()
    # 初始化headers
    my_headers = {‘User-Agent‘:‘fake1.1.1‘}
    # 初始化request
    my_request = Request(‘GET‘,‘/‘.join([ROOT_URL,‘users‘]),headers=my_headers, params={‘since‘:‘11‘})
    # 准备request
    my_prepared_request = my_request.prepare()
    # 发送request,并用response接受
    my_response = my_session.send(my_prepared_request,timeout=(3,3))
    print( ‘>>>>Request Headers:‘)
    print( json.dumps(dict(my_response.request.headers),indent=4))
    print( ‘>>>>Request body:‘)
    print( my_response.request.body)
    print( ‘>>>>Response url:‘)
    print( my_response.url)
    print( ‘>>>>Response Headers:‘)
    print( json.dumps(dict(my_response.headers),indent=4))
    print( ‘>>>>Response Status Code:‘)
    print( my_response.status_code)
    print( ‘>>>>Response Status Code Reason:‘)
    print( my_response.reason)
    # print( ‘>>>>Response :‘)
    # print(better_print(my_response.json()))

def hook_function(response, *args, **kw):
    print (‘回调函数>>>‘,response.headers[‘Content-Type‘])

def event_hook_use():
    ‘‘‘
        事件钩子,即回调函数,指定获得response时候调用的函数
    ‘‘‘
    response = requests.get(‘http://www.baidu.com‘,hooks={‘response‘:hook_function})

if __name__=="__main__":
    # get_simple_use()
    # get_auth_use()
    # get_params_use()
    # patch_json_use()
    # request_exception_use()
    # my_request_use()
    event_hook_use()

requests库使用demo

参数类型

不同网站接口所对应的发送请求所需的参数类型不同

https://developer.github.com/v3/#parameters

1.URL参数

https://xxx/xx?a=1&b=2&c=3

request库中使用requests.get(url, params={‘a‘:‘1‘,‘b‘:‘2‘,‘c‘:‘3‘})

优势:跳转方便,速度快

劣势:明文,长度有限制

2.表单参数提交

Content-Type: application/x-www-form-urlencoded

request库中使用requests.post(url, data={‘a‘:‘1‘,‘b‘:‘2‘,‘c‘:‘3‘})

3.json参数提交

Content-Type: application/json

request库中使用request.post(url, json={‘a‘:‘1‘,‘b‘:‘2‘,‘c‘:‘3‘})

举例网站

https://developer.github.com

使用参考:https://developer.github.com/v3/guides/getting-started/

请求方法

GET -- 查看资源

POST -- 增加资源

PATCH -- 修改资源

PUT -- 修改资源(比PATCH修改的力度大)

DELETE -- 删除资源

HEAD -- 查看响应头

OPTIONS -- 查看可用请求方法

异常处理

requests库中显示引发的所有异常都继承自requests.exceptions.RequestException,所以直接捕获该异常即可。

自定义request

[email protected]:requests/requests.git

通过阅读request源码,了解Session(proxy,timeout,verify)、PreparedRequest(body,headers,auth)、Response(text,json...)

处理响应

响应基本API

响应的附加信息

status_code     响应码     E:\yc_study\python\request\request\HTTP状态码.html

reason      响应码解释

headers   响应头

url    该响应是从哪个url发来的

history      重定向的历史信息

elapsed    接口调用时长

request    该响应对应的request

响应的主体内容

encoding  主体内容的编码格式

content    主体内容,str类型

text  主体内容,unicode类型

json  主体内容,json类型

raw  流模式下,返回一个urllib3.response.HTTPResponse类型的对象,可以分块取出数据

>>> r = requests.get(‘https://api.github.com/events‘, 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‘

iter_content    流模式下,返回字节码,但会自动解码,可以分块取出数据

with open(filename, ‘wb‘) as fd:

    for chunk in r.iter_content(chunk_size=128):

        fd.write(chunk)

注1:iter_content和raw的区别

使用Response.iter_content会处理很多你直接使用Response.raw时必须处理的内容。在流式传输下载时,以上是检索内容的首选和推荐方式。请注意,chunk_size可以随意调整为更适合您的用例的数字。

Response.iter_content会自动解码gzip和deflate传输编码。Response.raw是一个原始的字节流,它不转换响应内容。如果您确实需要访问返回的字节,请使用Response.raw。

注2:使用流模式读取文件时,最终需要关闭流

http://www.cnblogs.com/Security-Darren/p/4196634.html

# -*- coding:utf-8 -*-

def get_image(img_url):
    import requests
    # response = requests.get(img_url,stream=True)
    # 引入上下文管理器的closing来实现关闭流
    from contextlib import closing
    # with closing(requests.get(img_url,stream=True,headers={‘User-Agent‘:‘Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36‘})) as response:
    with closing(requests.get(img_url,stream=True)) as response:
        print(‘Request Headers>>:\n‘,response.request.headers)
        with open(‘demo1.jpg‘,‘wb‘) as img_file:
            for chunk in response.iter_content(128):
                img_file.write(chunk)

def main():
    img_url=‘https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1512314249355&di=6371398ddfba39ce23fc02b74b2d59cf&imgtype=0&src=http%3A%2F%2Fpic.58pic.com%2F58pic%2F16%2F42%2F96%2F56e58PICAu9_1024.jpg‘
    # img_url=‘http://img5.imgtn.bdimg.com/it/u=2502798296,3184925683&fm=26&gp=0.jpg‘
    get_image(img_url)

if __name__ == ‘__main__‘:
    main()

requests库--下载图片并保存到本地

事件钩子--回调函数

  见 “发送请求” 下的代码

HTTP认证

基本认证

原理

使用

即上面说过的明文auth

requests.get(‘https://api.github.com/user‘,auth=(‘wahaha‘, ‘123456‘))

结果

此种方式在request库中是使用的base64编码的,直接解码可以得到用户名和密码

  headers如下:

oauth认证

原理

oauth的流程

http://www.barretlee.com/blog/2016/01/10/oauth2-introduce/

官方自定义oauth示例

http://www.python-requests.org/en/master/user/advanced/#custom-authentication

使用

简单使用:在settings->developer settings -> personal access tokens处生成一个测试token,并选择scope,将该token值放到request的headers中即可

结果

  headers如下:

proxy代理

原理

背景

本机不可以访问外网

代理服务器可以访问外网

配置代理服务器后,所有访问外网的请求会被发送到代理服务器,然后代理服务器发送该请求到外网服务器,然后·外网服务器返回响应到代理服务器,代理服务器再返回到本机

更多

搜索 heroku + socks

cookie

原理

由于HTTP本身是无状态的,即每个HTTP请求应该是独立的,但是由于现实需要后面的请求需要依赖前面的请求所获得的结果,所以产生了cookie。

1.浏览器第一次发送HTTP请求(无cookie)

2.服务器返回带cookie的HTTP响应

3.浏览器解析相应中的cookie,并保存在本地

4.浏览器第二次发送请求(带cookie)

官方使用

http://docs.python-requests.org/en/master/user/quickstart/#cookies

session

原理

由于cookie需要将用户的数据在每次请求中都附带,而数据在网络上传输是不安全的,所以产生了session,session会将主要数据保存在服务器端,而只给浏览器端返回一个带session-id的cookie,一定保障了数据的安全性与传输效率

时间: 2024-10-11 10:23:45

从Request库理解HTTP消息的相关文章

iOS runtime探究(二): 从runtime開始深入理解OC消息转发机制

你要知道的runtime都在这里 转载请注明出处 http://blog.csdn.net/u014205968/article/details/67639289 本文主要解说runtime相关知识,从原理到实践.由于包括内容过多分为下面五篇文章详细解说.可自行选择须要了解的方向: 从runtime開始: 理解面向对象的类到面向过程的结构体 从runtime開始: 深入理解OC消息转发机制 从runtime開始: 理解OC的属性property 从runtime開始: 实践Category加入属

数据获取--爬虫-3(Request库)

Request库使用教程 相比于urllib更加简便易用的HTTP库. Requests GET请求:只需要向requests.get()方法中传入相应的url即可以实现GET请求并获得Response.POST请求使用requests.post()方法实现代码如下: #GET请求 import requests response = requests.get('https://www.baidu.com/') print(response) #POST请求 import requests da

python3 request 库

request库 虽然Python的标准库中 urllib.request 模块已经包含了平常我们使用的大多数功能,但是它的 API 使用起来让人感觉不太好,而 Requests 自称 "HTTP for Humans",说明使用更简洁方便. Requests 唯一的一个非转基因的 Python HTTP 库,人类可以安全享用. Requests 继承了urllib2的所有特性.Requests支持HTTP连接保持和连接池,支持使用cookie保持会话,支持文件上传,支持自动确定响应内

Python3 urllib.request库的基本使用

urllib.request库 是 Python3 自带的模块(不需要下载,导入即可使用)python 自带的模块库文件都是在C:\Python\Lib目录下(C:\Python是我Python的安装目录),python第三方模块库都是在C:\Python\Lib\site-packages 下.urllib.request库在windows下的路径(C:\Python\Lib\urllib). 一:用urllib.request 里的urlopen()方法发送一个请求 import urlli

ASP.NET 4.0 设定 了 validateRequest="false" 仍然会出现 具有潜在危险 Request.QueryString 的错误消息

摘要:ASP.NET 4.0 设定 了 validateRequest="false" 仍然会出现 具有潜在危险Request.QueryString的错误消息 微软的asp.net网页都会默认进行Request Validation,但若是想规避这样的内建行为.(建议仍要有其他的方法来防范XSS攻击) 通常我们可以在.aspx中的Page Tag设定: ? 或是直接对整个站台设定Web.Config中??下设定全域的 不过,假如你现在在ASP.NET 4.0 的环境下的话,就算进行上

Python Request库学习(一)

一.安装Requests库 pip install requests 二.Request库基本使用 在Request库中常见的两种方法就是GET方法和Post方法,安装成功后,可以看到它自带了两个示例: 此外还支持De'lete.Put.Options方法.而equests库的方便之处在于所有的请求都可以使用一句代码来实现. 三.Get方法 使用Get: 简单示例: 运行结果: Params: Get方法常见的形式:https://ip:port/xxxx?xx=xx,如果访问带有参数的Url,

深入delphi编程理解之消息(一)WINDOWS原生窗口编写及消息处理过程

通过以sdk方式编制windows窗口程序,对理解windows消息驱动机制和delphi消息编程有很大的帮助. sdk编制windows窗口程序的步骤: 1.对TWndClass对象进行赋值; 2.向系统注册wndclass对象(RegisterClass): 3.CreateWindow创建窗口,获得窗口句柄Hwnd; 4.显示窗口(ShowWindow): 5.通过GetMessage函数不断获取系统消息,交给程序处理,程序过通回调函数(wndproc)处理系统消息.(消息处理部分)程序代

理解Windows消息循环机制

理解消息循环和整个消息传送机制对Windows编程十分重要.如果对消息处理的整个过程不了解,在windows编程中会遇到很多令人困惑的地方. 什么是消息(Message)每个消息是一个整型数值,如果查看头文件(查看头文件了解API是一个非常好的习惯和普遍的做法)可以发现如下一些宏定义: #define WM_INITDIALOG                   0x0110 #define WM_COMMAND                      0x0111 #define WM_L

Android 异步消息处理机制前篇(二):深入理解Message消息池

上一篇中共同探讨了ThreadLocal,这篇我们一起看下常提到的Message消息池到底是怎么回事,废话少说吧,进入正题. 对于稍有经验的开发人员来说我们在使用Handler发送异步消息获取Message的时候都会使用如下代码获取一个Message对象: 1 Message msg = mHandler.obtainMessage(); 而不是直接new一个: 1 Message msg = new Message(); 二者的主要区别就是上面的用到缓存池概念,如果池中有闲着的则拿来用,没有则