当前位置:   article > 正文

request模块

request模块

1 request 基本使用

1.1 requests模块的作用

作用:发送网络请求,返回响应数据

中文文档 : http://docs.python-requests.org/zh_CN/latest/index.html
  • 1
  • 2
  • 3

1.2. Requests的简单使用

使用 Requests 发送网络请求非常简单。

1.2.1 安装
pip install requests
  • 1
1.2.2 发送请求
#使用requests库前都要导入requests库
import requests

#发送GET,POST,PUT,DELETE,HEAD 以及 OPTIONS 请求
r = requests.get('https://postman-echo.com/get')
r = requests.post('https://postman-echo.com/post')
r = requests.put('https://postman-echo.com/put')
r = requests.delete('https://postman-echo.com/delete')
r = requests.head('https://postman-echo.com/get')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
1.2.3 响应状态码、响应头、响应体

当请求返回后,我们如何查看响应对象的内容

import requests

# 访问百度首页
resp = requests.get('http://www.baidu.com')

# 查看响应状态码
print(resp.status_code)
# 200

# 查看响应头
print(resp.headers)

# 查看响应体,未进行解码
# content 是字节类型数据
print(resp.content)

# 查看响应体,解码之后的
print(resp.text)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

请求发出后,Requests 会基于 HTTP 头部对响应的编码作出推测。当你访问 resp.text 之时,Requests 会使用其推测的文本编码, 如果 request 推测的编码和实际的响应的编码不同则可能出现乱码。我们可以通过 resp.encoding 查看当前猜测的编码, 也可以通过赋值来改变这个编码.

import requests

resp = requests.get('http://www.baidu.com')

# 查看当前的 encoding
print(resp.encoding)
# 'ISO-8859-1'

# 更改 encoding
resp.encoding = 'utf-8'

# 查看更改后的 encoding
print(resp.encoding)
# 'utf-8'

# 查看解码的文本内容
print(resp.text)
# 非乱码的内容
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
1.2.4 Json

手动将 json 格式的响应体转换为字典

import json
import requests

# 这里请求 postman 提供的地址,他会返回一个 json 格式的响应体
url = 'https://postman-echo.com/ip'
resp = requests.get(url)

# 获取响应头
headers = resp.headers

# 获取响应头 Content-Type ;这个头告诉客户端响应体的格式
content_type = headers.get('Content-Type','no [Content-Type] header')

# 判断是否是 json 格式的响应体
if 'application/json' in content_type:
    # 获取响应体
    content = resp.content

    # 通过 json.loads 解析为字典
    dict_data = json.loads(content)

    # 查看 dict_data
    print(type(dict_data))
else:
    print(f'响应体格式是:{content_type} ,不是 json 格式的')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

通过 响应对象的 json 方法

import requests

# 这里请求 postman 提供的地址,他会返回一个 json 格式的响应体
url = 'https://postman-echo.com/ip'
resp = requests.get(url)

# 通过响应对象的 json 方法获取 json 数据
print(resp.json())
# {'ip': '140.206.149.83'}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

如果 JSON 解码失败, r.json() 就会抛出一个异常。例如,响应内容是 html 格式的,尝试访问 r.json() 将会抛出异常。

import requests

# 这里请求百度首页
url = 'http://www.baidu.com'

# 请求 baidu 的首页,这里会获得 html
resp = requests.get(url)

# 响应体不是 json 类型,会抛出异常
print(resp.json())

# 抛出异常
# ......
# JSONDecodeError: Expecting value: line 1 column 1 (char 0)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
1.2.5 传递URL参数
import requests

# 这个接口会把我们传递的 url 参数,通过响应体返回
url = 'https://postman-echo.com/get'

# GET请求时传递参数
payload = {'key1': 'value1', 'key2': 'value2', 'key3': ['value3', 'valua4']}

# 通过 params 参数传递 url 参数
resp = requests.get(url, params=payload)

# 查看发起请求的的完整 url
print(resp.url)

