GitOPEN's Home.

《手把手带你学爬虫──初级篇》第2课 Requests库讲解

Word count: 3,953 / Reading time: 17 min
2018/09/14 Share

本教程所有源码下载链接:https://share.weiyun.com/5xmFeUO 密码:fzwh6g

Requests库讲解

简介与安装

Requests是一常用的http请求库,它使用python语言编写,可以方便地发送http请求,以及方便地处理响应结果。

引用官方文档中的第一句话,来对Requests库进行一句话简介:

Requests 唯一的一个非转基因的 Python HTTP 库,人类可以安全享用。

翻译一下,就是:

Requests库使用简单安全,威力无边,老少皆宜。

至于安装,使用pip安装,简直不能更方便了:

1
pip install requests

其他不多说,直接上手!

Requests库的基本用法

体验入门

通过用一个读取百度首页的例子,来体验一下如何在不用浏览器的情况下,读取互联网上的信息。

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


def get_html():
response = requests.get("http://www.baidu.com")
print(response.status_code)
print(response.encoding)
html_text = response.text
with open("baidu.html", "w") as file:
file.write(html_text)
print("write finished.")


if __name__ == '__main__':
get_html()

多次运行程序,控制台下输出的结果有两种,并且在当前文件夹下生成了一个baidu.html的文件,保存了从互联网上读取来的百度首页的内容:

1
2
3
4
5
6
7
8
# HTTP请求状态码
200
# 网页编码
ISO-8859-1
# 响应头信息(headers)
{'Content-Length': '7610', 'Cache-Control': 'private, no-cache, no-store, proxy-revalidate, no-transform', 'Connection': 'keep-alive', 'Content-Type': 'text/html', 'Date': 'Sat, 16 Jun 2018 07:00:11 GMT', 'Keep-Alive': 'timeout=4', 'Last-Modified': 'Mon, 23 Jan 2017 13:27:29 GMT', 'Pragma': 'no-cache', 'Proxy-Connection': 'keep-alive', 'Server': 'bfe/1.0.8.18', 'Set-Cookie': 'BDORZ=27315; max-age=86400; domain=.baidu.com; path=/'}
# 文件写入完毕
write finished.
1
2
3
4
200
UTF-8
{'Content-Length': '12886', 'Cache-Control': 'no-cache', 'Connection': 'keep-alive', 'Content-Type': 'text/html;charset=UTF-8', 'Keep-Alive': 'timeout=4', 'Pragma': 'no-cache', 'Proxy-Connection': 'keep-alive', 'Server': 'Apache-Coyote/1.1', 'Set-Cookie': 'andr_zz=7;domain=.baidu.com;path=/;max-age=600'}
write finished.

输出的结果有两种,是因为每一次服务器都给Requests发送的请求回应了不同的响应信息。这点不重要,这个现象是为了后面讨论response.encoding的用法。

入门例子剖析

HTTP状态码

当你需要访问一个网页时,你的浏览器(这里是Requests库)向网页所在的服务器(百度服务器)发出请求;服务器会返回一个头信息(server header),用以响应浏览器的请求。

常用HTTP请求状态码含义:

状态码 含义
200 请求成功
301 资源被永久转移到其它URL
404 请求的资源不存在
505 内部服务器错误

这些状态码的含义不必死记硬背,可以在需要的时候搜索一下。这里方便参考,给出简记方法:

非正常状态码 简记
1xx 服务器对客户端说:收到了
2xx 服务器对客户端说:合作愉快
3xx 服务器对客户端说:回头见
4xx 服务器对客户端说:你错了
5xx 服务器对客户端说:我错了

更详细的有关用法,只在有需求的时候查阅就可以了。参见《HTTP状态码》

网页编码

当得到的网页编码是ISO-8859-1时,我们在浏览器中打开baidu.html文件,发现是页面中凡是中文的地方都是乱码,如图:

当得到的网页编码是utf-8时,我们在浏览器中打开baidu.html文件,发现是页面是正常的,如图:

总结:

  • 当headers中不存在charset时,response.encoding默认认为编码为ISO-8859-1
  • 当headers中存在charset时,response.encoding显示为headers中charset的编码

头信息

浏览器在与服务器进行交流的过程中,会协商一些参数,用于影响页面的渲染和展示。当浏览器向服务器发送请求的时候,所携带的信息为请求头信息;当服务器向浏览器返回响应信息的时候,携带的信息响应头信息。在浏览器中,我们可以直观的看到这些信息:

这里我们不做详细的讲解,有兴趣的同学可以参考《HTTP教程》

HTTP请求报文(了解)

HTTP请求报文由3部分组成:请求行+请求头+请求体

获取请求报文的方法(Chrome浏览器)如图所示:

Request Headers的内容如下:

1
2
3
4
5
6
7
8
9
10
11
GET / HTTP/1.1
Host: www.baidu.com
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
DNT: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7
Cookie: BAIDUID=2D5F6595F31C411DF5DADEA1C10D8A81:FG=1; BIDUPSID=2D5F6595F31C411DF5DADEA1C10D8A81; PSTM=1529210459; BD_HOME=0; H_PS_PSSID=1446_21122_26350_26432; BD_UPN=123253

图解为:

Requests库也可以帮助我们拿到这些信息,以下代码在ipython中进行。

1
2
3
4
5
6
7
8
9
10
11
12
13
In [20]: r = requests.post('http://httpbin.org/post', data = {'username':'zhangsan','password':'123456'})

In [21]: r.request.method
Out[21]: 'POST'

In [22]: r.request.url
Out[22]: 'http://httpbin.org/post'

