重拾python爬虫之urllib

学习一门技术,总是要踩好多坑,然后收货一大堆疑惑,这么多相似的方式该学哪个呢?外面公司常用的是哪个呢?
就比如python爬虫,可以作为网络请求的方式有四种,按时间顺序排:

  1. 第一种urllib2 ,这个包是基于python2的,官方已经对python2停止更新了并且不再免费,我觉得这个urllib2没必要再学习和使用
  2. 第二种urllib 这个是python的标准库,在python3里整合了python2的urlliburllib2 ,有时间的可以学习一下。
  3. 第三种urllib3,这个是第三方库,是对第二种方式urllib的升级,做了很多改善,有时间可以学习一下。
  4. 第四种也是很流行的requests,各种请求的方法非常的优雅和人性化,其底层是urllib3,简化headers、proxy、cookie等的操作。这个重点学习。

作为一个爬虫工程师,如果你连urllib一点不会就说不过去了。虽然不常用,但是学习它,有它的历史意义,对爬虫的整个架构有一个更透彻的了解。

一、简介

urllib是Python中请求url连接的官方标准库,在Python2中主要为urllib和urllib2,在Python3中整合成了urllib。基本上涵盖了基础的网络请求功能。

该库有四个模块,分别是urllib.requesturllib.errorurllib.parseurllib.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 参数是用于设置请求超时时间。单位是秒。
  • cafilecapath代表 CA 证书和 CA 证书的路径。如果使用HTTPS则需要用到。
  • context参数必须是ssl.SSLContext类型,用来指定SSL设置
  • cadefault参数已经被弃用,可以不用管了。
  • 该方法也可以单独传入urllib.request.Request对象
  • 该函数返回结果是一个http.client.HTTPResponse对象。

http.client.HTTPResponse对象。它具有msgversionstatusreasondebuglevelclosed等属性以及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) #200
print(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  测试获得ip
http://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。

  1. 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 结合使用。
  1. OpenerDirector

对于 OpenerDirector,我们可以称之为 Opener。我们之前用过 urlopen() 这个方法,实际上它就是 urllib 为我们提供的一个Opener。那OpenerHandler 又有什么关系?

  • 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_id
10_1531039395672.102673
uuid_tt_dd
10_19936141720-1531039395672-826694

六、请求异常处理

发起请求难免会出现各种异常,我们需要对异常进行处理,这样会使得程序比较人性化。

异常处理主要用到两个类,urllib.error.URLErrorurllib.error.HTTPError

  • URLError

URLErrorurllib.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

HTTPErrorUEKRrror 的子类,专门处理 HTTP 和 HTTPS 请求的错误。它具有三个属性。

  1. code:HTTP 请求返回的状态码。
  2. renson:与父类用法一样,表示返回错误的原因。
  3. headers:HTTP 请求返回的响应头信息。
from  urllib import request,error
data = {
    'name':'xfy'
}
data = parse.urlencode(data).encode()
from urllib import error
try:
    response = request.urlopen(url,data=data)
except error.HTTPError as e:
    print(e.reason)
    print(e.code)
    print(e.headers)
    
打印:
METHOD NOT ALLOWED
405
Connection: close
Server: gunicorn/19.8.1
Date: Sun, 08 Jul 2018 08:57:40 GMT
Content-Type: text/html
Allow: GET, OPTIONS, HEAD
Content-Length: 178
Access-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标准库,了解为主。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容

  • urllib and urllib2 区别 –博主提示:下面的是python2中的用法,python3需要做出相应...
    sunnyRube阅读 1,399评论 0 1
  • Handler处理器 和 自定义Opener 1. 概述 opener是 urllib2.OpenerDirect...
    rhlp阅读 910评论 0 0
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,580评论 18 139
  • 那一天,青春闭上了双眸,爱她的人突然无所适从,眼泪如注如露;讨厌她的人,载歌载舞,举杯欢庆。 第二天,青春被路过的...
    恒木小苑苑阅读 244评论 0 0
  • 如果有来生 我愿化作一只白鸽 洁白的双翼挥斥着 将自己的泪水化作倾盆大雨 洒向西部 翱翔 飞过一座座荒废的群山 粉...
    冷BIN阅读 172评论 0 1