1.requests的请求方式
2.请求参数传递
3.响应response
4.Cookie和Session
5.Cookie基础详细

1.requests请求方式

requests库下主要有两个请求方式:POST,GET请求

GET请求

举例说明:

1
2
3
4
5
import requests

response = requests.get("http://www.baidu.com")
print(type(response)) # <class ‘requests.models.Response’>
print(response.status_code) # 200

将参数写成字典的形式,利用get()方法的参数进行请求,可以动态更改请求参数

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

# 普通请求
r = requests.get('https://anoyi.com/')

# 带 Query 参数,等价于 https://anoyi.com/?key1=value1&key2=value2
payload = {'key1': 'value1', 'key2': 'value2'}
r = requests.get('https://anoyi.com/', params=payload)

# 带 Headers
headers = {'user-agent': 'anoyi-app/0.0.1'}
r = requests.get('https://anoyi.com/', headers=headers)

# 带 Basic Authentication
r = requests.get('https://anoyi.com/', auth=('user', 'pass'))

POST请求

POST请求可以携带多种形式的参数:

  • request payload(负载)

先将request payload格式的数据写成标准的json数据格式,最后再转换成字符串(json.dumps将数据字符串化,json.loads是将字符串还原成原本的数据格式)

1
2
3
4
5
6
7
8
9
10
11
12
import json
import requests
# request payload数据格式
payloadData = {
'afnPriceStr': 10,
'currency':'USD',
'productInfoMapping': {
'asin': 'B072JW3Z6L',
'dimensionUnit': 'inches',
}
}
r = requests.post(url="url", data=json.dumps(payloadData))
  • application/json

application/json格式的请求头是指用来告诉服务端post过去的消息主体是序列化后的 JSON 字符串,但是如果服务器后端支持可以直接传入一个字典的话,就不需要再将数据JSON序列化了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import json
import requests

url = 'http://official-account/app/messages/group'
body = {"type": "text", "content": "测试文本", "tag_id": "20717"}
headers = {'content-type': "application/json"}

#print type(body)
#print type(json.dumps(body))
# 这里有个细节,如果body需要json形式的话,需要做处理
# 可以是data = json.dumps(body)
response = requests.post(url, data = json.dumps(body), headers = headers)
# 也可以直接将data字段换成json字段,2.4.3版本之后支持
response2 = requests.post(url, json = body, headers = headers)

# 返回信息
print(response.text)
# 返回响应头
print(response.status_code)
  • x-www-form-urlencoded(默认格式)

最常见post提交数据的方式,以form表单形式提交数据

reqeusts支持以application/x-www-form-urlencoded数据格式发送post请求,只需要将请求的参数构造成一个字典,然后传给requests.post()的data参数即可。

同时也是支持以键值对的形式来提交数据

1
2
3
4
5
6
7
8
9
10
11
import requests
# 键值对参数
headers = {'content-type': 'application/x-www-form-urlencoded; charset=UTF-8'}
res = requests.post('https://anoyi.com/', headers=headers, data='key=value')

# 字典型参数
data = {
"key1": "value1",
"key2": "value2"
}
rsp = requests.post('https://anoyi.com/', headers=headers, data=data)
  • form-data

除了传统的application/x-www-form-urlencoded表单,我们另一个经常用到的是上传文件用的表单,这种表单的类型为multipart/form-data

一般用于实现文件上传外,也可同样作为简单form表单发送请求

1
2
3
4
5
6
7
8
9
10
11
12
13
import requests
# 基本 post 请求
data = {
'name':'M.Lu',
'age':'22'
}
response = requests.post("http://httpbin.org/post", data=data)
print(response.text)

# 文件上传
files = {"file": open("C:/Users/Administrator/Desktop/test.txt", "rb")}
res = requests.post("http://httpbin.org/post", files=files)
print(res.text)
  • text/xml

text/xml可实现对webService发送数据请求

1
2
3
4
import requests
xml = """my xml"""
headers = {'Content-Type': 'application/xml'}
requests.post('http://www.example.com', data=xml, headers=headers)

其它请求

1
2
3
4
5
6
7
8
9
10
11
12
import requests
# PUT
r = requests.put('https://anoyi.com/', data={'key':'value'})

# DELETE
r = requests.delete('https://anoyi.com/')