In [23]: r.request.headers
Out[23]: {'User-Agent': 'python-requests/2.18.4', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Length': '33', 'Content-Type': 'application/x-www-form-urlencoded'}

In [24]: r.request.body
Out[24]: 'username=zhangsan&password=123456'

Request Headers的字段讲解:

属性名 含义
Accept 请求报文通过该属性告诉服务端,客户端接受什么类型的响应
Cookie HTTP请求发送时,会把保存在该请求域名下的所有cookie值一起发送给web服务器
Referer 先前网页的地址,当前请求网页紧随其后,即来路
Cache-Control 指定请求和响应遵循的缓存机制
Connection 表示是否需要持久连接(HTTP 1.1默认进行持久连接)
Upgrade-Insecure-Requests 让浏览器自动升级请求 (由 http 升级成 https)
User-Agent 浏览器的浏览器身份标识字符串
Accept-Encoding 能够接受的编码方式列表
Accept-Language 能够接受的回应内容的自然语言列表
Accept-Charset 能够接受的字符集

更多具体的请求字段含义,请参考维基HTTP头字段,这里不做详细讲解。

HTTP协议

HTTP协议可是互联网最基础最重要的协议。它可是一门大的学问。我们这里仅仅讲解一些基本概念。

HTTP协议,超文本传输协议,即HyperText Transfer Protocol,是互联网上应用最为广泛的一种网络协议。所有的WWW文件都必须遵守这个标准。

HTTP是一个基于“请求与响应”模式的、无状态的应用层协议。无状态可以理解为:每一个请求与响应没有上下文联系。

对于HTTP协议,我们在日常使用过程中,最直观的就是URL,即统一资源定位符。它的格式为:http://host[:port][path]。URL是通过HTTP协议存取互联网资源的路径,一个URL对应一个数据资源。

HTTP协议的请求方法,常用的有6种,Requests的几个常用方法是和这个对应的:

方法名 含义
GET 请求获取URL位置的资源
POST 向指定资源提交数据进行处理请求(例如提交表单或者上传文件)
HEAD 向服务器请求与GET请求相一致的响应,只不过响应体将不会被返回。这一方法可以再不必传输整个响应内容的情况下,就可以获取包含在响应小消息头中的元信息。
PUT 向指定资源位置上传其最新内容,覆盖原资源
DELETE 请求服务器删除URL定位的资源
PATCH 请求局部更新URL定位的资源,节省网络带宽

Requests库常用方法入门

需要知道的7个方法:

方法名称 意义
requests.request() 构造一个请求。它是基础方法
requests.get() 发送Get请求获取网页信息, 并返回实体主体,也可以提交数据,包含在url中
requests.post() 向指定资源提交数据进行处理请求(提交表单或者上传文件),数据被包含在请求体中
requests.head() 类似于get请求,返回的响应中没有具体的内容,用于获取报头
requests.put() 发送PUT请求的方法, 从客户端向服务器传送的数据取代指定的文档的内容。
requests.patch() 发送PATCH(局部修改)请求的方法
requests.delete() 发送DELETE(删除)请求的方法, 请求服务器删除指定的资源

在实际编写爬虫的时候,最最常用的也就是加粗显示的3个方法。下面,我们在ipython中测试使用这几个方法。

requests.head()使用方法

获取响应头信息,没有返回内容体。

1
2
3
4
5
6
7
8
9
10
11
$ ipython
Python 3.6.5 (default, Mar 30 2018, 06:42:10)
Type 'copyright', 'credits' or 'license' for more information
IPython 6.4.0 -- An enhanced Interactive Python. Type '?' for help.

In [1]: import requests

In [2]: r = requests.head('http://httpbin.org/get')

In [3]: r.headers
Out[3]: {'Content-Length': '208', 'Access-Control-Allow-Credentials': 'true', 'Access-Control-Allow-Origin': '*', 'Connection': 'keep-alive', 'Content-Type': 'application/json', 'Date': 'Sat, 16 Jun 2018 10:44:44 GMT', 'Keep-Alive': 'timeout=4', 'Proxy-Connection': 'keep-alive', 'Server': 'gunicorn/19.8.1', 'Via': '1.1 vegur'}

requests.post()

向URL用POST请求发送一个字典,自动编码为form表单数据。

1
2
3
4
5
6
In [4]: payload = {'key1': 'value1','key2': 'value2'}

In [5]: r = requests.post('http://httpbin.org/post',data = payload)

In [6]: print(r.text)
{"args":{},"data":"","files":{},"form":{"key1":"value1","key2":"value2"},"headers":{"Accept":"*/*","Accept-Encoding":"gzip, deflate","Connection":"close","Content-Length":"23","Content-Type":"application/x-www-form-urlencoded","Host":"httpbin.org","User-Agent":"python-requests/2.18.4"},"json":null,"origin":"45.77.28.136","url":"http://httpbin.org/post"}

form字段:

1
"form":{"key1":"value1","key2":"value2"}

向URL用POST请求发送一个字符串,自动编码为data。

1
2
3
4
5
6
In [7]: abc = 'ABC'

In [8]: r = requests.post('http://httpbin.org/post',data = abc)

In [9]: print(r.text)
{"args":{},"data":"ABC","files":{},"form":{},"headers":{"Accept":"*/*","Accept-Encoding":"gzip, deflate","Connection":"close","Content-Length":"3","Host":"httpbin.org","User-Agent":"python-requests/2.18.4"},"json":null,"origin":"45.77.28.136","url":"http://httpbin.org/post"}

data字段:

1
"data":"ABC"

requests.put()

该方法和post()方法的使用类似,只不过它可以将原有的数据覆盖掉。

Requests库主要方法解析

requests.request(method,url,**kwargs)

  • method:请求方式,对应get/put/post等7种
  • url:获取页面的url连接
  • kwargs:控制访问的参数,共13个,均为可选项
    因此,将method改为不同的请求方式,将等同于具体的requests请求方法。
    例如:`requests.request(“GET”,url,
    kwargs)等同于requests.get(url,kwargs)`。 kwargs:控制访问的参数,13个可用参数的具体使用方法如下:
  1. params:字典或者字节序列,作为参数增加到url中

    1
    2
    3
    4
    5
    6
    In [10]: kv = {'key1': 'value1','key2': 'value2'}

    In [11]: r = requests.request('GET','http://python123.io/ws', params = kv)

    In [12]: print(r.url)
    https://python123.io/ws?key1=value1&key2=value2
  2. data:字典、字节序列或者文件对象,作为Request的内容。

    1
    2
    3
    4
    5
    6
    7
    In [21]: kv = {'key1': 'value1','key2': 'value2'}

    In [22]: r = requests.request('POST','http://python123.io/ws', data = kv)

    In [23]: body = '主体内容'

    In [24]: r = requests.request('POST','http://python123.io/ws', data = body.encode('utf-8'))
  3. json:JSON格式的数据,作为Request的内容。

    1
    2
    3
    ln [25]: kv = {'key1': 'value1','key2': 'value2'}

    In [26]: r = requests.request('POST','http://python123.io/ws', json = kv)
  4. headers:字典,用来指定请求头。⭐️

    1
    2
    3
    In [27]: hd = {'User-Agent': 'Chrome/10'}

    In [28]: r = requests.request('POST','http://python123.io/ws', headers = hd)
  5. cookies:字典或者CookieJar,Request中的cookie。⭐️

  6. auth:元祖,支持HTTP认证功能。

  7. files:字典类型,传输文件。

    1
    2
    3
    In [35]: fs = {'file': open('baidu.html','rb')}

    In [36]: r = requests.request('POST','http://python123.io/ws', files = fs)
  8. timeout:设定超时时间,单位,秒。⭐️

    1
    In [37]: r = requests.request('GET','http://python123.io/ws', timeout = 10)
  9. proxies:字典类型,设定访问代理服务器,可以增加登录认证。⭐️

    使用这个字段,可以隐藏自己的ip,防止服务器识别爬虫。

    1
    2
    3
    4
    5
    In [40]: pxs = {
    ...: 'http': 'http://user:[email protected]:1234',
    ...: 'https': 'https://10.10.10.10:4321'}

    In [41]: r = requests.request('GET', 'http://www.baidu.com', proxies = pxs)
  10. allow_redirects:它的值为True/False,默认为True,重定向开关。表示,是否允许对url进行重定向。

  11. stream:True/False,默认值为True,获取的内容是否立即下载。默认是立即下载的。

  12. verify:True/False,默认为True,认证SSL证书开关。是否对SSL证书进行认证。

  13. cert:本地SSL证书路径。

Response对象的属性

需要记住的几个属性为:

属性名 含义
response.status_code HTTP响应状态码
response.encoding 从HTTP中charset推断的网页编码方式,如果charset不存在,返回ISO-8859-1
response.apparent_encoding 从响应内容中分析出的内容编码方式
response.content 二进制形式的响应内容,如请求的连接是一个图片等二进制文件,返回的内容用response.content
response.text 字符串形式的响应内容,如请求的连接是一个网页,其内容为html等字符串形式内容,返回的内容用response.text

在爬虫实践中,如果是反复循环迭代大量信息,不建议使用response.apparent_encoding来推断网页编码,因为这个操作非常耗时。因此,通常的做法是,我们在编写爬虫时,提前确定网页的编码方式,然后设置给response.encoding。

Requests库的异常

异常 含义
requests.ConnectionError 网络连接出现异常,如拒绝连接等
requests.HTTPError HTTP错误异常
requests.URLRequired URL缺失异常
requests.TooManyRedirects 请求超过了设定的最大重定向次数
requests.ConnectTimeout 连接远程服务器超时异常
requests.Timeout 请求URL超时,产生超时异常

动手试一试:

在下面的通用代码中,用Exception这个父类,捕捉了所有可能出现的异常。如果将url = "http://www.baidu.com"中的网址写错了,例如将http://去掉,将会报错requests.exceptions.MissingSchema

1
出现异常,类型为:<class 'requests.exceptions.MissingSchema'>,内容为:Invalid URL 'www.baidu.com': No schema supplied. Perhaps you meant http://www.baidu.com?

爬取网页的通用代码示例

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


def get_html(url):
try:
r = requests.get(url, timeout=30)
r.raise_for_status()
r.encoding = r.apparent_encoding
return r.text
except Exception as e:
print("出现异常,类型为:{},内容为:{}", type(e), str(e))


if __name__ == '__main__':
url = "http://www.baidu.com"
result = get_html(url)
print(result)

实战——获取京东商品页面信息

该实验在ipython下进行。

1
2
3
4
5
6
7
8
9
10
11
12
In [1]: import requests

In [2]: r = requests.get("https://item.jd.com/3446665.html")

In [3]: r.status_code
Out[3]: 200

In [4]: r.encoding
Out[4]: 'gbk'

In [5]: r.text[:500]
Out[5]: '<!DOCTYPE HTML>\n<html lang="zh-CN">\n<head>\n <!-- shouji -->\n <meta http-equiv="Content-Type" content="text/html; charset=gbk" />\n <title>【LG27UD58】LG 27UD58-B 27英寸4K IPS硬屏 低闪屏滤蓝光LED背光液晶显示器【行情 报价 价格 评测】-京东</title>\n <meta name="keywords" content="LG27UD58,LG27UD58,LG27UD58报价,LG27UD58报价"/>\n <meta name="description" content="【LG27UD58】京东JD.COM提供LG27UD58正品行货,并包括LG27UD58网购指南,以及LG27UD58图片、27UD58参数、27UD58评论、27UD58心得、27UD58技巧等信息,网购LG27UD58上京东,放心又轻松" />\n <meta name="format-detection" con'

实战——爬取网络图片并存储在本地

该实验在pycharm编辑器中编写并执行:

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
import requests
import os


def get_pic(url):
# Linux、Unix系统路径
# 如果是Windows系统应该写 file_dir = ".//pics//"
file_dir = './pics/'
filename = url.split("/")[-1]
file_path = file_dir + filename
try:
if not os.path.exists(file_dir):
os.mkdir(file_dir)
if not os.path.exists(file_path):
r = requests.get(url, timeout=30)
r.raise_for_status()
with open(file_path, 'wb') as f:
f.write(r.content)
print('文件保存成功')
else:
print('图片已经存在')
except Exception as e:
print("出现异常,类型为:{},内容为:{}".format(type(e), str(e)))


if __name__ == '__main__':
url = "http://image.ngchina.com.cn/2018/0616/20180616123038195.jpg"
get_pic(url)

参考资料推荐


欣慰帮到你 一杯热咖啡
【奋斗的Coder!】企鹅群
【奋斗的Coder】公众号
CATALOG
  1. 1. Requests库讲解
  2. 2. 简介与安装
  3. 3. Requests库的基本用法
    1. 3.1. 体验入门
    2. 3.2. 入门例子剖析
      1. 3.2.1. HTTP状态码
      2. 3.2.2. 网页编码
      3. 3.2.3. 头信息
    3. 3.3. HTTP请求报文(了解)
    4. 3.4. HTTP协议
    5. 3.5. Requests库常用方法入门
      1. 3.5.1. requests.head()使用方法
      2. 3.5.2. requests.post()
      3. 3.5.3. requests.put()
    6. 3.6. Requests库主要方法解析
    7. 3.7. Response对象的属性
    8. 3.8. Requests库的异常
    9. 3.9. 爬取网页的通用代码示例
  4. 4. 实战——获取京东商品页面信息
  5. 5. 实战——爬取网络图片并存储在本地
  6. 6. 参考资料推荐