专栏首页Python 知识大全Python爬虫这么久了,它们三兄弟终于搞清楚了(干货)

Python爬虫这么久了,它们三兄弟终于搞清楚了(干货)

urllib,urllib2和 urllib3的区别

01/11

周五 晴

在可供使用的网络库中,urllib和urllib2可能是投入产出比最高的两个,是Python中操作url的官方标准库。它们让你能够通过网络访问文件,就像这些文件位于你的计算机中一样。只需一个简单的函数调用,就几乎可将统一资源定位符(URL)可指向的任何动作作为程序的输入。结合re模块使用将发挥强大威力!

一、urllib

urllib作为Python的标准库,基本上涵盖了基础的网络请求功能。

1.urllib.request

urllib中,request这个模块主要负责构造和发起网络请求,并在其中加入Headers、Proxy等。

(1)发起GET请求

主要使用urlopen()方法来发起请求:

from urllib import request
 
resp =request.urlopen('http://www.baidu.com')
print(resp.read().decode())在urlopen()方法中传入字符串格式的url地址,则此方法会访问目标网址,然后返回访问的结果。

返回的结果会是一个http.client.HTTPResponse对象,使用此对象的read()方法可以获取访问网页获得的数据。但是要注意的是,获得的数据会是bytes的二进制格式,所以需要decode()一下,转换成字符串格式。

使用带参数的GET方法取回URL:

>>> import urllib
>>> params =urllib.urlencode({'spam': 1, 'eggs': 2, 'bacon': 0})
>>> f =urllib.urlopen("http://www.musi-cal.com/cgi-bin/query?%s" % params)
>>> print f.read()

(2)发起POST请求

urlopen()默认的访问方式是GET,当在urlopen()方法中传入data参数时,则会发起POST请求。注意:传递的data数据需要为bytes格式。timeout参数还可以设置超时时间,如果请求时间超出,那么就会抛出异常。

from urllib import request
resp=request.urlopen('http://httpbin.org/post', data=b'word=hello', timeout=10)
print(resp.read().decode())
使用带参数的POST方法:
>>> import urllib
>>> params =urllib.urlencode({'spam': 1, 'eggs': 2, 'bacon': 0})
>>>f=urllib.urlopen("http://www.musi-cal.com/cgi-bin/query", params)
>>> print f.read()

(3)添加Headers

通过urllib发起的请求会有默认的一个Headers:"User-Agent":"Python-urllib/3.6",指明请求是由urllib发送的。

所以遇到一些验证User-Agent的网站时,我们需要自定义Headers,而这需要借助于urllib.request中的Request对象。

from urllib import request
url = 'http://httpbin.org/get'
headers = {'user-agent': 'Mozilla/5.0(Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/537.36 (KHTML, like Gecko)Chrome/66.0.3359.181 Safari/537.36'}# 需要使用url和headers生成一个Request对象,然后将其传入urlopen方法中
req = request.Request(url, headers=headers)
resp = request.urlopen(req)
print(resp.read().decode())

(4)Request对象

如上所示,urlopen()方法中不止可以传入字符串格式的url,也可以传入一个Request对象来扩展功能,Request对象如下所示。

class urllib.request.Request(url, data=None,headers={},
                            origin_req_host=None,
                            unverifiable=False, method=None)

构造Request对象必须传入url参数,data数据和headers都是可选的。

最后,Request方法可以使用method参数来自由选择请求的方法,如PUT,DELETE等等,默认为GET。

(5)添加Cookie

为了在请求时能带上Cookie信息,我们需要重新构造一个opener。

使用request.build_opener方法来进行构造opener,将我们想要传递的cookie配置到opener中,然后使用这个opener的open方法来发起请求。

from http import cookiejar
from urllib import request
 
url = 'https://www.baidu.com'
 
# 创建一个cookiejar对象
cookie = cookiejar.CookieJar()
 
# 使用HTTPCookieProcessor创建cookie处理器
cookies = request.HTTPCookieProcessor(cookie)
 
# 并以它为参数创建Opener对象
opener = request.build_opener(cookies)
 
# 使用这个opener来发起请求
resp = opener.open(url)
 
# 查看之前的cookie对象,则可以看到访问百度获得的cookie
for i in cookie:
   print(i) 

或者也可以把这个生成的opener使用install_opener方法来设置为全局的,之后使用urlopen方法发起请求时,都会带上这个cookie:

