学习一门技术,总是要踩好多坑,然后收货一大堆疑惑,这么多相似的方式该学哪个呢?外面公司常用的是哪个呢?
就比如python爬虫,可以作为网络请求的方式有四种,按时间顺序排:
第一种
urllib2
,这个包是基于python2的,官方已经对python2停止更新了并且不再免费,我觉得这个urllib2没必要再学习和使用第二种
urllib
这个是python的标准库,在python3里整合了python2的urllib
和urllib2
,有时间的可以学习一下。第三种
urllib3
,这个是第三方库,是对第二种方式urllib
的升级,做了很多改善,有时间可以学习一下。第四种也是很流行的
requests
,各种请求的方法非常的优雅和人性化,其底层是urllib3,简化headers、proxy、cookie等的操作。这个重点学习。
作为一个爬虫工程师,如果你连urllib
一点不会就说不过去了。虽然不常用,但是学习它,有它的历史意义,对爬虫的整个架构有一个更透彻的了解。
一、简介
urllib
是Python中请求url连接的官方标准库,在Python2中主要为urllib和urllib2,在Python3中整合成了urllib。基本上涵盖了基础的网络请求功能。
该库有四个模块,分别是urllib.request
,urllib.error
,urllib.parse
,urllib.robotparser
。前三个比较常用。
urllib.request 发送http请求
urllib.error 处理请求过程中,出现的异常。
urllib.parse 解析url
urllib.robotparser 解析robots.txt 文件
二、请求方式
1、get请求
#第一步导包from urllib import request url = "http://httpbin.org"#第二步请求response = request.urlopen(url,timeout=1)#第三步打印返回数据print(response.read().decode())
访问的结果会是一个http.client.HTTPResponse
对象,使用此对象的read()
方法,则可以获取访问网页获得的数据。但是要注意的是,获得的数据会是bytes
的二进制格式,所以需要decode()
一下,转换成字符串格式。
urllib发送请求是用urlopen()
源码如下
urllib.request.urlopen(url, data=None, [timeout, ]*, cafile=None, capath=None, cadefault=False, context=None)
第一个参数 String 类型的地址
data
是 bytes 类型的内容,可通过bytes()
函数或者encode()
转为化字节流。它也是可选参数。使用data
参数,请求方式变成以POST
方式提交表单。使用标准格式是application/x-www-form-urlencoded
timeout
参数是用于设置请求超时时间。单位是秒。cafile
和capath
代表 CA 证书和 CA 证书的路径。如果使用HTTPS则需要用到。context
参数必须是ssl.SSLContext类型,用来指定SSL设置cadefault
参数已经被弃用,可以不用管了。该方法也可以单独传入
urllib.request.Request
对象该函数返回结果是一个
http.client.HTTPResponse
对象。
http.client.HTTPResponse
对象。它具有msg
、version
、status
、reason
、debuglevel
、closed
等属性以及read()
、readinto()
、getheader(name)
、getheaders()
、fileno()
等函数。
# print(response.msg) # OK# print(response.version) #11# print(response.status) #200# print(response.reason) #OK# print(response.getcode()) #200# print(response.getheaders) # <bound method HTTPResponse.getheaders of <http.client.HTTPResponse object at 0x0000023C554DB588>># print(response.geturl()) #http://httpbin.org/headers
2、post请求
from urllib import request,parse url = "http://httpbin.org"data = { 'name':'xfy'}# data = bytes(parse.urlencode(data),encoding='utf8');data = parse.urlencode(data).encode() response = request.urlopen(url+"/post",data=data) print(response.status) #200print(response.read().decode())
data
需要被转码成字节流。而data
是一个字典。我们需要使用 parse.urlencode()
将字典转化为字符串。再使用 bytes()或者encode() 转为字节流。最后使用 urlopen()
发起请求,请求是模拟用 POST 方式提交表单数据。
这里说一下http://httpbin.org
,这个url专门是用来爬虫请求测试的。
http://httpbin.org/get 测试get请求http://httpbin.org/post 测试post请求http://httpbin.org/headers 测试获得headers http://httpbin.org/ip 测试获得iphttp://httpbin.org/cookies 测试获得cookies
三、创建 Request 对象
urlopen()还可以传一个Request对象
req = request.Request(url+"/get") response = request.urlopen(req)print(response.read().decode())
urllib/request 包下有一个类Request
其初始化方法如下
def __init__(self, url, data=None, headers={}, origin_req_host=None, unverifiable=False, method=None):
url
参数是请求链接,这个是必传参数,其他的都是可选参数。data
参数跟 urlopen() 中的 data 参数用法相同。headers
参数是指定发起的 HTTP 请求的头部信息。headers 是一个字典。它除了在 Request 中添加,还可以通过调用 Reques t实例的 add_header() 方法来添加请求头。origin_req_host
参数指的是请求方的 host 名称或者 IP 地址。unverifiable
参数表示这个请求是否是无法验证的,默认值是False。意思就是说用户没有足够权限来选择接收这个请求的结果。例如我们请求一个HTML文档中的图片,但是我们没有自动抓取图像的权限,我们就要将 unverifiable 的值设置成 True。method
参数指的是发起的 HTTP 请求的方式,有 GET、POST、DELETE、PUT等
四、设置headers 模拟浏览器
通过urllib
发起的请求会有默认的一个Headers:"User-Agent":"Python-urllib/3.6"
,指明请求是由urllib
发送的。
所以遇到一些验证User-Agent的网站时,我们需要自定义Headers
,而这需要借助于urllib.request
中的Request
对象。
headers = { 'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36'} req = request.Request(url+"/headers",headers=headers) response = request.urlopen(req)print(response.read().decode())
五、Request的高端使用
如果我们需要在请求中添加代理、处理请求的 Cookies,我们需要用到Handler和OpenerDirector。
Handler
Handler 的中文意思是处理者、处理器。 Handler 能处理请求(HTTP、HTTPS、FTP等)中的各种事情。它的具体实现是这个类 urllib.request.BaseHandler。它是所有的 Handler 的基类,其提供了最基本的Handler的方法,例如default_open()、protocol_request()等。
继承 BaseHandler 有很多个,我就列举几个比较常见的类:
ProxyHandler:为请求设置代理
HTTPCookieProcessor:处理 HTTP 请求中的 Cookies
HTTPDefaultErrorHandler:处理 HTTP 响应错误。
HTTPRedirectHandler:处理 HTTP 重定向。
HTTPPasswordMgr:用于管理密码,它维护了用户名密码的表。
HTTPBasicAuthHandler:用于登录认证,一般和 HTTPPasswordMgr 结合使用。
OpenerDirector
对于 OpenerDirector
,我们可以称之为 Opener
。我们之前用过 urlopen() 这个方法,实际上它就是 urllib 为我们提供的一个Opener
。那Opener
和 Handler
又有什么关系?
opener
对象是由build_opener(handler)
方法来创建出来。我们需要创建自定义的
opener
,就需要使用install_opener(opener)
方法。值得注意的是,
install_opener
实例化会得到一个全局的OpenerDirector
对象。
1、使用代理
有些网站做了浏览频率限制。如果我们请求该网站频率过高。该网站会被封IP,禁止我们的访问。所以我们需要使用代理来突破这“枷锁”。
proxy_header = request.ProxyHandler({ 'http':'101.236.19.165:8866'}) opener = request.build_opener(proxy_header) request.install_opener(opener) response = request.urlopen(url+"/ip")print(response.read().decode())#打印结果{"origin":"101.236.19.165"}
2、cookie的设置
如果请求的页面每次需要身份验证,我们可以使用 Cookies 来自动登录,免去重复登录验证的操作。获取 Cookies 需要使用http.cookiejar.CookieJar()
实例化一个Cookies对象。再用rllib.request.HTTPCookieProcessor
构建出handler对象。最后使用 opener 的 open()函数即可。
import http.cookiejar# 创建一个cookiejar对象cookie = http.cookiejar.CookieJar()# 使用HTTPCookieProcessor创建handler处理器handler = request.HTTPCookieProcessor(cookie)# 并以它为参数创建Opener对象opener = request.build_opener(handler)# 使用这个opener来发起请求response = opener.urlopen("https://blog.csdn.net/keep_learn/article/details/68124190")for item in cookie: print(item.name) print(item.value) 打印结果 dc_session_id10_1531039395672.102673uuid_tt_dd10_19936141720-1531039395672-826694
六、请求异常处理
发起请求难免会出现各种异常,我们需要对异常进行处理,这样会使得程序比较人性化。
异常处理主要用到两个类,urllib.error.URLError
和urllib.error.HTTPError
。
URLError
URLError
是urllib.error
异常类的基类, 可以捕获由urllib.request
产生的异常。它具有一个属性reason
,即返回错误的原因。
from urllib import request,error data = { 'name':'xfy'} data = parse.urlencode(data).encode()try: response = request.urlopen(url,data=data)except error.URLError as e: print(e.reason) 打印 METHOD NOT ALLOWED
HTTPError
HTTPError
是UEKRrror
的子类,专门处理 HTTP 和 HTTPS 请求的错误。它具有三个属性。
code
:HTTP 请求返回的状态码。renson
:与父类用法一样,表示返回错误的原因。headers
:HTTP 请求返回的响应头信息。
from urllib import request,error data = { 'name':'xfy'} data = parse.urlencode(data).encode()from urllib import errortry: response = request.urlopen(url,data=data)except error.HTTPError as e: print(e.reason) print(e.code) print(e.headers) 打印: METHOD NOT ALLOWED405Connection: close Server: gunicorn/19.8.1Date: Sun, 08 Jul 2018 08:57:40 GMT Content-Type: text/html Allow: GET, OPTIONS, HEAD Content-Length: 178Access-Control-Allow-Origin: * Access-Control-Allow-Credentials: true Via: 1.1 vegur
七、下载数据到本地
在我们进行网络请求时常常需要保存图片或音频等数据到本地,一种方法是使用python的文件操作,将read()获取的数据保存到文件中。
而urllib
提供了一个urlretrieve()
方法,可以简单的直接将请求获取的数据保存成文件。
from urllib import request url = 'http://python.org/'request.urlretrieve(url, 'python.html')
urlretrieve()
方法传入的第二个参数为文件保存的位置,以及文件名。
注:urlretrieve()
方法是python2直接移植过来的方法,以后有可能在某个版本中弃用。
八、urllib 处理 https 请求ssl 证书验证
import ssl#处理HTTPS请求 SSL证书验证 忽略认证 比如12306 网站url = "https://www.12306.cn/mormhweb/"#添加忽略ssl证书验证context = ssl._create_unverified_context() header = headers = { "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_0) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11"} req = request.Request(url, headers=header) res = request.urlopen(req,context = context) print(res.read().decode())
九、urllib.parse
urllib.parse
是urllib中用来解析各种数据格式的模块。
urllib.parse.quote
在url中,是只能使用ASCII中包含的字符的,也就是说,ASCII不包含的特殊字符,以及中文等字符都是不可以在url中使用的。而我们有时候又有将中文字符加入到url中的需求,例如百度的搜索地址:
https://www.baidu.com/s?wd=周杰伦
?之后的wd参数,则是我们搜索的关键词。那么我们实现的方法就是将特殊字符进行url编码,转换成可以url可以传输的格式,urllib中可以使用quote()
方法来实现这个功能。
from urllib import parse keyword = '周杰伦'parse.quote(keyword) %E5%91%A8%E6%9D%B0%E4%BC%A6
如果需要将编码后的数据转换回来,可以使用unquote()
方法。
parse.unquote('%E5%91%A8%E6%9D%B0%E4%BC%A6')'周杰伦'
urllib.parse.urlencode
在访问url时,我们常常需要传递很多的url参数,而如果用字符串的方法去拼接url的话,会比较麻烦,所以urllib
中提供了urlencode
这个方法来拼接url参数。
params = {'query':'徐繁韵','name':'xfy'} data = parse.urlencode(params)print(data) query=%E5%BE%90%E7%B9%81%E9%9F%B5&name=xfy
urllib这个官方的python标准库,了解为主。
作者:潇潇漓燃
链接:https://www.jianshu.com/p/fab16367c127