# 查看响应体
print(resp.json())

# 手动拼接参数
url = 'https://postman-echo.com/get?key1=value1&key2=value2&key3=value3&key3=value4'
resp = requests.get(url)

# 查看响应体 json
print(resp.json())
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
1.2.6 定制请求头
import requests

# 这个接口会把我们携带的请求头通过响应体返回
url = 'https://postman-echo.com/headers'

# 定义请求头字典
headers = {'test-header': 'my-accept'}

# 通过 headers 参数传递自定义请求头
resp = requests.get(url, headers=headers)

# 查看响应体 json
print(resp.json())
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

注意: 所有的 header 值必须是 string、bytestring 或者 unicode。尽管传递 unicode header 也是允许的,但不建议这样做

1.2.7 Cookie

快速访问响应的cookie

import requests

# 访问这个接口时,服务器会返回一个 cookie
url = 'https://postman-echo.com/cookies'

resp = requests.get(url)

# 通过响应对象的 cookies 属性查看服务器返回的 cookie
print(resp.cookies)

#  <RequestsCookieJar[<Cookie sails.sid=s%3AXnK01xxH1XlWurud4tQ4vHaYyyBZtl0U.1EHKamEv2C%2BiZ7C%2Fo9xhWWBNWOPVCOYgAMgn7tPH97Y for postman-echo.com/>]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

从 http 协议的角度来说,服务返回的 cookie 是通过响应头的 set-cookie 返回的,requests 包会自动解析 set-cookie 响应头,将解析的 cookies 放到响应对象的 cookies 属性中,所以我们也可以通过 resp.headers 查看 cookie 的响应头。

发送cookies到服务器

import requests

# 这个接口会把我们携带的cookies通过响应体返回
url = 'https://postman-echo.com/cookies'

# 构建 cookie
cookies = {
    'foo1':'foo1',
    'foo2':'foo2'
}

# 通过 cookies 参数发送 cookies
resp = requests.get(url, cookies=cookies)

# 查看响应体 json
print(resp.json())
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

把 Cookie Jar 传到 Requests 中:

import requests

# 新建 RequestsCookieJar 对象
jar = requests.cookies.RequestsCookieJar()

# 通过 set 方法添加 cookie
jar.set('foo1', 'f001')
jar.set('foo2', 'f0002')

# 这个接口会把我们携带的cookies通过响应体返回
url = 'https://postman-echo.com/cookies'

# 通过 cookies 参数传递 cookiejar 对象
resp = requests.get(url, cookies=jar)

# 查看响应体 json
print(resp.json())
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
1.2.8 POST 发送 json 数据

除了 get 请求方法之外,我们常用的还有 post 方法,使用 requests可以方便的发送 json 数据给服务器。我们把 python 的字典传递给 post 方法的 json 参数即可。

import requests

auth = {
    "username":"admin",
    "password":"admin1234"
}
# 调用登录接口
url = 'http://localhost:8000/login/'
# 将 auth 传递给 json
resp = requests.post(url, json=auth)
# 查看响应体 json
print(resp.json())
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
1.2.9 Session

我们通过浏览器进行登录操作时,服务器会返回cookie,浏览器会把这些 cookie 存储下来,下次发起请求就把之前保存的 cookie 携带着发送给服务器,从而实现了状态保持。

我们通过 requests.[get|post|…] 进行登录操作或者其他操作,服务器返回了 cookie,下次再通过 requests.[get|post|…] 发起其他请求时,requests 并不会把前面请求的 cookie 携带着发送给服务器,也就是说我们通过 requests.[get|post|…] 是无法自动实现状态保持的。

我们可以通过 requests.Session 来实现状态保持,我们通过 Session 对象的 [get|post|…] 方法发起请求,session 对象会自动保存响应的 cookie,并且下次发起请求时自动携带着这些 cookie。session.cookies 可以查看 session 中保存的所有 cookie。

需求:获取用户信息。获取用户信息必须先调用进行用户登录接口,在调用获取用户信息接口。

