文章目录
一、requests简介及安装
1. 简介
Requests库是由python语言基于urllib编写的,采用的是Apache2 Licensed开源协议的HTTP库,它在做网络请求上会比urllib使用更加方便。
2. 安装
直接使用pip安装即可
pip install requests
二、requests使用方法介绍
1. 请求方式
requests
包含多种请求方式:
- GET- 请求页面,并返回页面内容
- POST- 大多用于提交表单或上传文件,数据包含在请求体中
- HEAD- 类似于GET请求,只不过返回的响应中没有具体的内容,用于获取报头
- PUT- 从客户端向服务器传送的数据取代指定文档中的内容
- DELETE- 请求服务器删除指定的页面
- CONNECT- 把服务器当作跳板,让服务器代替客户端访问其他网页
- OPTIONS- 允许客户端查看服务器的性能
- TRACE- 回显服务器收到的请求,主要用于测试或诊断
2. 基本用法
这里只介绍常用的GET请求和POST请求
2.1 GET请求
GET请求中的参数包含在URL里面,并且数据是明文的,可以在URL中看到。
GET请求提交的数据最多只有1024字节。
以实验网址为例(http://httpbin.org/get
)
基本请求:
import requests
r = requests.get(url='http://httpbin.org/get') # 使用GET请求访问
print(r.text) # 打印网页的HTML文本
打印结果:
{
"args": {},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate",
"Host": "httpbin.org",
"User-Agent": "python-requests/2.22.0"
},
"origin": "12.192.229.251, 12.192.229.251",
"url": "https://httpbin.org/get"
}
可以发现,我们成功的发起了GET请求,返回结果中包含请求头
、URL
、IP
等信息。
那么,对于GET请求,如果要附加额外的信息,要怎么添加呢?
使用params参数构造带请求参数的GET请求:
import requests
# 请求参数
params = {
'name': 'Evan',
'age': '24'
}
r = requests.get(url='http://httpbin.org/get', params=params) # 带请求参数的GET请求
print(r.text)
打印结果:
{
"args": {
"age": "24",
"name": "Evan"
},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate",
"Host": "httpbin.org",
"User-Agent": "python-requests/2.22.0"
},
"origin": "12.192.229.251, 12.192.229.251",
"url": "https://httpbin.org/get?name=Evan&age=24"
}
可以看到设置的params
参数已经起作用了,不过还有一种方法也可以提供请求参数,就是构建完整的URL,因为GET请求的参数会包含在URL里面。
使用 urlencode模块 将字典序列化为GET请求参数:
import requests
from urllib.parse import urlencode
# 请求参数
params = {
'name': 'Evan',
'age': '24'
}
r = requests.get(url='http://httpbin.org/get?' + urlencode(params))
print(r.text)
打印结果:
{
"args": {
"age": "24",
"name": "Evan"
},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate",
"Host": "httpbin.org",
"User-Agent": "python-requests/2.22.0"
},
"origin": "12.192.229.251, 12.192.229.251",
"url": "https://httpbin.org/get?name=Evan&age=24"
}
可以看到结果和使用params
参数的GET请求是一样的。
2.2 POST请求
POST请求大多在表单提交时发起。比如一个登陆表单,输入用户名和密码后,点击“登陆”按钮,这通常会发起一个POST请求,其数据通常以表单的形式传输,表单数据会放在请求体中,而不会体现在URL中,所以提交的数据是保密的,不会泄露敏感信息,并且 POST请求提交的数据大小没有限制。
以实验网址为例(http://httpbin.org/post
)
基本请求:
import requests
# 请求参数
data = {
'name': 'Evan',
'age': '24'
}
r = requests.post(url='http://httpbin.org/post', data=data) # 使用POST请求访问
print(r.text)
打印结果:
{
"args": {},
"data": "",
"files": {},
"form": {
"age": "24",
"name": "Evan"
},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate",
"Content-Length": "16",
"Content-Type": "application/x-www-form-urlencoded",
"Host": "httpbin.org",
"User-Agent": "python-requests/2.22.0"
},
"json": null,
"origin": "12.192.229.251, 12.192.229.251",
"url": "https://httpbin.org/post"
}
可以发现,其中form
部分就是我们提交的数据,这就证明POST请求成功发送了。
requests还可以模拟提交一些数据,比如上传文件,要怎么添加呢?
使用files参数构造带上传文件的POST请求:
import requests
files = {'file': open('haimianbaobao.ico', 'rb')} # 文件路径
r = requests.post(url='http://httpbin.org/post', files=files) # 带上传文件的POST请求
print(r.text)
打印结果:
{
"args": {},
"data": "",
"files": {
"file": "data:application/octet-stream;base64,R0lGODlhkQCCAHAAACH5BABBAAAALAAAAA...="
},
"form": {},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate",
"Content-Length": "8732",
"Content-Type": "multipart/form-data; boundary=c15f3180298f305a48359831993ed6b8",
"Host": "httpbin.org",
"User-Agent": "python-requests/2.22.0"
},
"json": null,
"origin": "12.192.229.251, 12.192.229.251",
"url": "https://httpbin.org/post"
}
以上省略部分内容,可以发现,里面包含files
这个字段,而form
字段是空的,这证明文件上传部分会单独有一个files
字段来标识。
3. 高级用法
现在大部分网站都有反爬机制,所以在请求网页的时候一般都要添加请求头才可以得到响应,某些网站限制登陆时还要设置cookies等,下面介绍一些常用的高级用法。(POST请求和GET请求同理,这里以GET请求为例
)
3.1 添加请求头
请求头,用来说明服务器要使用的附加信息,比较重要的信息有Cookie、Referer、User-Agent等
下面简要说明一些常用的请求头信息:
- Accept- 请求报头域,用于指定客户端可接受哪些类型的信息。
- Accept-Language- 指定客户端可接受的语言类型
- Accept-Encoding- 指定客户端可接受的内容编码
- Host- 用于指定请求资源的主机IP和端口号,其内容为请求URL的原始服务器或网关的位置
- Cookie- 也常用复数形式Cookies,它的主要功能是维持当前访问会话,服务器会用会话保存登陆状态信息
- Referer- 此内容用来标识这个请求是从哪个页面发过来的,服务器可以拿这一信息做相应的处理,如做来源统计,放盗链处理等
- User-Agent- 简称UA,它是一个特殊的字符串头,可以使服务器识别客户使用的操作系统及版本、浏览器及版本等信息。在做爬虫时加上此信息,可以伪装为浏览器,如果不加,很可能会被识别出为爬虫
- Content-Type- 也叫互联网媒体类型(Internet Media Type)或者MIME类型,它用来表示具体请求中的媒体类型信息。例如,text/html代表HTML格式,image/gif代表GIF图片,application/json代表JSON类型等
看到这相信你已经了解请求头中大部分参数的含义了,现在开始用程序实现这些功能
使用headers参数添加”User-Agent“:
import requests
# 请求头参数
headers = {
"User-Agent": 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/78.0.3904.108 Safari/537.36'
}
r = requests.get(url='http://httpbin.org/get', headers=headers) # 带请求头的GET请求
print(r.text)
打印结果:
{
"args": {},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate",
"Host": "httpbin.org",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36"
},
"origin": "12.192.229.251, 12.192.229.251",
"url": "https://httpbin.org/get"
}
可以看到,“User-Agent”
已经被添加上去了,所以添加请求头很简单,只要添加headers
参数即可,headers
是一个字典类型,根据需求填入相应的请求头信息就可以轻松的提交各种请求方式了。
3.2 会话维持
说到会话维持,第一想到的就是使用cookies,网页为什么能保持会话,在登陆后不用重新登陆,就是因为cookies保持会话了,所以我们想要会话维持就要在请求头中添加对应的cookies,但是问题来了,如果每次在请求的时候都去添加cookies,这未免也太麻烦了吧,所以requests有一个新的利器-Session对象
,利用它,我们可以方便地维护一个会话,而且不用担心cookies的问题,它会帮我们自动处理好。
示例如下:
没有使用Session之前:
import requests
# 第一次访问,并设置cookies
r1 = requests.get(url='http://httpbin.org/cookies/set/number/123456789')
print('r1: {}'.format(r1.text))
# 第二次访问
r2 = requests.get(url='http://httpbin.org/cookies')
print('r2: {}'.format(r2.text))
打印结果:
r1: {
"cookies": {
"number": "123456789"
}
}
r2: {
"cookies": {}
}
这里我们请求了一个测试网址(http://httpbin.org/cookies/set/number/123456789
)
请求这个网址时,可以设置一个cookie,名称叫做number,内容是123456789,
随后又请求了(http://httpbin.org/cookies
),此网址可以获取当前的Cookies,但是看打印结果cookies为空,所以使用2次requests是相当于打开两个浏览器,这两次requests的内容是不共享的。
接下来看使用Session的例子:
import requests
# 实例化Session对象
s = requests.Session()
# 第一次访问,并设置cookies
r1 = s.get(url='http://httpbin.org/cookies/set/number/123456789')
print('r1: {}'.format(r1.text))
# 第二次访问
r2 = s.get(url='http://httpbin.org/cookies')
print('r2: {}'.format(r2.text))
打印结果:
r1: {
"cookies": {
"number": "123456789"
}
}
r2: {
"cookies": {
"number": "123456789"
}
}
成功获取!所以需要登陆某些网站传递登陆信息时就使用Session
对象来保持同一个会话,这样就免去了每次要设置cookies的烦琐了。
3.3 代理设置
对于某些网站,在测试的时候请求几次能正常获取内容,但是一旦开始大规模爬取,网站可能会弹出验证码,或者跳转到登陆认证页面,更甚至可能会直接封禁客户端的IP,导致一定时间段内无法访问,那么,为了防止这种情况发生,我们需要设置代理来解决这个问题。
使用proxies参数设置代理:
import requests
# 使用普通格式
proxies = {"http": "http://10.10.1.10:3128", "https": "http://10.10.1.10:1080"}
# 使用HTTP Basic Auth格式
proxies = {"http": "http://user:[email protected]:3128"}
# 使用SOCKS协议(需要安装 'requests[socks]' 模块)
proxies = {"http": "socks5://user:password@host:port", "https": "socks5://user:password@host:port"}
requests.get('http://httpbin.org/get', proxies=proxies) # 使用代理的GET请求
当然,直接运行这个实例可能不行,因为这些代理IP可能是无效的,这里只讲解proxies
的使用格式和方法,具体大家可以去代理IP网站下载免费的代理或者付费的代理试验。
3.4 超时设置
在本机网络状况不好或者服务器网络响应太慢时,我们可能会等待很久的时间才能收到响应,这个时候就可以使用timeout
参数,这个时间的计算是从发出请求到服务器响应的时间。
示例如下:
import requests
r = requests.get(url='http://httpbin.org/get', timeout=1)
print(r.text)
打印结果:
Traceback (most recent call last):
File "C:/Evan/my_program/shining_star/trunk/unit_testing/test1.py", line 20, in <module>
r = requests.get(url='http://httpbin.org/get', timeout=1)
File "C:\pycharm_user\venv\lib\site-packages\requests\api.py", line 75, in get
return request('get', url, params=params, **kwargs)
File "C:\pycharm_user\venv\lib\site-packages\requests\api.py", line 60, in request
return session.request(method=method, url=url, **kwargs)
File "C:\pycharm_user\venv\lib\site-packages\requests\sessions.py", line 533, in request
resp = self.send(prep, **send_kwargs)
File "C:\pycharm_user\venv\lib\site-packages\requests\sessions.py", line 646, in send
r = adapter.send(request, **kwargs)
File "C:\pycharm_user\venv\lib\site-packages\requests\adapters.py", line 529, in send
raise ReadTimeout(e, request=request)
requests.exceptions.ReadTimeout: HTTPConnectionPool(host='httpbin.org', port=80): Read timed out. (read timeout=1)
通过这样的方式,我们可以将超时时间设置为1秒,如果在1秒内没有收到响应,那就抛出异常,还可以加上try-except
进行异常处理,防止等待过长而浪费时间,我们还可以直接设置为None
,或者不设置直接留空,因为默认也是None
,这样的话表示永久等待下去,直到收到服务器响应结果。
3.5 身份认证
在访问某些网站时,我们可能会遇到如下图所示,弹出一个输入框提示身份验证,此时可以使用auth
参数添加用户名和密码进行认证。
示例如下:
import requests
r = requests.get('http://localhost:5000', auth=('username', 'password'))
print(r.text)
auth
参数是一个元组,该元组第一个参数为用户名,第二个参数为密码,提供这个参数后requests会默认使用HTTPBasicAuth
这个类来认证,这样就可以解除认证,继续访问后续页面了。
4. 响应
当我们使用requests请求网页时,会返回一个response,我们就是要解析这个response,才能拿到我们想要的信息,所以接下来先介绍响应是由哪些信息组成的,然后再介绍怎么用requests获取这些信息。
4.1 响应的组成
响应是指服务器返回客户端的结果,可以分为三个部分:(响应状态码、响应头、响应体)
4.1.1 响应状态码
响应状态码表示服务器的响应状态,如200
代表服务器正常响应,404
代表页面未找到,500
代表服务器内部发生错误。在爬虫中,我们可以根据状态码来判断服务器的响应状态然后再进行下一步的处理。
下面列出一些常见的状态码供参考:
- 200- 【
成功
】服务器已经成功处理了请求 - 301- 【
永久移动
】请求的网页已永久移动到新位置,即永久重定向 - 302- 【
临时移动
】请求的网页暂时跳转到其他页面,即暂时重定向 - 400- 【
错误请求
】服务器无法解析该请求 - 401- 【
未授权
】请求没有进行身份验证或验证未通过 - 403- 【
禁止访问
】服务器拒绝此请求 - 404- 【
未找到
】服务器找不到请求的网页 - 408- 【
请求超时
】服务器请求超时 - 410- 【
已删除
】请求的资源已永久删除 - 500- 【
服务器内部错误
】服务器遇到错误,无法完成请求 - 502- 【
错误网关
】服务器作为网关或代理,从上游服务器收到无效响应 - 503- 【
服务不可用
】服务器当前无法使用 - 504- 【
网关超时
】服务器作为网关或代理,但是没有及时从上游服务器收到请求 - 505- 【
HTTP版本不支持
】服务器不支持请求中所有的HTTP协议版本
4.1.2 响应头
响应头包含了服务器对请求的应答信息,如Content-Type
、Server
、Set-Cookie
等。
下面简要说明一些常用的响应头信息:
- Date- 标识响应产生的时间
- Last-Modified- 指定资源的最后修改时间
- Content-Encoding- 指定响应内容的编码
- Server- 包含服务器的信息,比如名称、版本号等
- Content-Type- 文档类型,指定返回的数据类型是什么,如
text/html
代表返回HTML文档,application/x-javascript
则代表返回JavaScript文件,image/jpeg
则代表返回图片 - Set-Cookie- 设置Cookies,响应头中的
Set-Cookie
告诉浏览器需要将此内容放在Cookies中,下次请求携带Cookies请求 - Expires- 指定响应的过期时间,可以使代理服务器或浏览器将加载的内容更新到缓存中,如果再次访问时,就可以直接从换从中加载,降低服务器负载,缩短加载时间
4.1.3 响应体
响应体是最重要的内容,响应的正文数据都是在响应体中,比如请求网页时,它的响应体就是网页的HTML代码,请求一张图片时,它的响应体就是图片的二进制数据,在做爬虫时,我们主要通过响应体得到网页的源代码,JSON数据等,然后从中做相应内容的提取。
当然,在我们不使用爬虫时也可以直接看到响应体(也就是网页源代码),所以在开始写爬虫前应先看一遍网页源代码,了解自己要抓取哪些信息,这些信息放在哪个位置等等。
下面介绍一些查看网页源代码的方法:
- 打开浏览器开发者工具(
按F12
),然后在浏览器开发者工具中点击Elements
,就可以看到网页的源代码了,也就是响应体的内容,它是解析的目标 - 在网页上按
鼠标右键
,然后点击查看网页源代码
,这个时候会弹出一个新的窗口,里面的内容就是当前页面的源代码了
4.2 响应的获取
在发送请求后,得到的自然就是响应了,上面我们已经介绍了响应是由哪些信息组成的,现在介绍怎么用requests去获取这些信息。
示例如下:
# -*- coding:utf-8 -*-
import requests
r = requests.get(url='http://httpbin.org/get') # 使用GET请求访问
# 获取网页信息
print('请求的URL: {}'.format(r.url)) # 获取当前URL,返回一个字符串
print('响应状态码: {}'.format(r.status_code)) # 获取响应状态码,返回一个整形
print('响应头部信息: {}'.format(r.headers)) # 获取响应头部信息,返回一个字典
print('响应Cookies: {}'.format(r.cookies)) # 获取响应Cookies,返回一个字典
print('访问的历史记录: {}'.format(r.history)) # 获取访问的历史记录,可以查看是否重定向,返回一个列表
print('网页源代码: {}'.format(r.text)) # 获取网页源代码,返回一个字符串
print('网页二进制数据: {}'.format(r.content)) # 获取网页内容的二进制格式,返回一个二进制数据
print('JSON数据: {}'.format(r.json)) # 如果响应信息是JSON数据则调用此方法,返回一个字典
打印结果:
请求的URL: http://httpbin.org/get
响应状态码: 200
响应头部信息: {'Access-Control-Allow-Credentials': 'true', 'Access-Control-Allow-Origin': '*', 'Content-Encoding': 'gzip', 'Content-Type': 'application/json', 'Date': 'Sat, 21 Dec 2019 13:50:15 GMT', 'Referrer-Policy': 'no-referrer-when-downgrade', 'Server': 'nginx', 'X-Content-Type-Options': 'nosniff', 'X-Frame-Options': 'DENY', 'X-XSS-Protection': '1; mode=block', 'Content-Length': '181', 'Connection': 'keep-alive'}
响应Cookies: <RequestsCookieJar[]>
访问的历史记录: []
网页源代码: {
"args": {},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate",
"Host": "httpbin.org",
"User-Agent": "python-requests/2.21.0"
},
"origin": "119.123.1.99, 119.123.1.99",
"url": "https://httpbin.org/get"
}
网页二进制数据: b'{\n "args": {}, \n "headers": {\n "Accept": "*/*", \n "Accept-Encoding": "gzip, deflate", \n "Host": "httpbin.org", \n "User-Agent": "python-requests/2.21.0"\n }, \n "origin": "119.123.1.99, 119.123.1.99", \n "url": "https://httpbin.org/get"\n}\n'
JSON数据: <bound method Response.json of <Response [200]>>