# HEAD
r = requests.head('https://anoyi.com/')

# OPTIONS
r = requests.options('https://anoyi.com/')

2.传递参数

      无论是post还是get请求,对url进行请求时,都可以传递参数

headers

反爬虫措施的基本操作,将爬虫伪装成正常的浏览器,躲过服务器的验证

1
2
3
4
5
6
headers = {
"User-Agent": "", 浏览器对象
"Cookie":"", cookie能够存储浏览器上次访问的信息
"host":"", 计算机ip
"referer":"" 引用
}

timeout超时

      超时是请求能够容忍的最大时间,如果在这个时间内,还没有响应返回过来,那么这次请求就算失败了,不再继续等待请求的结果。浏览器发送请求后,服务器接受数据处理后,再返回目标数据,这过程中可能因为各种原因导致响应很慢,设置timeout,超时后停止访问
response = requests.post(“http://httpbin.org/post", data=data,timeout = 10)

verify证书

      证书验证也是我们经常会遇到的问题,通常情况下,访问一些网站的时候,都会验证访问者的证书是否合法,如果不合法,就不允许访问。大部分情况,我们之间设置证书验证为 False 即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 有验证
response = requests.get("https://cms.hit.edu.cn/") # 程序会中断
print(response.status_code)
# 没有验证
response = requests.get("https://cms.hit.edu.cn/", verify=False)
print(response.status_code)
去除 warning 方法
from requests.packages import urllib3
urllib3.disable_warnings()
response = requests.get("https://cms.hit.edu.cn/", verify=False)
print(response.status_code)
cert 手动指定证书
response = requests.get("https://cms.hit.edu.cn/",cert={'path/server.crt', '/path/key'})
print(response.status_code)

当我们设置SSL验证为False时,会弹出很多警告,这时我们就需要新增两行代码:

1
2
3
4
import requests
from urllib3.exceptions import InsecureRequestWarning
# 禁用安全请求警告
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)

proxies代理

      代理也是一个很常用的方法。通常,在我们需要多个主机进行访问或需要绕过防火墙时,可以利用代理进行访问

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 无密码
proxies = {
"http":"http://178.128.63.64:8388"
}
# 有密码
proxies = {
"http":"http://user:password@178.128.63.64:8388"
}
response = requests.get("https://www.taobao.com", proxies=proxies)
print(response.status_code)
# 利用 socks 进行代理设置
proxies = {
"http":"socks5://178.128.63.64:8388",
"https":"socks5://178.128.63.64:8388"
}
response = requests.get("https://www.taobao.com", proxies=proxies)
print(response.status_code)

补充:2020-4-13 代理池的设计

今天花了一段时间设计了一个代理池,参考我的GitHub【python代理池设计】

cookies

cookies除了放置在headers请求头里之外,也可以使用requests关键字里的cookies={…}

cookie放在请求头里发请求和使用requests关键字cookies={…}没有任何区别

1
response = requests.post(url=url, headers=headers, data=data, cookies=cookies)

区别cookie放置位置:

  • cookie放在headers中:格式类似于("key1:value1; key2:value2; key3:value3")
1
2
3
headers = {
"Cookie": "_octo=GH1.1.162052.1572277627; _ga=GA1.2.579499272.1572277630; tz=Asia%2FShanghai"
}
  • cookie放在requests关键词中的cookies可以为CookieJar类或者字典格式的cookie

stream流文件

Bit、 Byte、KB、MB、GB之间的换算:

1 Byte = 8 Bits(即 1B=8b,字节是内存的基本单位)
1 KB = 1024 Bytes
1 MB = 1024 KB
1 GB = 1024 MB

Bit意为“位”或“比特”,是计算机运算的基础,属于二进制的范畴;
Byte意为“字节”,是计算机文件大小的基本计算单位;

这两者应用的场合不同。通常用bit来作数据传输的单位,因为物理层,数据链路层的传输对于用户是透明的,而这种通信传输是基于二进制的传输。在应用层通常是用byte来作单位,表示文件的大小,在用户看来就是可见的数据大小。比如一个字符就是1byte,如果是汉字,则是2byte

比如常见的音视频,放置某些文件过大,内存溢出