requests 方式

from requests import Request

auth = {
    "username":"admin",
    "password":"admin1234"
}
# 调用登录接口
login_url = 'http://localhost:8000/login/'

# 将 auth 传递给 json
resp = requests.post(login_url, json=auth)

print(resp.json())

# 调用用户信息接口
info_url = 'http://localhost:8000/info/'

resp = requests.get(info_url)

print(resp.json())
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

session 方式

from requests import Request, Session

# 新建 session 对象
session = Session()

# 查看 session 中的 cookie
print(session.cookies)

auth = {
    "username":"admin",
    "password":"admin1234"
}
# 调用登录接口
login_url = 'http://localhost:8000/login/'

# 通过 session 发起请求
resp = session.post(login_url, json=auth)

# 通过 resp.cookies 查看
print(session.cookies)

print(resp.json())

# 调用用户信息接口
info_url = 'http://localhost:8000/info/'

resp = session.get(info_url)

print(resp.json())
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
1.2.9.1 session.cookies 操作
session.cookies 对象类似于字典,我们可以通过操作字典的方式操作 cookies

from requests import Session

session = Session()

print(session.cookies)

# 添加 cookie
session.cookies['cookie-1']='value-1'
print(session.cookies)

# 修改 cookie
session.cookies['cookie-1']='value-1-updated'
print(session.cookies)

# 查看 cookie
print(session.cookies['cookie-1'])
print(session.cookies.get('cookie-1'))

# 删除
del session.cookies['cookie-1']
print(session.cookies)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
1.2.9.2 session 请求头

使用 cookie 的状态保持本身有一些缺陷,因为浏览器发起请求时会自动携带 cookie,攻击者利用这一点进行跨域攻击 CSRF。为了避免这种情况发生,有一种解决方案是: 将认证信息添加到自定义的请求头中,由于是自定义的请求头,浏览器也就无法自动携带该请求头,我们需要在发起 ajax 请求的时候,手动添加该请求头。

在 session 中我们可以通过把 自定义的请求头 放入 session.headers 中,那么每次通过 session 对象发起请求的时候,就会自动携带者该请求头,不用每次都通过 headers 参数来携带。

session.headers 和 cookies 类似,也是字典格式的对象。

from requests import Session

# 这个接口会把我们携带的请求头通过响应体返回
url = 'https://postman-echo.com/headers'

# 新建 session 对象
session = Session()

# 打印 session.headers 的默认值
print(session.headers)

# 添加自定义请求头
session.headers['Auth-Token'] = 'some token xxxxx'

resp = session.get(url)

# 查看响应体 json
print(resp.json())

# 如果添加了 headers 参数,那么会和 session.headers 合并
resp = session.get(url,headers={'my-header':'header-value'})
print(resp.json())

# headers 参数不会被保存到 session.headers 中,只对当请求有效
print(session.headers)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

2 request 深入使用

2.1 使用 requests 发送表单请求

import requests
import json


class King(object):

    def __init__(self, word):
        self.url = "http://fy.iciba.com/ajax.php?a=fy"
        self.word = word
        self.headers = {
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36"
        }
        self.post_data = {
            "f": "auto",
            "t": "auto",
            "w": self.word
        }

    def get_data(self):
        response = requests.post(self.url, headers=self.headers, data=self.post_data)
        # 默认返回bytes类型,除非确定外部调用使用str才进行解码操作
        return response.content

    def parse_data(self, data):

        # 将json数据转换成python字典
        dict_data = json.loads(data)

        # 从字典中抽取翻译结果
        try:
            print(dict_data['content']['out'])
        except:
            print(dict_data['content']['word_mean'][0])

    def run(self):
        # url
        # headers
        # post——data
        # 发送请求
        data = self.get_data()
        # 解析
        self.parse_data(data)

if __name__ == '__main__':
    # king = King("人生苦短,及时行乐")
    king = King("China")
    king.run()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47

