[Passage1] 学习urllib库

我将分三篇文章介绍urllib的使用,这是第一篇。

目录(删除部分本文不介绍)

  1. urllib 库的简介

  2. 发送请求(使用request模块)

  3. 异常处理(使用error模块)

  4. 解析 url(使用parse模块)

1.urllib 库的简介

Python3内置了一个HTTP请求库—— urllib,通过它我们可以很方便的模拟http请求过程。这个库包含5个模块:

  • request:最基本的HTTP请求模块,可用来模拟发送请求的过程。

  • error:异常处理模块,用于捕获异常,防止程序意外终止。

  • parse:工具模块,提供了许多URL方法,比如拆分、合并等。

  • robotparser:识别网站的robot文件,判断哪些网站可以爬取。

  • response:Python官网未作详细介绍。

下面分别就前三个模块的使用给出详细介绍

2.发送请求

使用request模块我们可以很方便的发送http请求并得到响应。

2.1 urlopen()

想要抓取一个网页,我们可以使用urlopen函数,比如我们抓取百度实际上只需要两行代码:

>>>from urllib import request
>>>response = request.urlopen('https://www.baidu.com/')

response就包含了请求百度网页后的响应内容,我们可以查看一下它的类型:

>>>print(type(response))
<class 'http.client.HTTPResponse'>

可见response是http.client.HTTPResponse类型。这个类型具有一些方法和属性,下面给出一些常用的方法和属性:

# 常用方法
>>>response.read()  # 获取响应中的html代码
>>>response.getheaders()  # 获取响应头中所有字段
>>>response.getheader('Server')  # 响应头的特定字段 接受key 返回value
# 常用属性
>>>response.status  # 获取响应的状态码 200表示正确返回 还有其他状态码比如404,405等

特别要指出的reponse的read方法返回的是html代码的字节流形式(即Python中的Bytes类型),并且对于一个response来说超出一次使用read方法得到的结果将为空。我们以百度的网页为例:

>>>response.read()  # 第一次使用read方法 得到bytes类型的html代码
b'<html>\r\n<head>\r\n\t<script>\r\n\t\tlocation.replace(location.href.replace("https://","http://"));\r\n\t</script>\r\n</head>\r\n<body>\r\n\t<noscript><meta http-equiv="refresh" content="0;url=http://www.baidu.com/"></noscript>\r\n</body>\r\n</html>'
>>>response.read()  # 第二次使用read方法 结果为空bytes
b''

使用read方法的时候需要注意上面两点。

到目前为止我们只为urlopen函数传入一个url就实现了最基本的GET请求。urlopen函数还提供了其他的参数帮助我们实现其他功能。我们再介绍一些。

  • data参数

如果我们要以POST方式请求网页,我们就必须在调用urlopen函数时传入data参数。data参数必须是字节流格式,可以用bytes函数转换。下面是一个实例:

from urllib import parse
from urllib import request

url = 'http://httpbin.org/post'

# 构造data
dic = {'name':'li'}
dic_to_str = parse.urlencode(dic)  
data = bytes(dic_to_str, encoding='utf8')

# 以POST方式请求网页
response = request.urlopen(url=url, data=data)
print(response.read())

--------------------------------
b'{"args":{},"data":"","files":{},"form":{"he":"123"},"headers":{"Accept-Encoding":"identity","Connection":"close","Content-Length":"6","Content-Type":"application/x-www-form-urlencoded","Host":"httpbin.org","User-Agent":"Python-urllib/3.7"},"json":null,"origin":"36.25.163.88","url":"http://httpbin.org/post"}\n'

在实例中,urlopen接收了一个data参数,这个参数是由一个字典转换而来的。parse.urlencode函数先将一个字典转化成字符串(确切的说这里将{'name':'li'}转为了'name=li'),然后再利用bytes函数将字符串转为字节流。

我们这里请求的站点比较特殊,他们可以测试我们的POST请求是否成功。注意到返回的html内容中有一项form,该字段的内容与我们传入的data内容一致,这就表示我们的POST请求成功了。有些人可能疑惑POST是什么,实际上,POST和GET都属于请求网页的一种方法,比较这两者,POST方式请求的时候需要我们给服务器多传入一个表单,而GET方式则只需要一个url即可。

  • timeout参数

timeout参数决定请求网页时的超时时间,单位为秒。顾名思义就是当请求时间超出这个参数设置的值之后程序将会抛出一个异常,这可以避免网页长时间无响应造成的假死。来看实例:

# 设置超时时间很短 程序抛出异常
from urllib import request
>>>url = 'https://www.baidu.com/'
>>>request.urlopen(url, timeout=1)  # 请求时间未超过timeout 正常返回
<http.client.HTTPResponse object at 0x00000241EA63A7F0>
>>>request.urlopen(url, timeout=0.01)  # 请求时间超过timeout 抛出异常
...
raise URLError(err)
urllib.error.URLError: <urlopen error _ssl.c:1029: The handshake operation timed out>

通过trt-except语句我们可以在请求某网页太久之后跳过该网页,继续请求下面的网页:

from urllib import request
from urllib import error
try:
    response = urllib.request.urlopen('https://www.baidu.com/', timeout=0.1)
except urllib.error.URLError as e:
        print('TIME OUT', e)
        
-------------------------------
TIME OUT <urlopen error timed out>

urlopen函数还有一些参数,不过没有那么常用,我们可以在需要的时候查询文档。

2.2 利用Request()构造请求

尽管urlopen函数已经可以实现基本的请求了,但是它并不能构造一个完整的HTTP请求,而一些请求的字段对于爬虫来说又非常重要,比如请求头之中包含的User-Agent字段可以让爬虫模仿成浏览器,避免被服务器发觉而被封杀。为了构造更完整的请求,request模块提供了一个Request类。

Request类的API如下:

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

  • url是必选参数。

  • data参数只在需要传入表单时使用。它是一个bytes类型的参数。

  • headers参数接收一个字典,表示请求头。除了直接构造,还可以让构造完成的实例使用add_header方法添加。前面提到的User-Agent字段就属于请求头的内容。

  • origin_req_host 参数指的是请求方的 host 名称或者 IP 地址。

  • unverifiable 参数指的是这个请求是否是无法验证的,默认是False。意思就是说用户没有足够权限来选择接收这个请求的结果。例如我们请求一个 HTML 文档中的图片,但是我们没有自动抓取图像的权限,这时 unverifiable 的值就是 True。

  • method 参数是一个字符串,它用来指示请求使用的方法,比如GET,POST,PUT等等。

我们看一个例子:

from urllib import request, parse

url = 'http://httpbin.org/post'
headers = {
    'User-Agent': 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)',  
    'Host': 'httpbin.org'
}
dict = {
    'name': 'Germey'
}
data = bytes(parse.urlencode(dict), encoding='utf8')
req = request.Request(url=url, data=data, headers=headers, method='POST')
response = request.urlopen(req)
print(response.read().decode('utf-8'))

这个例子展示了由四个参数构造的Request对象req,请求时只需要把构造好的req传给urlopen函数就可以实现请求过程了。

参考资料:

[1] 《Python3 网络爬虫开发实战》 崔庆才

[2] https://docs.python.org/3/library/urllib.html#module-urllib urllib官方文档

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

推荐阅读更多精彩内容