Request
"HTTP for Humans",意思是让 HTTP 协议服务于人类。在 Request 库官网上写到 "Requests is an elegant and simple HTTP library for Python, built for human beings." 意思是 “Requests是一个针对人类的优雅而简单的Python HTTP库。” 试用之后,深刻体会到这个描述是很贴切的,Request 库不仅小巧,能够轻松实现对 HTML 页面的自动爬取和自动网络请求提交,是 python 网络爬虫必须学习的内容。
说明文档和参考资料
Requests: 让 HTTP 服务人类
Python 网络爬虫与信息提取,北京大学,嵩天
预备知识
URL
在 WWW(world wide web)上,每一信息资源都有统一的且在网上唯一的地址,该地址就叫URL,它是WWW的统一资源定位标志,就是指网络地址。格式为:
protocol :// hostname[:port] / path / [;parameters][?query]#fragment
参数 | 说明 |
---|---|
protocol(协议) | 指定使用的传输协议 |
hostname(主机名) | 存放资源的服务器的域名系统(DNS) 主机名或 IP 地址 |
port(端口号) | 可选,省略时使用方案的默认端口,各种传输协议都有默认的端口号 |
path(路径) | 由零或多个“/”符号隔开的字符串,用来表示主机上的一个目录或文件地址。 |
parameters(参数) | 用于指定特殊参数的可选项 |
query(查询) | 可选,用于给动态网页传递参数 |
fragment(信息片断) | 用于指定网络资源中的片断 |
HTTP 协议
http是一个简单的请求-响应协议,通常运行在TCP之上。指定了客户端可能发送给服务器什么样的消息以及得到什么样的响应。请求和响应消息的头以ASCII码形式给出,消息内容则具有一个类似MIME的格式。HTTP协议对资源有如下操作:
方法 | 说明 |
---|---|
GET | 请求获取URL位置的资源 |
HEAD | 请求获取URL位置资源的响应消息报告,即获得该资源的头部信息 |
POST | 请求向URL位置的资源后附加新的数据 |
PUT | 请求向URL位置存储的一个资源,覆盖原URL位置的资源 |
PATCH | 请求局部更新URL位置的资源,即改变该处资源的部分内容 |
DELETE | 请求删除URL位置存储的资源 |
.get()方法
先上代码再说
使用交互式解释器,直接放一段代码:
import requests
r = requests.get("http://www.xuexi365.com")
r.status_code
r.text
运行结果:
看到超星学习通的页面信息被我们成功爬取到了。
get()方法的语法为:
requests.get(url, params=None, **kwargs)
参数 | 说明 |
---|---|
url | 拟获取页面的url链接 |
params | url中的额外参数,字典或字节流格式,可选 |
**kwargs | 12个控制访问的参数 |
这里我们想要谈的内容比较多。
Request 对象
Request对象的作用是与客户端交互,收集客户端的 Form、Cookies、超链接,或者收集服务器端的环境变量。request 对象是从客户端向服务器发出请求,包括用户提交的信息以及客户端的一些信息。客户端可通过 HTML 表单或在网页地址后面提供参数的方法提交数据,然后服务器通过 request 对象的相关方法来获取这些数据。request 的各种方法主要用来处理客户端浏览器提交的请求中的各项参数和选项。
requests.get("http://www.xuexi365.com")
当我们使用 get() 方法时,就会构造一个向服务器请求资源的 Request 对象。
Response 对象
Response 对象用于动态响应客户端请示,控制发送给用户的信息,并将动态生成响应。Response 对象只提供了一个数据集合 cookie,它用于在客户端写入 cookie 值。若指定的 cookie 不存在,则创建它。若存在,则将自动进行更新。结果返回给客户端浏览器。
get() 方法将会返回一个包含服务器资源的 Response 对象,关于 Response 对象有比较多值得一谈的内容。
response对象的属性
属性 | 说明 |
---|---|
r.status_code | HTTP请求的返回状态,200表示连接成功,404表示失败 |
r.text | HTTP响应内容的字符串形式,即,url对应的页面内容 |
r.encoding | 从HTTP header中猜测的响应内容编码方式 |
r.apparent_encoding | 从内容分析出的响应内容编码方式(备选编码方式) |
r.content | HTTP响应内容的二进制形式 |
例如我们来看看刚才返回的 response 对象的属性:
编码
如果我们爬取百度页面的信息,运行的效果如下所示。
这个信息没法读,查看编码。
也就是说默认编码是“ISO-8859-1”,这个我们是看不懂的,所以改成“utf-8”。
这下我们就能看懂了,当你用默认编码方式看不懂的时候可以改用备选方式,r.apparent_encoding 相比 r.encoding 方法来说会去分析编码的一些特征,因此在大部分情况下前者的编码方式会更准确。
Request 库异常
异常 | 说明 |
---|---|
requests.ConnectionError | 网络连接错误异常,如DNS查询失败、拒绝连接等 |
requests.HTTPError | HTTP错误异常 |
requests.URLRequired | URL缺失异常 |
requests.TooMangRedirects | 超过最大重定向次数,产生重定向异常 |
requests.ConnectTimeout | 连接远程服务器超时异常 |
requests.Timeout | 请求URL超时,产生超时异常 |
r.raise_for_status() | 如果不是200,产生异常requests.HTTPError |
爬取信息的时候是有可能遇到异常的,因此在读取之前,应该先用 r.status_code 检查一下,若值为 200 则为成功爬取,若为 404 或其他则失败。
爬取信息的代码框架
由于爬取信息可能会返回异常,因此我们在进行查看时要先 try-except 一下。
import requests
def getHTMLText(url):
try:
r = requests.get(url, timeout = 30)
r.raise_for_status() #如果状态不是200,引发HTTPError异常#
r.encoding = r.apparent_encoding
return r.text
except:
return "产生异常"
if __name__ == "__main__":
url = "http://www.xuexi365.com"
print(getHTMLText(url))
.request()方法
requests.request(method, url, **kwargs)
从本质上来说,request 库中的其他方法都是调用 .request() 方法来实现的,因此可以认为这个库只有这一种方法,下面我们来详细谈一下。
参数 | 说明 |
---|---|
method | 请求方式 |
url | 拟获取页面的url链接 |
- 请求方式有 'GET'、'HEAD'、'POST'、'PUT'、'PATCH'、'DELETE'、'OPTIONS' 7 种,分别对应 HTTP 协议的 7 种操作。
**kwargs:控制访问的参数,均为可选项,共13个,一个一个来说一下。
params:字典或字节序列,作为参数增加到url中
例如构造一个字典,通过 .request() 方法向网页提交:
kv = {'key1': 'value1', 'key2': 'value2'}
r = requests.request('GET', 'http://www.xuexi365.com', params=kv)
print(r.url)
data:字典、字节序列或文件对象,作为Request的对象
例如构造一个字典和字符串,通过 .request() 方法向网页提交:
kv = {'key1': 'value1', 'key2': 'value2'}
r = requests.request('POST', 'http://www.xuexi365.com', data=kv)
body = '我爱超星'
r = requests.request('POST', 'http://www.xuexi365.com', data=body)
json:JSON格式的数据,作为Request的内容
kv = {'key1': 'value1'}
r = requests.request('POST', 'http://www.xuexi365.com', json=kv)
headers:字典,HTTP定制头
hd = {'user-agent': 'Chrome/10'}
r = requests.request('POST', 'http://www.xuexi365.com', headers=hd)
files:字典类型,传输文件
fs = {'file': open('data.xls','rb')}
r = requests.request('POST', 'http://www.xuexi365.com', files=fs)
timeout:设定超时时间,秒为单位
r = requests.request('GET', 'http://www.xuexi365.com', timeout=10)
proxies:字典类型,设置访问代理服务器,可以增加登录认证
pxs = {'http': 'http://user:pass@10.10.10.1:1234'
'https': 'https://10.10.10.1:4321'}
r = requests.request('GET', 'http://www.xuexi365.com', proxies=pxs)
其他参数
参数 | 说明 |
---|---|
cookies | 字典或 CookieJar,Request 中的 cookie |
auth | 元组,支持HTTP认证功能 |
allow_redirects | True/False,默认为Ture,重定向开关 |
stream | True/False,默认为True,获取内容立即下载开关 |
verigy | True/False,默认为True,认证SSL证书开关 |
cert | 本地SSL证书路径 |
Request 库方法
方法 | 说明 |
---|---|
requests.request() | 构造一个请求,支撑一下各方法的基础方法 |
requests.get() | 获取 HTML 网页的主要方法,对应于 HTTP 的 GET |
requests.head() | 获取 HTML 网页头信息的方法,对应于 HTTP 的 HEAD |
requests.post() | 向 HTML 网页提交 POST 请求的方法,对应于 HTTP 的 POST |
requests.put() | 向 HTML 网页提交 PUT 请求的方法,对应于 HTTP 的 PUT |
requests.patch() | 向 HTML 网页提交局部修改请求,对应于 HTTP 的 PATCH |
requests.delete() | 向 HTML 页面提交删除请求,对应于 HTTP 的 DELETE |
接下来我们看下还没有看过的方法。
获取 HTML 网页头信息: head()
requests.head(url, **kwargs)
参数 | 说明 |
---|---|
url | 拟获取页面的url链接 |
**kwargs | 13个控制访问的参数 |
向 HTML 网页提交 POST 请求: post()
requests.post(url, data=None, json=None, **kwargs)
参数 | 说明 |
---|---|
url | 拟获取页面的url链接 |
data | 字典、字节序列或文件,Request的内容 |
json | JSON格式的数据,Request的内容 |
**kwargs | 11个控制访问的参数 |
向 HTML 网页提交 PUT 请求: put()
requests.put(url, data=None, **kwargs)
参数 | 说明 |
---|---|
url | 拟获取页面的url链接 |
data | 字典、字节序列或文件,Request的内容 |
**kwargs | 12个控制访问的参数 |
向 HTML 网页提交局部修改请求: patch()
requests.patch(url, data=None, **kwargs)
参数 | 说明 |
---|---|
url | 拟获取页面的url链接 |
data | 字典、字节序列或文件,Request的内容 |
**kwargs | 12个控制访问的参数 |
向 HTML 页面提交删除请求: delete()
requests.delete(url, **kwargs)
参数 | 说明 |
---|---|
url | 拟获取页面的url链接 |
**kwargs | 12个控制访问的参数 |
实例
爬京东商品信息
启动交互式解释器:
爬亚马逊商品信息
启动交互式解释器:
返回了异常信息,我们把信息输出来看看。
亚马逊对我们的来路提出了质疑,这是因为亚马逊有审查机制,能阻止非浏览器对网页的访问,用代码检查下:
r.request.headers
也就是说现在 'User-Agent' 的值为 'python-requests/2.23.0',亚马逊可以轻松地知道我们使用了 requests 爬虫。
但是参数 'User-Agent' 是可以修改的,也就是说我们要通过向网页提交一个已修改的字典,让亚马逊误认为我们是浏览器。
可以看到我们已经成功伪装成浏览器,并成功爬取了信息。输出来看看:
向 360 搜索提交关键词
360 搜索的关键词接口是:
https://www.so.com/s?p=keyword
因此我们需要构造一个字典,键为“p”,值为要提交的关键词,然后用 get() 方法提交,启动交互式解释器:
根据返回的 URL, 我们爬取成功。
- 百度有反爬机制,现在已经不能用这种方法提交了!
爬取图片
网页图片链接的格式一般为:
http://www.example.com/picture.jpg
例如我博客上的一张图片链接:
https://img2020.cnblogs.com/blog/1774310/202003/1774310-20200324224617313-1761177311.png
接下来我们要爬取图片并保存在电脑上,启动交互式解释器:
尝试打开文件,成功打开,证明爬取成功,到 D 盘看看,确实多了一个图片文件。
获取 IP 地址归属地
使用iP138来爬取 IP 地址归属地,向网页提交 IP 地址之后的格式为:
http://m.ip138.com/ip.asp?ip=ipaddress
也就是说我们要构造一个字符串,字符串的内容是要获取归属地的 IP 地址,然后向网页提交。启动交互式解释器:
返回 200,说明爬取成功,把爬取的内容输出出来看看:
由此可见,我们提交的 IP 地址所有于百度。