2.2 requests使用代理

  • 让服务器以为不是同一个客户端在请求
  • 防止我们的真实地址被泄露,防止被追究

为了让服务器以为不是同一个客户端在请求;为了防止频繁向一个域名发送请求被封ip,所以我们需要使用代理ip;那么我们接下来要学习requests模块是如何使用代理ip的

用法:

response = requests.get(url, proxies=proxies)
  • 1

proxies参数的格式: 字典

例如:

proxies = { 
    "http": "http://127.0.0.1:1082", 
    "https": "http://127.0.0.1:1082", 
}
  • 1
  • 2
  • 3
  • 4

注意:如果proxies字典中包含有多个键值对,发送请求时将按照url地址的协议来选择使用相应的代理ip

3 request 其他用法

3.1 处理证书错误

知识点

  • requests 不进行 https 验证
  • retrying 重试
  • requests处理证书错误

原因:该网站的CA证书没有经过【受信任的根证书颁发机构】的认证
关于CA证书以及受信任的根证书颁发机构点击了解更多,课上我们不做展开

3.1.1 代码中发起请求的效果

那么如果在代码中请求会怎么样呢?

import requests

requests.get('http://api.mering.live')
抛出以下错误

SSLError: HTTPSConnectionPool(host='api.mering.live', port=443): Max retries exceeded with url: / (Caused by SSLError(SSLCertVerificationError("hostname 'api.mering.live' doesn't match either of 'www.mering.live', 'mering.live'")))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
3.1.2 解决方案

为了在代码中能够正常的请求,我们使用verify=False参数,此时requests模块发送请求将不做CA证书的验证:verify参数能够忽略CA证书的认证

import requests

requests.get('http://api.mering.live',verify=False) # 这里不会报错了
  • 1
  • 2
  • 3

实际上认证的验证是在客户端进行的,客户端可以选择不对证书进行验证,但是这个是危险的,容易被其他人窃取信息。

3.2. 超时参数timeout的使用

有时候我们再访问某个网站的时候,可能由于网络延迟或者服务器处理速度等原因导致,请求发送出去后,过了很久都没有得到响应,我们可以使用超时参数,在等待一段时间后,如果没有得到服务器的响应就抛出超时异常

超时参数timeout的使用方法:

response = requests.get(url, timeout=3)
timeout=3表示:发送请求后,3秒钟内返回响应,否则就抛出异常

import requests


url = 'https://twitter.com'
response = requests.get(url, timeout=3)     # 设置超时时间

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

3.3. retrying 模块的使用

有时候我们希望对网站的请求失败时,能够自动重新发起请求,这个时候我们可以利用 retrying 模块。

3.3.1 retrying模块的使用
retrying模块的地址:https://pypi.org/project/retrying/
  • 1

安装:

pip install retrying
  • 1

retrying 模块的使用

  • 用 retrying 模块提供的 retry 模块

  • 通过装饰器的方式使用,让被装饰的函数反复执行

retry 中可以传入参数 stop_max_attempt_number ,让函数报错后继续重新执行,达到最大执行次数的上限,如果每次都报错,整个函数报错,如果中间有一个成功,程序继续往后执行

3.3.2 retrying和requests的简单封装

实现一个发送请求的函数,每次爬虫中直接调用该函数即可实现发送请求,在其中

  • 使用timeout实现超时报错
  • 使用retrying模块实现重试

参考代码:

import requests
from retrying import retry

headers = {}

# 最大重试3次,3次全部报错,才会报错
@retry(stop_max_attempt_number=3) 
def _parse_url(url)
    # 超时的时候回报错并重试
    response = requests.get(url, headers=headers, timeout=3) 
    # 状态码不是200,也会报错并重试
    assert response.status_code == 200
    return response


def parse_url(url)
    try: # 进行异常捕获
        response = _parse_url(url)
    except Exception as e:
        print(e)
        # 报错返回None
        response = None
    return response
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/259774?site
推荐阅读
相关标签
  

闽ICP备14008679号