# 将这个opener设置为全局的opener
request.install_opener(opener)
resp = request.urlopen(url)

(6)设置Proxy代理

使用爬虫来爬取数据的时候,常常需要使用代理来隐藏我们的真实IP。

点击查看IP代理详细教程

from urllib import request
 
url = 'http://httpbin.org/ip'
proxy ={'http':'218.18.232.26:80','https':'218.18.232.26:80'}
 
# 创建代理处理器
proxies = request.ProxyHandler(proxy)
# 创建opener对象
opener = request.build_opener(proxies)
 
resp = opener.open(url)
print(resp.read().decode())

(7)下载数据到本地

在我们进行网络请求时常常需要保存图片或音频等数据到本地,一种方法是使用python的文件操作,将read()获取的数据保存到文件中。

而urllib提供了一个urlretrieve()方法,可以简单的直接将请求获取的数据保存成文件。

from urllib import request
 
url = 'http://python.org/'
# urlretrieve()方法传入的第二个参数为文件保存的位置,以及文件名。
request.urlretrieve(url, 'python.html')
注:urlretrieve()方法是Python2.x直接移植过来的方法,以后有可能在某个版本中弃用。

2.urllib.response

在使用urlopen()方法或者opener的open()方法发起请求后,获得的结果是一个response对象。这个对象有一些方法和属性,可以让我们对请求返回的结果进行一些处理。

read():获取响应返回的数据,只能使用一次。

getcode():获取服务器返回的状态码。

getheaders():获取返回响应的响应报头。

geturl():获取访问的url。


3.urllib.parse

urllib.parse是urllib中用来解析各种数据格式的模块。

(1) urllib.parse.quote

在url中,是只能使用ASCII中包含的字符的,也就是说,ASCII不包含的特殊字符,以及中文等字符都是不可以在url中使用的。而我们有时候又有将中文字符加入到url中的需求.urllib中可以使用quote()方法来实现这个功能。

>>> from urllib import parse
>>> keyword = '南北'
>>> parse.quote(keyword)
'%E5%8D%97%E5%8C%97'
如果需要将编码后的数据转换回来,可以使用unquote()方法。 
>>>parse.unquote('%E5%8D%97%E5%8C%97')
'南北'

(2)urllib.parse.urlencode

在访问url时,我们常常需要传递很多的url参数,而如果用字符串的方法去拼接url的话,会比较麻烦,所以urllib中提供了urlencode这个方法来拼接url参数。

>>> from urllib import parse
>>> params = {'wd': '南北', 'code': '1', 'height': '188'}
>>> parse.urlencode(params)
'wd=%E5%8D%97%E5%8C%97&code=1&height=188'
urllib.error

在urllib中主要设置了两个异常,一个是URLError,一个是HTTPError,HTTPError是URLError的子类。

HTTPError还包含了三个属性:

code:请求的状态码

reason:错误的原因

headers:响应的报头

二、urllib2

Python2.x的一个例子:

import urllib2
 
# 设置浏览器请求头
ua_headers={
   "User-Agent":"Mozilla/5.0 (Windows NT 6.1; WOW64;rv:34.0) Gecko/20100101 Firefox/34.0"
}
 
#建立请求内容
request=urllib2.Request("http://baidu.com/",headers=ua_headers)
 
#获取响应
response=urllib2.urlopen(request)
 
#页面内容
html=response.read()
 
print html
print response.getcode()    #返回响应码
print response.geturl()     #返回实际url
print response.info()       #返回服务器响应的报头
来自urllib2官方文档的几个例子:
 
GET一个URL:
 
>>> import urllib2
>>> f =urllib2.urlopen('http://www.python.org/')
>>> print f.read()
 
使用基本的HTTP认证:
 
import urllib2
auth_handler = urllib2.HTTPBasicAuthHandler()
auth_handler.add_password(realm='PDQApplication',
                         uri='https://mahler:8092/site-updates.py',
                          user='klem',
                         passwd='kadidd!ehopper')
opener = urllib2.build_opener(auth_handler)
urllib2.install_opener(opener)
urllib2.urlopen('http://www.example.com/login.html')
 
一个使用代理的例子:


proxy_handler = urllib2.ProxyHandler({'http':'http://www.example.com:3128/'})
proxy_auth_handler =urllib2.ProxyBasicAuthHandler()
proxy_auth_handler.add_password('realm','host', 'username', 'password')
opener = urllib2.build_opener(proxy_handler,proxy_auth_handler)
opener.open('http://www.example.com/login.html')
添加HTTP请求头部:
 
import urllib2
req =urllib2.Request('http://www.example.com/')
req.add_header('Referer','http://www.python.org/')
r = urllib2.urlopen(req)
更改User-agent:


import urllib2
opener = urllib2.build_opener()
opener.addheaders = [('User-agent','Mozilla/5.0')]
opener.open('http://www.example.com/')

注:httplib和httplib2、httplib是http客户端协议的实现,通常不直接使用,urllib是以httplib为基础,httplib2是第三方库,比httplib有更多特性。httplib比较底层,一般使用的话用urllib和urllib2即可。

三、urllib3

urllib3功能强大且易于使用,用于HTTP客户端的Python库。许多Python的原生系统已经开始使用urllib3。

urllib3提供了很多python标准库urllib里所没有的重要特性:

线程安全

连接池

客户端SSL/TLS验证

文件分部编码上传

协助处理重复请求和HTTP重定位

支持gzip和deflate压缩编码

支持HTTP和SOCKS代理

100%测试覆盖率

1.安装

urllib3是一个第三方库,pip安装:

pip install urllib3

2.使用

urllib3主要使用连接池进行网络请求的访问,所以访问之前需要先创建一个连接池对象:

导入urllib3模块:

>>> import urllib3

(1)设置headers

通过request()方法向请求(request)中添加一些其他信息:

>>> r = http.request(
...    'POST',
...    'http://httpbin.org/post',
...    fields={'hello': 'world'})
或者:在request()方法中,可以定义一个字典类型(dictionary),并作为headers参数传入:
 
headers={'X-Something': 'value'}
resp = http.request('GET','http://httpbin.org/headers', headers=headers)

(2)设置url参数

对于GET等没有请求正文的请求方法,可以简单的通过设置fields参数来设置url参数。
 
fields = {'arg': 'value'}
resp = http.request('GET','http://httpbin.org/get', fields=fields)
如果使用的是POST等方法,则会将fields作为请求的请求正文发送。
所以,如果你的POST请求是需要url参数的话,那么需要自己对url进行拼接。
 
fields = {'arg': 'value'}
resp = http.request('POST','http://httpbin.org/get', fields=fields)

(3)设置代理

>>> import urllib3
>>> proxy =urllib3.ProxyManager('http://50.233.137.33:80', headers={'connection':'keep-alive'})
>>> resp = proxy.request('get','http://httpbin.org/ip')
>>> resp.status
200
>>> resp.data
b'{"origin":"50.233.136.254"}\n'

注:urllib3中没有直接设置cookies的方法和参数,只能将cookies设置到headers中。

(4)官网的一些介绍

请求(request)中的数据项(requestdata)可包括:Headers

在request()方法中,可以定义一个字典类型(dictionary)并作为headers参数传入:

>>> r = http.request(
...    'GET',
...    'http://httpbin.org/headers',
...    headers={
...        'X-Something': 'value'
...    })
>>>json.loads(r.data.decode('utf-8'))['headers']
{'X-Something': 'value', ...}
Query parameters

对于GET、HEAD和DELETE请求,可以简单的通过定义一个字典类型作为fields参数传入即可:

>>> r = http.request(
...    'GET',
...    'http://httpbin.org/get',
...    fields={'arg': 'value'})
>>>json.loads(r.data.decode('utf-8'))['args']
{'arg': 'value'}

对于POST和PUT请求(request),需要手动对传入数据进行编码,然后加在URL之后:

>>> from urllib.parse importurlencode
>>> encoded_args = urlencode({'arg':'value'})
>>> url = 'http://httpbin.org/post?'+ encoded_args
>>> r = http.request('POST', url)
>>>json.loads(r.data.decode('utf-8'))['args']
{'arg': 'value'}
Form data

对于PUT和POST请求(request),urllib3会自动将字典类型的field参数编码成表格类型.

>>> r = http.request(
...    'POST',
...    'http://httpbin.org/post',
...    fields={'field': 'value'})
>>>json.loads(r.data.decode('utf-8'))['form']
{'field': 'value'}
JSON

在发起请求时,可以通过定义body参数并定义headers的Content-Type参数来发送一个已经过编译的JSON数据:

>>> import json
>>> data = {'attribute': 'value'}
>>> encoded_data =json.dumps(data).encode('utf-8')
>>> r = http.request(
...    'POST',
...    'http://httpbin.org/post',
...    body=encoded_data,
...    headers={'Content-Type': 'application/json'})
>>>json.loads(r.data.decode('utf-8'))['json']
{'attribute': 'value'}
Files & binary data 

使用multipart/form-data编码方式上传文件,可以使用和传入Form data数据一样的方法进行,并将文件定义为一个元组的形式(file_name,file_data):

>>> with open('example.txt') as fp:
...    file_data = fp.read()
>>> r = http.request(
...    'POST',
...    'http://httpbin.org/post',
...    fields={
...        'filefield': ('example.txt', file_data),
...    })
>>>json.loads(r.data.decode('utf-8'))['files']
{'filefield': '...'}

文件名(filename)的定义不是严格要求的,但是推荐使用,以使得表现得更像浏览器。同时,还可以向元组中再增加一个数据来定义文件的MIME类型:

>>> r = http.request(
...    'POST',
...    'http://httpbin.org/post',
...    fields={
...        'filefield': ('example.txt', file_data, 'text/plain'),
...    })

如果是发送原始二进制数据,只要将其定义为body参数即可。同时,建议对header的Content-Type参数进行设置:

>>> with open('example.jpg', 'rb')as fp:
...    binary_data = fp.read()
>>> r = http.request(
...    'POST',
...    'http://httpbin.org/post',
...    body=binary_data,
...    headers={'Content-Type': 'image/jpeg'})
>>>json.loads(r.data.decode('utf-8'))['data']
Response content

timeouts

使用timeout,可以控制请求的运行时间。在一些简单的应用中,可以将timeout参数设置为一个浮点数:

>>> http.request(
...    'GET', 'http://httpbin.org/delay/3', timeout=4.0)
<urllib3.response.HTTPResponse>
>>> http.request(
...    'GET', 'http://httpbin.org/delay/3', timeout=2.5)
MaxRetryError caused by ReadTimeoutError

岁月有你 惜惜相

本文分享自微信公众号 - Python 知识大全(TuoLaJi522),作者:厅长大人

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-11-01

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

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 关于编码解码问题,我给大家总结好了,请查收

    将一个十六进制字符串解码成一个字节字符串或者将一个字节字符串编码成 一个十六进制字符串。

    Python知识大全
  • 手把手教你使用Python抓取QQ音乐数据(第一弹)

    5.分析网页源代码 Elements,发现无歌曲信息,无法使用 BeautifulSoup,如下图所示,结果为空。

    Python知识大全
  • Python 常用库

    下载地址:http://www.riverbankcomputing.com/software/pyqt/download

    Python知识大全
  • 代理错误[WinError 10061]

    hankleo
  • iOS版本手机银行存在安全风险漏洞

    据国外媒体报道,苹果iPhone或iPad用户需注意,iOS版本手机银行存在安全风险漏洞。 研究人员阿里尔·桑切斯(Ariel Sanchez)...

    安恒信息
  • iOS开发CoreGraphics核心图形框架之四——变换函数

        在上一篇博客中,介绍了有关CGContext相关操作方法,其中可以直接调用一些方法来进行所绘制图形的平移,缩放,翻转等变换。对于图形了几何变换,开发者也...

    珲少
  • webbench压力测试软件

    进行测试: webbench -c 1000 -t 60 http://192.168.1.2/phpinfo.php 参数说明:

    院长技术
  • Django的页面模版提取(三)

    每一个的头部都是这样的,作为一个懒惰的程序员,当然是要把他们拎出来了。 我们写一个base.html来当作模版。 以forgot.html为例,可以看出只有红框...

    zx钟
  • 朋友圈(拉姆齐定理)- HDU 6152

    拉姆齐Ramsey定理是一个稍微难于理解的定理,该定理又称拉姆齐二染色定理,是要解决这样的问题:

    ACM算法日常
  • RESTful源码学习笔记之RPC和 RESTful 什么区别

    REST,即Representational State Transfer的缩写。翻译过来是表现层状态转换。 如果一个架构符合REST原则,就称它为RESTfu...

    Jetpropelledsnake21

扫码关注云+社区

领取腾讯云代金券