HTTP协议
在开始介绍Requests库和爬虫之前,首先需要先多了解了解HTTP协议,这里就不过多的介绍了,有熟悉HTTP的可以略过,不熟悉的HTTP的可以点击下面地址,去详细的了解以下。
同时推荐一个学习HTTP的书,HTTP权威指南。
Requests介绍及基本使用
Requests是一个简单且优雅的Python HTTP库,相较于Python标准库中的urllib和urllib2的库,Requests更加的便于理解使用。
Requests是Python的第三方库,也是目前公认爬取网页最好的第三方库,使用起来非常简单,简洁。
Requests的安装
# 直接使用pip进行安装即可
pip install requests
Requests安装非常简单,有任何问题,可通过官网查询学习。
https://requests.readthedocs.io/en/master/
检查Requests是否安装成功
>>> import requests
>>> r = requests.get("https://fdevops.com")
>>> r.status_code
200
>>> r.encoding = 'utf-8'
>>> r.text
'<!DOCTYPE html><html lang="zh-CN"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1"><meta name="renderer" content="webkit"><meta name="viewport" content="initial-scale=1.0,user-scalable=no,maximum-scale=1,width=device-width"><link media="all" href="https://fdevops.com/wp-content/cache/autoptimize/css/autoptimize_e29d02f3d2c20b556652ce02cee3d2e7.css" rel="stylesheet" /><title>兰玉磊的技术博客</title><meta name="keywords" content="人工智能...
Requests库的7个主要的方法
方法 | 说明 |
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 |
在Requests库中有两个非常重要的对象,Request和Response。
- Request是请求相关的所有资源
- Response是请求返回的所有资源,在爬虫的过程中占据了非常重要的位置
Requests简单的请求过程
- 首先向指定的url发送GET请求,Requests会构造一个向服务器请求资源的Request对象。
- 当请求送达后,Requests库会接收到服务器返回的一个包含服务器资源的Response对象,这个Response对象就包含了从服务器返回的所有相关资源,包括请求状态,请求的HTML内容等等。
Response对象最常用的5个属性
属性 | 说明 |
r.status_code | HTT请求的返回状态,200表示成功,400表示失败,其他状态值,请查看https://fdevops.com/2020/03/14/http-all-code |
r.text | HTTP响应内容的字符串形式,即URL对应的页面内容 |
r.encoding | 从HTTP header中猜测的相应内容编码方式 |
r.apparent_encoding | 从内容中分析出的相应内容编码方式(备选编码方式) |
r.content | HTTP响应内容的二进制形式 |
Requests库的方法介绍
requests.request(method, url, **kwargs)
method: 请求方式,对应get/put/post等7种
url: 获取的页面数据的url链接地址
**kwargs: 控制访问的参数,均为可选项,共13个
requests.request() 参数 method
的请求方式。
r = requests.request("GET", url, **kwargs)
r = requests.request("HEAD", url, **kwargs)
r = requests.request("POST", url, **kwargs)
r = requests.request("PUT", url, **kwargs)
r = requests.request("PATCH", url, **kwargs)
r = requests.request("DELETE", url, **kwargs)
r = requests.request("OPTIONS", url, **kwargs)
equests.request() 中的url
参数就想说了,就是一个你需要爬取的链接地址。
requests.request() 中的**kwargs
参数解析。
params: 字典或字节序列,作为参数增加到url中。
>>> kv = {"a": 1, "b": 2}
>>> r = requests.request("GET", "https://fdevops.com", params=kv)
>>> r.url
'https://fdevops.com/?a=1&b=2'
data: 字典、字节序列或者文件对象,作为Request对象的内容
>>> kv = {"a": 1, "b": 2}
>>> r = requests.request("POST", "https://fdevops.com", data=kv)
>>> body = "测试内容"
>>> r = requests.request("POST", "https://fdevops.com", data=body.encode('utf-8'))
>>>
json: JSON格式的数据,作为Request的内容
>>> kv = {"a": 1, "b": 2}
>>> r = requests.request("POST", "https://fdevops.com", json=kv)
headers: 字典格式的数据,定制HTTP头数据
>>> hd = {"user-agent": 'Chrome/10'} # 定制headers里的user-agent
>>> r = requests.request("POST", "https://fdevops.com", headers=hd)
cookies: 字典或者CookieJar格式,Request中的cookie,从HTTP中解析cookie
auth: 元组,支持HTTP认证功能
files: 字典类型,进行传输文件的时候使用的字段参数
>>> fs = {"file", open("demo.txt", "rb")}
>>> r = requests.request("POST", "https://fdevops.com", files=fs)
timeout: 设置超时时间,单位为秒
>>> r = requests.request("GET", "https://fdevops.com", timeout=10)
proxies: 字典类型,设置访问代理服务器,可以增加登陆认证,可以有效的隐藏源访问的IP地址,有效的防止对爬虫的逆追踪
>>> pxs = {"http": "http://user:pass@192.168.1.1:8000",
"https": "https://192.168.1.1:8001"}
>>> r = requests.request("GET", "https://fdevops.com", proxies=pxs)
allow_redirects: True/False,默认为True,重定向的开关
stream: True/False,默认为True,对获取的内容是否立即下载的开关
verify: True/False,默认为True,认证SSL证书的开关
cert: 本地SSL证书的路径
requests.get(url, params=None, **kwargs)
url: 获取的页面数据的url链接地址
params: url中的额外参数,字典或者字节流格式,可选参数
**kwargs: 12个控制访问的参数,请参考requests.requests()的**kwargs参数解析
requests.head(url, **kwargs)
url: 获取的页面数据的url链接地址
**kwargs: 13个访问控制参数,请参考requests.requests()的**kwargs参数解析
requests.post(url, data=None, json=None, **kwargs)
url: 获取的页面数据的url链接地址
data: 字典、字节序列或者文件对象,作为Request对象的内容
json: JSON格式的数据,作为Request的内容
**kwargs: 11个访问控制参数,请参考requests.requests()的**kwargs参数解析
requests.put(url, data=None, **kwargs)
url: 获取的页面数据的url链接地址
data: 字典、字节序列或者文件对象,作为Request对象的内容
**kwargs: 12个访问控制参数,请参考requests.requests()的**kwargs参数解析
requests.patch(url, data=None, **kwargs)
url: 获取的页面数据的url链接地址
data: 字典、字节序列或者文件对象,作为Request对象的内容
**kwargs: 12个访问控制参数,请参考requests.requests()的**kwargs参数解析
requests.delete(url, **kwargs)
url: 获取的页面数据的url链接地址
**kwargs: 13个访问控制参数,请参考requests.requests()的**kwargs参数解析
爬取网页的通用代码结构
在我们写爬虫程序的时候,需要按照一个的顺序去处理程序返回的Response对象属性,如下图所示:
通过实际的例子演示一下
>>> import requests
>>> r = requests.get("https://baidu.com")
>>> r.status_code # 状态码
200
>>> r.text # 网页内容
'<!DOCTYPE html>\r\n<!--STATUS OK--><html> <head><meta http-equiv=content-type content=text/html;charset=utf-8><meta http-equiv=X-UA-Compatible content=IE=Edge><meta content=always name=referrer><link rel=stylesheet type=text/css href=http://s1.bdstatic.com/r/www/cache/bdorz/baidu.min.css><title>ç\x99¾åº¦ä¸\x80ä¸\x8bï¼\x8cä½\xa0å°±ç\x9f¥é\x81\x93</title></head> <body link=#0000cc> <div id=wrapper> <div id=head> <div class=head_wrapper> <div class=s_form> <div class=s_form_wrapper> <div id=lg> <img hidefocus=true src=//www.baidu.com/img/bd_logo1.png width=270 height=129> </div> ...'
>>> r.encoding # 网页编码,若是header中不存在charset字段,则默认为'ISO-8859-1',这种编码格式不支持中文
'ISO-8859-1'
>>> r.apparent_encoding # 根据页面内容得到的编码格式
'utf-8'
>>> r.encoding = r.apparent_encoding # 将编码格式替换成备用的编码格式
>>> r.encoding
'utf-8'
>>> r.text # 用新的编码格式,获取的内容就支持中文了。
'<!DOCTYPE html>\r\n<!--STATUS OK--><html> <head><meta http-equiv=content-type content=text/html;charset=utf-8><meta http-equiv=X-UA-Compatible content=IE=Edge><meta content=always name=referrer><link rel=stylesheet type=text/css href=http://s1.bdstatic.com/r/www/cache/bdorz/baidu.min.css><title>百度一下,你就知道</title></head> <body link=#0000cc> <div id=wrapper> <div id=head> <div class=head_wrapper> <div class=s_form> <div class=s_form_wrapper> <div id=lg> <img hidefocus=true src=//www.baidu.com/img/bd_logo1.png width=270 height=129> </div> ...'
>>>
通过上面的例子,可以看出如果编码不正确则无法正确的解析数据,而出现乱码的情况。
因为r.encoding
是通过headers
中的charset
来得到的,如果headers
中存在这个字段则是对应的编码格式,如果没有这个字段呢,则默认是ISO-8859-1
,而这种编码格式是无法解析中文,因此会出现中文乱码。
r.apparent_encoding
是根据返回的页面数据来获得的备用编码格式的,因此当出现返回乱码的时候,使用r.apparent_encoding
替换掉r.encoding
即可。
其实严格来说,r.apparent_encoding
比r.encoding
得到的编码格式更加准确,因为r.apparent_encoding
会去分析内容,而r.encoding
不会,仅仅只是通过headers
中`charset`而得到。
编码的简单介绍
- ISO-8859-1 属于单字节编码,最多能表示的字符范围是0-255,应用于英文系列。比如,字母a的编码为0x61=97。很明显,ISO-8859-1编码表示的字符范围很窄,无法表示中文字符。但是,由于是单字节编码,和计算机最基础的表示单位一致,所以很多时候,仍旧使用ISO-8859-1编码来表示。而且在很多协议上,默认使用该编码。
- Unicode(统一码、万国码、单一码)是计算机科学领域里的一项业界标准,包括字符集、编码方案等。Unicode 是为了解决传统的字符编码方案的局限而产生的,它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。1990年开始研发,1994年正式公布。
- UTF-8(8位元,Universal Character Set/Unicode Transformation Format)是针对Unicode的一种可变长度字符编码。它可以用来表示Unicode标准中的任何字符,而且其编码中的第一个字节仍与ASCII相容,使得原来处理ASCII字符的软件无须或只进行少部份修改后,便可继续使用。因此,它逐渐成为电子邮件、网页及其他存储或传送文字的应用中,优先采用的编码。
Requests中的常用异常
我们在爬取网页的过程中,肯定不会是一直一帆风顺的,会出现各种情况,比如已知网络链接异常,防火墙拦截等等,因此在开发爬虫程序的时候,对异常的处理也是非常重要的,需知道每种异常的处理方式。
Requests库支持的6中常用异常
异常 | 说明 |
requests.ConnectionError | 网络连接错误异常,如DNS解析失败,拒绝连接等 |
requests.HTTPError | HTTP错误异常 |
requests.URLRequired | URL缺失异常 |
requests.TooManyRedirects | 超过最大重定向次数,产生重定向异常 |
requests.ConnectTimeout | 连接远程服务器超时异常 |
requests.Timeout | 请求URL超时,产生超时异常 |
Requests中的异常方法
r.raise_for_status() # 如果不是200,产生异常requests.HTTPError
通过一个实际的例子,演示一下:
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 Exception as e:
return "产生异常"
if __name__ == '__main__':
url = "https://baidu.com"
print(getHTMLText(url))
可以把上面的实例看成一个爬虫代码的简单结构。