1
2
3
4
5
response = requests.post(url=url, 
headers=headers,
data=data,
cookies=cookies,
stream=True)

拓:进度条下载二进制文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import sys
import requests

url = "https://w.wallha.com/ws/12/uOaBe9fY.MP4"
rsp = requests.head(url)
# 获取返回文件的大小
size = rsp.headers['Content-Length']
# 将字节Byte转换为MB
print("文件大小: %.2f MB" % (int(size) / 1024 / 1024))
p = 0
rp = requests.get(url, stream=True)
with open('./video.mp4', 'wb') as f:
# 开始下载每次请求1024字节
for i in rp.iter_content(chunk_size=1024):
p += len(i)
f.write(i)
done = 50 * p / int(size)
sys.stdout.write("\r[%s%s] %.2f%%" % ('█' * int(done), '' * int(50 - done), done + done))
sys.stdout.flush()

allow_redirects重定向

  • Redirect重定向就是通过各种方法将各种网络请求重新定个方向转到其它位置,从地址A跳转到地址 B 了:
  • 重定向状态码:
    • 301 redirect: 301 代表永久性转移(Permanently Moved)
    • 302 redirect: 302 代表暂时性转移(Temporarily Moved) (PS:有时是307 Temporarily)
  • 实际场景:
    举个简单的场景案例,先登录博客园打开我的博客首页,进我的随笔编辑界面,记住这地址:https://i.cnblogs.com/EditPosts.aspx?opt=1 ,退出博客园登录,把刚才我的随笔这个地址输入浏览器回车,抓包会看到这个请求状态码是 302,浏览器地址栏瞬间刷新跳到登录首页去了

自动处理重定向地址后,我们就获取不到重定向后的 url 了,就无法走下一步,这里我们可以设置一个参数禁止重定向:allow_redirects=False(allow_redirects=True 是启动重定向),然后就可以看到 status_code 是 302 了,重定向的跳转地址是在返回的请求头中

-301 永久性重定向处理方法

1
2
3
4
import requests
response = requests.session.get(url=deal_url, headers=headers, timeout=10)
# 获取重定向后的简化url
print(response.url)
  • 302/307 临时重定向处理方法
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    import requests
    #禁用安全请求警告
    from requests.packages.urllib3.exceptions import InsecureRequestWarning
    requests.packages.urllib3.disable_warnings(InsecureRequestWarning)

    url = "https://i.cnblogs.com/EditPosts.aspx?opt=1"
    headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36"
    }
    s = requests.Session()
    #打开我的随笔
    r = s.get(url,headers=headers,verify=False,allow_redirects=False)
    # print(r.content.decode("utf-8"))
    #打印状态码,自动处理重定向请求
    print(r.status_code)
    #获取重定向后的地址
    print(r.headers["Location"])

3.响应response

      响应是浏览器返回过来的信息,它有不同的属性

  • response.status_code: 状态码,不同的状态码代表了不同的请求状态
  • response.headers: 获取请求头
  • response.cookies: 获取cookies
  • response.url: 获取统一资源定位符url(也可以获取重定向后的跳转url)
  • response.text: 获取请求成功后的响应内容,数据类型为字符串型
  • response.content: 获取请求成功后的响应内容,数据类型为byte型。如果想取图片,文件,则可以通过response.content.
  • response.json(): 返回的是json格式的数据,也就是字典。现在的前后端的数据交互绝大部分都是通过json交互了

4.Cookie和Session

Session对象可以像requests一样调用get和post发起指定的请求,只不过如果使用session发请求的过程中如果产生了cookie,则cookie会被自动存储到该session对象中,那么意味着下一次使用session对象发送请求时,则该次请求就会自动携带cookie进行请求发送

在爬虫中使用session的时候,session对象至少会被使用几次?

至少两次:第一次使用session是为了将cookie捕获并存储到session对象中,下次的时候就会自动携带cookie进行发送

1
2
3
4
5
6
7
8
9
10
import requests
# 两次 get 请求, 没有任何关联,不可以
requests.get("http://httpbin.org/cookies/set/number/123456789") # 第一次请求
response = requests.get("http://httpbin.org/cookies") # 第二次请求
print(response.text)
"""
{
“cookies”: {}
}
"""

