爬虫系列(三) urllib的基本使用
一、urllib 简介
urllib 是 Python3 中自带的 HTTP 请求库,无需复杂的安装过程即可正常使用,十分适合爬虫入门
urllib 中包含四个模块,分别是
- request:请求处理模块
- parse:URL 处理模块
- error:异常处理模块
- robotparser:robots.txt 解析模块
以下我们将会分别讲解 urllib 中各模块的使用方法,但是由于篇幅问题,本文只会涉及模块中比较常用的内容
详细内容可以参考官方文档:https://docs.python.org/3.7/library/urllib.html
二、urllib 使用
在开始讲解前,先给大家提供一个用于测试的网站,http://www.httpbin.org/
这个网站可以在页面上返回所发送 请求 的相关信息,十分适合练习使用
好了,下面正式开始!
1、request 模块
request 模块是 urllib 中最重要的一个模块,一般用于 发送请求和接收响应
(1)urlopen 方法
urllib.request.urlopen()
urlopen 方法无疑是 request 模块中最常用的方法之一,常见的参数说明如下:
-
url
:必填,字符串,指定目标网站的 URL -
data
:指定表单数据该参数默认为 None,此时 urllib 使用 GET 方法 发送请求
当给参数赋值后,urllib 使用 POST 方法 发送请求,并在该参数中携带表单信息(bytes 类型)
-
timeout
:可选参数,用来指定等待时间,若超过指定时间还没获得响应,则抛出一个异常
该方法始终返回一个 HTTPResponse 对象,HTTPResponse 对象常见的属性和方法如下:
geturl()
:返回 URLgetcode()
:返回状态码getheaders()
:返回全部响应头信息getheader(header)
:返回指定响应头信息read()
:返回响应体(bytes 类型),通常需要使用decode('utf-8')
将其转化为 str 类型
例子1:发送 GET 请求
>>> import urllib.request
>>> url = 'http://www.httpbin.org/get'
>>> response = urllib.request.urlopen(url)
>>> type(response)
# <class 'http.client.HTTPResponse'>
>>> response.geturl()
# 'http://www.httpbin.org/get'
>>> response.getcode()
# 200
>>> response.getheaders()
# [('Connection', 'close'), ('Server', 'gunicorn/19.9.0'), ('Date', 'Sat, 11 Aug 2018 01:39:14 GMT'), ('Content-Type', 'application/json'), ('Content-Length', '243'), ('Access-Control-Allow-Origin', '*'), ('Access-Control-Allow-Credentials', 'true'), ('Via', '1.1 vegur')]
>>> response.getheader('Connection')
# 'close'
>>> print(response.read().decode('utf-8'))
# {
# "args": {},
# "headers": {
# "Accept-Encoding": "identity",
# "Host": "www.httpbin.org",
# "User-Agent": "Python-urllib/3.7"
# },
# "origin": "183.6.159.80, 183.6.159.80",
# "url": "https://www.httpbin.org/get"
# }
例子2:发送 POST 请求
urllib.parse.urlencode()
:进行 URL 编码,实际上是将 dict 类型数据转化成 str 类型数据
encode('utf-8')
:将 str 类型数据转化成 bytes 类型数据
>>> import urllib.request
>>> import urllib.parse
>>> url = 'http://www.httpbin.org/post'
>>> params = {
'from':'AUTO',
'to':'AUTO'
}
>>> data = urllib.parse.urlencode(params).encode('utf-8')
>>> response = urllib.request.urlopen(url=url,data=data)
>>> html = response.read().decode('utf-8')
>>> print(html)
# {
# "args": {},
# "data": "",
# "files": {},
# "form": { # 这是我们设置的表单数据
# "from": "AUTO",
# "to": "AUTO"
# },
# "headers": {
# "Accept-Encoding": "identity",
# "Connection": "close",
# "Content-Length": "17",
# "Content-Type": "application/x-www-form-urlencoded",
# "Host": "www.httpbin.org",
# "User-Agent": "Python-urllib/3.6"
# },
# "json": null,
# "origin": "116.16.107.180",
# "url": "http://www.httpbin.org/post"
# }
(2)Request 对象
实际上,我们还可以给 urllib.request.open()
方法传入一个 Request 对象作为参数
为什么还需要使用 Request 对象呢?因为在上面的参数中我们无法指定 请求头部,而它对于爬虫而言又十分重要
很多网站可能会首先检查请求头部中的 USER-AGENT
字段来判断该请求是否由网络爬虫程序发起
但是通过修改请求头部中的 USER_AGENT
字段,我们可以将爬虫程序伪装成浏览器,轻松绕过这一层检查
这里提供一个查找常用的 USER-AGENT 的网站:
urllib.request.Request()
参数说明如下:
url
:指定目标网站的 URLdata
:发送 POST 请求时提交的表单数据,默认为 Noneheaders
:发送请求时附加的请求头部,默认为 {}origin_req_host
:请求方的 host 名称或者 IP 地址,默认为 Noneunverifiable
:请求方的请求无法验证,默认为 Falsemethod
:指定请求方法,默认为 None
>>> import urllib.request
>>> url = 'http://www.httpbin.org/headers'
>>> headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36'
}
>>> req = urllib.request.Request(url, headers=headers, method='GET')
>>> response = urllib.request.urlopen(req)
>>> html = response.read().decode('utf-8')
>>> print(html)
# {
# "headers": {
# "Accept-Encoding": "identity",
# "Connection": "close",
# "Host": "www.httpbin.org",
# "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36" 这是我们设置的 User-Agent
# }
# }
(3) 使用 Cookie
什么是 Cookie?
Cookie 是指某些网站为了辨别用户身份、进行 session 跟踪而储存在用户本地终端上的数据
① 获取 Cookie
>>> import urllib.request
>>> import http.cookiejar
>>> cookie = http.cookiejar.CookieJar()
>>> cookie_handler = urllib.request.HTTPCookieProcessor(cookie)
>>> opener = urllib.request.build_opener(cookie_handler)
>>> response = opener.open('http://www.baidu.com')
>>> for item in cookie:
print(item.name + '=' + item.value)
# BAIDUID=486AED46E7F22C0A7A16D9FE6E627846:FG=1
# BDRCVFR[RbWYmTxDkZm]=mk3SLVN4HKm
# BIDUPSID=486AED46E7F22C0A7A16D9FE6E627846
# H_PS_PSSID=1464_21106_26920
# PSTM=1533990197
# BDSVRTM=0
# BD_HOME=0
# delPer=0
② 使用 Cookie
>>> import urllib.request
>>> import http.cookiejar
>>> # 将 Cookie 保存到文件
>>> cookie = http.cookiejar.MozillaCookieJar('cookie.txt')
>>> cookie_handler = urllib.request.HTTPCookieProcessor(cookie)
>>> opener = urllib.request.build_opener(cookie_handler)
>>> response = opener.open('http://www.baidu.com')
>>> cookie.save(ignore_discard=True,ignore_expires=True)
>>> # 从文件读取 Cookie 并添加到请求中
>>> cookie = http.cookiejar.MozillaCookieJar()
>>> cookie = cookie.load('cookie.txt',ignore_discard=True,ignore_expires=True)
>>> cookie_handler = urllib.request.HTTPCookieProcessor(cookie)
>>> opener = urllib.request.build_opener(cookie_handler)
>>> response = opener.open('http://www.baidu.com')
>>> # 此时已经得到带有 Cookie 请求返回的响应
(4)使用代理
对于某些网站,如果同一个 IP 短时间内发送大量请求,则可能会将该 IP 判定为爬虫,进而对该 IP 进行封禁
所以我们有必要使用随机的 IP 地址来绕开这一层检查,这里提供几个查找免费的 IP 地址的网站:
- 西刺代理:http://www.xicidaili.com/nn/
- 云代理:http://www.ip3366.net/free/
- 快代理:https://www.kuaidaili.com/free/
注意,免费的代理 IP 基本上十分不稳定,而且还可能随时更新,所以最好自己写一个爬虫去维护
>>> import urllib.request
>>> import random
>>> ip_list = [
{'http':'61.135.217.7:80'},
{'http':'182.88.161.204:8123'}
]
>>> proxy_handler = urllib.request.ProxyHandler(random.choice(ip_list))
>>> opener = urllib.request.build_opener(proxy_handler)
>>> response = opener.open('http://www.httpbin.org/ip')
>>> print(response.read().decode('utf-8'))
# {
# "origin": "61.135.217.7"
# }
2、parse 模块
parse 模块一般可以用于处理 URL
(1)quote 方法
当你在 URL 中使用中文时,你会发现程序会出现莫名其妙的错误
>>> import urllib.request
>>> url = 'https://www.baidu.com/s?wd=爬虫'
>>> response = urllib.request.urlopen(url)
# UnicodeEncodeError: 'ascii' codec can't encode characters in position 10-11: ordinal not in range(128)
这时,quote 方法就可以派上用场了,它使用转义字符替换特殊字符,从而将上面的 URL 处理成合法的 URL
>>> import urllib.parse
>>> url = 'https://www.baidu.com/s?wd=' + urllib.parse.quote('爬虫')
>>> url
# 'https://www.baidu.com/s?wd=%E7%88%AC%E8%99%AB'
(2)urlencode 方法
urlencode 方法在上面的文章中曾经用到过,不知道大家还有没有印象,这里我们再重新回顾一遍
简单来说,urlencode 方法就是将 dict 类型数据转化为符合 URL 标准的 str 类型数据,请看演示:
>>> import urllib.parse
>>> params = {
'from':'AUTO',
'to':'AUTO'
}
>>> data = urllib.parse.urlencode(params)
>>> data
# 'from=AUTO&to=AUTO'
(3)urlparse 方法
urlparse 方法用于解析 URL,返回一个 ParseResult 对象
该对象可以认为是一个六元组,对应 URL 的一般结构:scheme://netloc/path;parameters?query#fragment
>>> import urllib.parse
>>> url = 'http://www.example.com:80/python.html?page=1&kw=urllib'
>>> url_after = urllib.parse.urlparse(url)
>>> url_after
# ParseResult(scheme='http', netloc='www.example.com:80', path='/python.html', params='', query='page=1', fragment='urllib')
>>> url_after.port
# 80
3、error 模块
error 模块一般用于进行异常处理,其中包含两个重要的类:URLError
和 HTTPError
注意,HTTPError 是 URLError 的子类,所以捕获异常时一般要先处理 HTTPError,常用的格式如下:
>>> import urllib.request
>>> import urllib.error
>>> import socket
>>> try:
response = urllib.request.urlopen('http://www.httpbin.org/get', timeout=0.1)
except urllib.error.HTTPError as e:
print("Error Code: ", e.code)
print("Error Reason: ", e.reason)
except urllib.error.URLError as e:
if isinstance(e.reason, socket.timeout):
print('Time out')
else:
print('Request Successfully')
# Time out
【参考资料】
【爬虫系列相关文章】