Requests

Requests

Yiuhang Chan

简介

  1. Requests是一个优雅而简单的Python HTTP库,专为人类而构建。
  2. 中文官方文档:http://cn.python-requests.org/zh_CN/latest/。
  3. 英文文档:http://docs.python-requests.org/en/master/api/

作者

Requests的作者Kenneth Reitz同样是一个富有传奇色彩的人物。

Requests目前基本上完全满足web请求的所有需求,以下是requests的特性:

  1. Keep-Alive & 连接池
  2. 国际化域名和URL
  3. 带持久Cookie的会话
  4. 浏览器式的SSL认证
  5. 自动内容解码
  6. 基本/摘要时的身份认证
  7. 优雅的 key/value Cookie
  8. 自动解压
  9. Unicode 响应体
  10. HTTP(S) 代理支持
  11. 文件分块上传
  12. 流下载
  13. 连接超时
  14. 分块请求
  15. 支持 .netrc

发送请求

使用 Requests 发送网络请求非常简单。导包, 之后添加方法进行。

Requests的请求不再像urllib一样需要去构造各种Request、opener和handler,使用Requests构造的方法,并在其中传入需要的参数即可。

发起请求的方法变得简单,只需要着重关注一下发起请求的参数 ,10个重要的参数。

    method, 请求方法
    url,  资源地址
    params=None, 查询参数也叫做查询字符串
    data=None,   post请求的表单数据
    headers=None, 请求头
    cookies=None, cookies
    files=None, # 文件
    auth=None, # 校验身份
    timeout=None, 超时时间
    allow_redirects=True, # 重定向
    proxies=None, 代理
    hooks=None,#  钩子函数
    stream=None,# 
    verify=None, 证书忽略
    cert=None, # 字符串 --证书的地址  元组()
    json=None,  post 请求的JSON数据

URL

传递URL参数也不用再像urllib中那样需要去拼接URL,而是简单的,构造一个字典,并在请求时将其传递给params参数,此时,查看请求的URL,则可以看到URL已经构造正确了,并且,有时候我们会遇到相同的url参数名,但有不同的值,而python的字典又不支持键的重名,那么我们可以把键的值用列表表示:

添加请求头

如果想自定义请求的Headers,同样的将字典数据传递给headers参数。

添加cookies

Requests中自定义Cookies也不用再去构造CookieJar对象,直接将字典递给cookies参数。

设置超时时间

设置访问超时,设置timeout参数即可。

设置代理

当我们需要使用代理时,同样构造代理字典,传递给proxies参数。

重定向

很多网站是http开头,为了不影响老客户,原网站不动,当访问http的原网址时,重定向到新的https网址,在requests中 allow_redirects默认是True,如果是False则不允许重定向,也就无法重定向新网址获取数据。

证书忽略验证

有时候我们使用了抓包工具,这个时候由于抓包工具提供的证书并不是由受信任的数字证书颁发机构颁发的,所以证书的验证会失败,所以我们就需要关闭证书验证。在请求的时候把verify参数设置为False就可以关闭证书验证了。

POST请求发送Json数据

POST请求发送Form表单数据

POST示例

https://www.17k.com/登录为案例,首先分析登录逻辑

尝试登录操作,发现操作后会其Headers下会显示请求的网址https://passport.17k.com/ck/user/login,且请求类型为POST

随后分析所需的构造参数

在Payload下可以发现其为表单数据,应构造的参数为{loginName: 123, password: 123}

另外还需添加headers伪装

接着根据分析的要素,构造请求,向服务器提交数据即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import requests

url='https://passport.17k.com/ck/user/login'

form_data = {
'loginName': '123',
'password': '123'
}
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36'
}

resp = requests.post(url, data=form_data, headers=headers)
print(resp.text)

response对象

属性

1
2
3
4
5
6
7
8
9
10
print(res.text)#直接转换成字符串 非字节码
print(res.content)#图片数据 使用此参数
print(res.status_code)#状态码
print(res.json()["headers"]["User-Agent"])#自动转换成 字典格式
# 一定要确保使用的格式是json格式的数据
print(res.headers)#响应头
print(res.cookies)#响应cookie
print(res.url)#请求的url
print(res.request.url)#请求的url
print(res.request.headers)#请求头

响应内容

通过Requests发起请求获取到的,是一个requests.models.Response对象。通过这个对象我们可以很方便的获取响应的内容。
之前通过urllib获取的响应,读取的内容都是bytes的二进制格式,需要我们自己去将结果decode()一次转换成字符串数据。
而Requests通过text属性,就可以获得字符串格式的响应内容。

