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

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

Requests库讲解

简介与安装

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

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

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

翻译一下,就是:

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

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

pip install requests

其他不多说,直接上手!

Requests库的基本用法

体验入门

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

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的文件,保存了从互联网上读取来的百度首页的内容:

# 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.
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的内容如下:

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中进行。

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()使用方法

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

$ 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表单数据。

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字段:

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

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

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字段:

"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中 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的内容。 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的内容。 ln [25]: kv = {'key1': 'value1','key2': 'value2'} In [26]: r = requests.request('POST','http://python123.io/ws', json = kv)
  4. headers:字典,用来指定请求头。⭐️ 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:字典类型,传输文件。 In [35]: fs = {'file': open('baidu.html','rb')} In [36]: r = requests.request('POST','http://python123.io/ws', files = fs)
  8. timeout:设定超时时间,单位,秒。⭐️ In [37]: r = requests.request('GET','http://python123.io/ws', timeout = 10)
  9. proxies:字典类型,设定访问代理服务器,可以增加登录认证。⭐️ 使用这个字段,可以隐藏自己的ip,防止服务器识别爬虫。 In [40]: pxs = { ...: 'http': 'http://user:pass@10.10.10.10: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

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

爬取网页的通用代码示例

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下进行。

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编辑器中编写并执行:

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)

参考资料推荐

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏HUBU生信

python爬虫:爬取58同城武汉地区商品房信息(最后碰到了58同城的反爬机制,吓得我不敢说话···)

今天外面天气有些古怪,女朋友明天又要考试,整整一天都在图书馆背书。遇到这种情况,像我这么懒的人,肯定就只有在宿舍玩游戏了。 可是,,,玩游戏真的很无聊耶,我都玩...

72310
来自专栏Python中文社区

用Python抓包工具查看周边拼车情况

作者:Elliot,一个有着全栈幻想的新零售产品经理 Github:https://github.com/bkidy/Dida_spider

32850
来自专栏未闻Code

Tenacity——Exception Retry 从此无比简单

Python 装饰器装饰类中的方法这篇文章,使用了装饰器来捕获代码异常。这种方式可以让代码变得更加简洁和Pythonic。

11930
来自专栏数据科学与人工智能

如何从头开始构建数据科学项目

有许多关于数据科学和机器学习的在线课程将指导您完成理论,并为您提供一些代码示例和对非常干净数据的分析。

14020
来自专栏HUBU生信

(更新)python爬虫实战:模拟登录12306(主要讲解验证码的突破)

刚刚刷完慕课,写完线代作业,现在是时候来一波验证码的突破测试了。在开始之前,我相信有很多朋友会问我:为什么要选择突破12306的验证码? 大家应该都知道,123...

1.6K20
来自专栏未闻Code

如果你不知道做什么,那就学一门杂学吧

多年以后,面对人工智能研究员那混乱不堪的代码,我会想起第一次和S君相见的那个遥远的下午。那时的B公司,还是一个仅有6个人的小团队,Mac和显示器在桌上依次排开,...

12610
来自专栏日常学python

如何爬取美团网美食

工作需求需要采集OTA网站的美食数据,某个城市的饭店类型情况等。对于老饕来说这不算个事。。。然而最后的结果是中午晚饭都没有时间去吃了。。。情况如下

19420
来自专栏三流程序员的挣扎

爬虫笔记2-解析

BeautifulSoup 用于解析已经抓取的文件内容。是解析、遍历、维护“标签树”的功能库。

12410
来自专栏CSDN技术头条

实战 Python 网络爬虫:美团美食商家信息和用户评论

美食是人类的毕生追求,说到美食,我们总会想起美团美食,面对类型众多的商家,应如何选择优质的商家,使消费最大合理化。在本 Chat 里,将讲述如何爬取美团商家信息...

80920
来自专栏机器学习原理

爬取百度问答目的分析网页总结

由于最近再开发问答系统,数据获取是一个问题,所以想通过爬虫爬取百度知道里面的问题和最优答案。

24510

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励