我们可以看到利用cookie模拟登陆时,两次访问,没有存储登录的状态。但我们利用 Session 对象,可以模拟登录:
第一利用session登录,存储浏览器信息,再发送请求,访问目标网站

1
2
3
4
5
6
7
8
9
10
11
import requests
# Session 对象, 相当于在一个浏览器中先后访问(例如:登录验证)
session = requests.Session()
result = session.get("http://httpbin.org/cookies/set/number/123456789")
response = session.get("http://httpbin.org/cookies")
print(response.text)
"""
{
“cookies”: {“number”: “123456789”}
}
"""

5.Cookie基础详细

      由前面我们已经知道了使用requests库的响应中可以获取cookie值,但却存在多种cookie写法

  1. response.cookie获取的是如下这种形式的cookieJar类(此种形式的cookie必须放置在response = requests.post(url=url, headers=headers, data=data, cookies=cookies)里面,而不是像以前一样放置在headers里面
1
2
3
4
5
6
<RequestsCookieJar[
<Cookie X_HTTP_TOKEN=42daf4b72327b2813774136851bf5e71415983ed09 for .lagou.com/>,
<Cookie user_trace_token=20200408105933-6470e1a5-1be3-4b1a-85c4-2cf2ced07646 for .lagou.com/>,
<Cookie JSESSIONID=ABAAAECABBJAAGIEB8B11EEB347561D234F0B9E026FE063 for www.lagou.com/>,
<Cookie SEARCH_ID=aff2447a4a0543a8bed59c906e97ba8a for www.lagou.com/>
]>

  1. response.cookie.get_dict():就是将cookieJar形式的cookie变为字典格式(字典格式,读取保存为json文件,以此来读写json,然后放置到headers请求头里)
{
    'X_HTTP_TOKEN': '42daf4b72327b2813774136851bf5e71415983ed09', 
    'user_trace_token': '20200408105933-6470e1a5-1be3-4b1a2ced07646', 
    'JSESSIONID': 'ABAAAECABBJAAGIEB8B11EEB347561D234F0B9E026FE063', 
    'SEARCH_ID': 'aff2447a4a0543a8bed59c906e97ba8a'
}

  1. requests.utils.dict_from_cookiejar(response.cookies):同理也是将cookieJar形式的cookie变为字典格式(字典格式,读取保存为json文件,以此来读写json,然后放置到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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# -*- coding:utf-8 -*-
import requests
import os
import json

"""
三种Cookie请求方式:
第一种:cookie放在headers中
第二种:cookie字典传给cookies参数
第三种:先发送post请求,获取cookie,带上cookie请求登陆之后的页面
"""

# cookie的读取(先判断cookie文件是否存在,若存在直接读取填入headers中,若不存在,则需要模拟登录后保存cookie)
COOKIE_PATH = 'xxx.json'
# to check whether it exist
if os.path.exists(COOKIE_PATH):
# to load the file of cookie
with open(COOKIE_PATH, 'r') as f:
cookie_ct = json.loads(f.read())

headers = {
'User-Agent': 'xxxxxx',
'Host': 'www.baidu.com',
'Cookie': cookie_ct,
}
try:
# try to load some website
session = requests.session()
response = session.get(url='www.baidu.com', headers=headers, timeout=0.1)
if response.status_code == 200:
print(response.content)
except Exception as e:
print(e)

"""
assume the cookie is not existing:
so,we need to send request_POST ,and get the cookies,
finally,we should load the website with the cookies
"""
headers = {
"User-Agent": 'dddddddd',
}
session = requests.session()
# the post_url can be found in the form or capture the url
post_url = 'http://www.renren.com/PLogin.do'
data = {
'name': 'chd',
'age': 18,
'password': 'chen111',
}
res = session.post(url=post_url, headers=headers, data=data, timeout=0.1)
# 请求失败抛出
if (res.status_code != 200):
raise Exception("登录失败!")

# 获取cookie
cookies_ct = requests.utils.dict_from_cookiejar(session.cookies)
# 将cookie保存至本地文件
with open(COOKIE_PATH, "w",encoding="utf-8") as f:
f.write(json.dumps(cookies_ct))

参考文章


 评论

联系我 | Contact with me

Copyright © 2019-2020 谁知你知我,我知你知深。此恨经年深,比情度日久

博客内容遵循 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 协议