字符编码和二进制数据

Requests会自动的根据响应的报头来猜测网页的编码是什么,然后根据猜测的编码来解码网页内容,基本上大部分的网页都能够正确的被解码。而如果发现text解码不正确的时候,就需要我们自己手动的去指定解码的编码格式。而如果需要获得原始的二进制数据,那么使用content属性即可。

session方法

session方法是requests库发起请求的一种方法,这种方法会自动保存访问页面得到的cookie值,从而再次访问的时候会自动携带cookie,使得操作cookie方便,不需要我们自己添加cookie了。常用于登录;

经典的登录逻辑

功能:自动更新请求头信息,常用在账号登录的时候,先访问登录页url,再访问数据提交的url
例:12306

session的使用

基本的使用方法与requests.get 相似,使用的session的时候需要先创建session对象

1
2
3
session=requests.session()#创建session对象
session.headers=headers#添加请求头
res_ss=session.get(index_url)

session示例

首先利用测试网址编入cookies

1
2
3
4
5
6
7
8
9
10
11
12
13
import requests

session = requests.session()
resp_ss = session.get('http://httpbin.org/cookies/set/CosTrace/12345678')
print(resp_ss.text)

"""
{
"cookies": {
"CosTrace": "12345678"
}
}
"""

采用requests.get方法尝试获取cookies,发现不存在值,这是因为requests方法本身不存在存储的功能

1
2
3
4
5
6
7
8
9
resp_req = requests.get('http://httpbin.org/cookies')
print(resp_req.text)

"""
{
"cookies": {}
}
}
"""

随后我们用session方法尝试获取cookies,发现成功

1
2
3
4
5
6
7
8
9
10
resp_req = session.get('http://httpbin.org/cookies')
print(resp_req.text)

"""
{
"cookies": {
"CosTrace": "12345678"
}
}
"""

Requests案例1 - 简易百度图片抓取

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
"""
目标:百度图片抓取
1. 打开网页 -->请求 -->伪装
a. 安装模块 pip install requests
b. 请求失败的话就在伪装继续添加标头
2. 下载图片 --保存本地 -->交互
a. 把响应内容中的图片url提取出来
b. 对每个图片的url,进行请求二进制的方法进行保存
"""
from hashlib import md5

import requests, re

# 赋值url
url = 'https://image.baidu.com/search/index?tn=baiduimage&ipn=r&ct=201326592&cl=2&lm=-1&st=-1&fm=index&fr=&hs=0&xthttps=000000&sf=1&fmq=&pv=&ic=0&nc=1&z=&se=1&showtab=0&fb=0&width=&height=&face=0&istype=2&ie=utf-8&word=%E5%AE%88%E6%9C%9B%E5%85%88%E9%94%8B&oq=%E5%AE%88%E6%9C%9B%E5%85%88%E9%94%8B&rsp=-1'

# 表头字典,制作伪装
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36',
}

# 赋值请求服务, 获取http数据
resp = requests.get(url, headers=headers)
http_data = resp.text

# 正则表达式提取图片
re_data = re.findall('thumbURL":"(.*?)"', http_data)

# 循环提取, md5去重命名
for i in re_data:
name_encode = md5(i.encode()).hexdigest()
img_resp = requests.get(i)
b_img_data = img_resp.content
with open(f'{name_encode}.jpg', 'wb') as f:
f.write(b_img_data)

Requests案例2 - 多页百度图片抓取

首先分析,在标头的响应查看滚动页面时返回的URL,分析翻页时的变化:

1
2
3
4
# 在标头的响应查看滚动页面时返回的url
url_1 = 'https://image.baidu.com/search/acjson?tn=resultjson_com&logid=8578568584458070132&ipn=rj&ct=201326592&is=&fp=result&fr=&word=%E5%AE%88%E6%9C%9B%E5%85%88%E9%94%8B&queryWord=%E5%AE%88%E6%9C%9B%E5%85%88%E9%94%8B&cl=2&lm=-1&ie=utf-8&oe=utf-8&adpicid=&st=&z=&ic=&hd=&latest=&copyright=&s=&se=&tab=&width=&height=&face=&istype=&qc=&nc=1&expermode=&nojc=&isAsync=&pn=60&rn=30&gsm=3c&1701269373791='
url_2 = 'https://image.baidu.com/search/acjson?tn=resultjson_com&logid=8578568584458070132&ipn=rj&ct=201326592&is=&fp=result&fr=&word=%E5%AE%88%E6%9C%9B%E5%85%88%E9%94%8B&queryWord=%E5%AE%88%E6%9C%9B%E5%85%88%E9%94%8B&cl=2&lm=-1&ie=utf-8&oe=utf-8&adpicid=&st=&z=&ic=&hd=&latest=&copyright=&s=&se=&tab=&width=&height=&face=&istype=&qc=&nc=1&expermode=&nojc=&isAsync=&pn=90&rn=30&gsm=5a&1701269630311='
url_3 = 'https://image.baidu.com/search/acjson?tn=resultjson_com&logid=8578568584458070132&ipn=rj&ct=201326592&is=&fp=result&fr=&word=%E5%AE%88%E6%9C%9B%E5%85%88%E9%94%8B&queryWord=%E5%AE%88%E6%9C%9B%E5%85%88%E9%94%8B&cl=2&lm=-1&ie=utf-8&oe=utf-8&adpicid=&st=&z=&ic=&hd=&latest=&copyright=&s=&se=&tab=&width=&height=&face=&istype=&qc=&nc=1&expermode=&nojc=&isAsync=&pn=120&rn=30&gsm=78&1701269630813='

随后比较三个URL直接的关系,可以发现大部分都是相同,因此删除所有相同的部分进行比较:

1
2
3
4
5
6
7
8
9
# 分析链接不同的规律,下面是不同的部分:
# pn: 当前显示的图片数量,一次翻页显示30张,pn(Page Number): 这个参数通常用于分页功能,表示当前显示的页面编号或者某些情况下显示的项目数量。
# 例如,在图像搜索结果中,pn=90可能表示当前显示的是第90张图片或第90页的内容。
# gsm未知,可能表示一个特定的标识符或编码,用于追踪请求或控制返回的内容
# 后面的长数值是时间戳,时间戳通常用于记录事件发生的具体时间,有时用于缓存控制或确保请求的唯一性

url_1_compar = 'pn=60&gsm=3c&1701269373791='
url_2_compar = 'pn=90&gsm=5a&1701269630311='
url_3_compar = 'pn=120&gsm=78&1701269630813='

最后把完整URL输入到浏览器,查看删减这三个不同的部分哪些会影响数据的获取:

1
2
3
4
# 通过删减url发现时间戳和gsm均不影响翻页,因此剩余影响数据获取的不同点是pn,且每30一获取:
url_1_compar_2 = 'pn=60'
url_2_compar_2 = 'pn=90'
url_3_compar_2 = 'pn=120'

通过分析可以发现百度翻页规律,随后编写循环(此例为三页)配合案例1的伪装即可获取

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
# 表头字典,制作伪装
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36',
}
if not os.path.exists('images'):
os.mkdir('images')

# 编写循环,每30返回一次:
for i in range(1, 4):
url = f'https://image.baidu.com/search/acjson?tn=resultjson_com&logid=8578568584458070132&ipn=rj&ct=201326592&is=&fp=result&fr=&word=%E5%AE%88%E6%9C%9B%E5%85%88%E9%94%8B&queryWord=%E5%AE%88%E6%9C%9B%E5%85%88%E9%94%8B&cl=2&lm=-1&ie=utf-8&oe=utf-8&adpicid=&st=&z=&ic=&hd=&latest=&copyright=&s=&se=&tab=&width=&height=&face=&istype=&qc=&nc=1&expermode=&nojc=&isAsync=&pn={i * 30}&rn=30'
resp = requests.get(url, headers=headers) # 赋值请求服务, 获取http数据
data = resp.json() # json -> 字符串转成dict格式,前提条件就是resp一定时json格式
data_list = data.get("data") # 这是一个列表
for j in data_list:
img_url = j.get("thumbURL") # 获取该变量下的值
if img_url: # 当请求到数据时
try:
img_url_encode = md5(img_url.encode()).hexdigest() # md5去重,唯一标识符
img_resp = requests.get(img_url)
except Exception as e:
print(e) # 是否有脏数据
continue
else:
b_img_data = img_resp.content
with open('images/' + img_url_encode + '.jpg', 'wb') as f:
f.write(b_img_data)
else:
continue
  • 标题: Requests
  • 作者: Yiuhang Chan
  • 创建于 : 2021-02-22 18:12:32
  • 更新于 : 2024-02-28 18:50:20
  • 链接: https://www.yiuhangblog.com/2021/02/22/20210222requests/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论