urllib的使用

urllib的使用

urllib是python内置的HTTP请求库,包含如下四个模块:

request:它是最基本HTTP请求模块,可以用来模拟发送请求,就像在浏览器里输入网址然后按回车一样,只需要传入URL以及额外的参数,就可以模拟实现这个过程了。

error:异常处理模块,如果出现请求错误,可以捕获到这些异常,然后进行重试或其他操作以保证程序不会意外终止。

parse:一个工具模块,提供了许多URL处理方法,比如拆分、解析、合并等。

robotparse:主要用来识别网站的robots.txt文件,然后判断哪些往回走哪可以爬,哪些网站不可以爬。

 

1.request模块

 urllib.request 模块提供了最基本的构造HTTP请求的方法,利用它可以模拟浏览器发送请求,同时还有处理授权验证、重定向、Cookies以及其他内容。

# 导入模块
from urllib import request
# 调用urlopen()方法发送请求
response = request.urlopen('https://www.python.org')
print(response.read().decode('utf-8'))

通过简单的两行代码就可以将python官网的源代码抓取下来了,上面得到的response是一个HTTPResponse 类型的对象,通过该对象调用read()、readinto()、getheader(name)、getheaders()、fileno()等方法,以及msg、version、status、reason、debuglevel、closed等属性。下面来详细分析urlopen()函数的API:

urllib.request.urlopen(url,data=None,[timeout],cafile=None,capath=None,cadefault=False,content=None)

除了url参数以外,其余的参数都是可选的。

data参数:如果要添加该参数,并且如果它是字节流编码格式的内容(bytes类型),则需要通过bytes()方法转换。另外,如果传递了这个参数,则它的请求方式不再是GET,而是POST请求。

import ulllib.parse
import urllib.request

data = bytes(urllib.parse.urlencode({'name':'jonas'}),encoding='utf-8')
response = urllib.request.urlopen('http://httpbin.org/post',data=data)
print(response.read())

这里传递了一个参数name,值是jonas。它需要被转码成bytes类型,其中转转字节流采用了bytes()方法,该方法的第一个参数需要时str类型,需要用urllib.parse模块的urlencode()方法来将dict转化为str类型;第二个参数指定编码方式。

 

timeout参数:用于设置超时时间,单位为秒。如果超出设置的时间还没有得到响应,就会抛出URLError异常。

import urllib.request

response = urllib.request.urlopen('http://httpbin.org/get',timeout=1)

如果超过了1秒没有得到响应,程序就会抛出URLError异常,该异常属于urllib.error模块,错误原因是超时。

 

上面通过urlopen()方法可以实现最基本的请求发起,但这几个简答的参数并不足以构建一个完整的请求,如果请求中需要加入Headers信息,就可以利用更强大的Request类来构建。

import urllib.request

request = urllib.request.Request('https://python.org')
response = urllib.request.urlopen(request)
print(response.read().decode('utf-8'))

可以发现,上面依然是用urlopen()方法来发送请求,只不过该方法的参数不再是url,而是一个Request对象。

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

第一个参数 url 是必须必须的,用于请求的URL。

第二个参数data如果要传,则必须传bytes()类型,跟上面的一样,如果是字典,可以通过urllib.parse.urlencode()来编码。

第三个参数headers是一个字典,它就是请求头,可以在构造请求时通过headers参数直接构造,也可以通过调用请求实例的add_header()方法添加。请求头最常用的用法就是通过修改User-Agent来伪装浏览器,默认的User-Agent是Python-urllib,如果不修改该值,则很有可能会被识别为爬虫。

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

第五个参数unverifiable表示这个请求是否是无法验证的,默认是False,意思就是说用户没有足够权限来选择接受这个请求的结果。

第六个参数method是一个字符串,用来指示请求使用的方法。

下面传入多个参数来构建你请求:

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'           
}
my_dict = {'name':'jonas'}
data = bytes(parse.urlencode(my_dict),encoding='utf-8')
req = request.Request(url=url,data=data,headers=headers,method='POST')
print(response.read().decode('utf-8'))

  在上面构建了请求,成功的伪装成浏览器去发请求拿数据,但是反爬虫的技术不仅仅是检查请求头的User-Agent,还有很多方式,比如,服务器会检测某个IP在单位时间内的请求次数,如果超过了某个值,那么服务器会拒绝服务,返回一些错误信息。所以在时候就需要用到代理技术了(详细在后面介绍)。

在urllib.request模块里有一个BaseHandler类,它是所有其他Handler的父类,它提供了最基本的方法,除此以外还有很多基于这个类的子类:

HTTPDefaultErrorHandler:用于处理HTTP响应错误,错误会怕抛出HTTPError异常。

HTTPRedirectHandler:用于处理重定向

HTTPCookieProcessor:用于处理Cookies

ProxyHandler:用于设置代理,默认代理为空

HTTPPasswordMgr:用于管理密码,它维护了用户名和密码的表

HTTPBasicAuthHandler:用于管理认证,如果一个链接打开时需要认证,那么可以使用它来解决认证问题

  除了这些以外,还有一个比较重要的类就是OpernerDirector,称为Opener,上面使用的urlopen()方法的返回值其实就是一个Opener对象,有些网站在打开时就会弹出提示框,直接提示你输入用户名和密码,验证成功后才能查看页面,如果需要请求这样的页面,就可以通过HTTPBasicAuthHandler来完成了。

from urllib.request import HTTPPasswordMgrWithDefaultRealm,HTTPBasicAuthHandler,build_opener
from urllib.error import URLError

username = 'jonas'
password = 123456
url = 'localhost:3000'

p = HTTPPasswordMgrWithDefaultRealm()
p.add_password(None,url,username,password)
auth_handler = HTTPBasicAuthHandler(p)
opener = build_opener(auth_handler)

try:
    result = opener.open(url)
    html = result.read().decode('utf-8')
except URLError as e:
    print(e.reason)  

这里首先实例化 HTTPBasicAuthHandler 对象,其参数是 HTTPPasswordMgrWithDefaultRealm 对象,它利用add_password()添加进去用户名和密码,这样就建立了一个处理验证的Handler,接下来就可以利用这个Handler并使用build_opener()方法构建一个Opener,这个Opener在发送请求时就相当于验证成功了,然后利用Opener的open()方法打开链接,就完成验证了,这里获取到的结果就是验证后的页面源码内容。

 

除了上面的验证以外,在爬虫的时候免不了使用的就是代理技术。

from urllib.error import URLError
from urllib.request import ProxyHandler,build_opener

proxy_handler = ProxyHandler({
   'http':'http://127.0.0.1:5000',
   'https':'https://127.0.0.1:5000'  
})
opener = build_opener(proxy_handler)
try:
    response = opener.open('https://www.baidu.com')
    print(response.read().decode('utf-8'))
except URLError as e:
    print(e.reason)

这里使用了ProxyHandler,其参数是一个字典,键名是协议类型,然后利用这个Handler及build_opener()方法构造一个Opener

 

2.error模块

2.1 URLError

URLError类来自urllib库的error模块,它继承自OSError,是error异常模块的基类,由request模块产生的异常都可以通过捕获这个类类处理。它有一个reason属性,用于返回错误的原因。

from urllib import request,error

try:
    response = request.urlopen('https://www.baidu123.com')
except error.URLError as e:
    print(e.reason)

上面请求了一个不存在的URL,就可以捕获到这个异常。

 

2.2 HTTPError

它是URLError的子类,专门用于处理HTTP请求错误,它有如下3个属性:

code:返回HTTP状态码

reason:返回错误的原因

headers:返回请求头

 

3.parse模块

parse模块定义了处理URL的标准接口,例如实现URL各部分的抽取、合并以及连接转换。

3.1 urlparse()

该方法可以实现URL的识别和分段

from urllib.parse import urlparse

result = urlparse('http://www.baidu.com/index.html;user?id=5#comment')
print(type(result),result)

 该方法返回的结果是一个ParseResult对象,它包含6个部分,分别是scheme代表协议、netloc代表域名、path代表访问路径、params代表参数、query代表查询条件和fragment代表锚点

一个标准的连接格式:scheme://netloc/path;params?query#fragment

除了这种最基本的解析方式,该方法还卡伊传其他参数:

urllib.parse.urlparse(urlstring,scheme='',allow_fragments=True)

urlstring:待解析的URL,必须参数

scheme:默认的协议

allow_fragments:是否忽略fragment

 

3.2 urlunparse()

该方法可以接受一个可迭代对象,但是长度必须是6,如果不足或者过多都会报错。

from urllib import parse

data = ['http','www.baidu.com','index.html','user','a=6','comment']
print(parse.urlunparse(data))

这样就实现了URL的构造了

 

3.3 urlsplit()

该方法和urlparse()非常相似,不同的就是它不再单独解析params这一部分。

 

3.3 urlunsplit()

与urlunparse()类似,它也是将连接各部分组合成完整连接的方法,传入的参数也是一个可迭代对象,唯一有区别的就是长度必须是5

 

3.4 urlencode()

 该方法常用于构造GET请求的参数,具体用法在上面已经有示例。

 

3.5 parse_qs()

如果需要处理一串GET请求参数,可以利用该方法进行反序列化。

 

3.6 quote()

该方法可以将内容转化为URL编码的格式。URL中带有中文参数时,有时可能会导致乱码问题,此时用这个方法可以将中文字符转化为URL编码

from urllib.parse import quote

keyword = '壁纸'
url = 'https://www.baidu.com/s?wd=' + quote(keyword)
print(url)

对应的,还有unquote()方法,用于URL解码

from urllib.parse import unquote

url = 'https://www.baidu.com/s?wd=%E5%A3%81%E7%BA%BB'
print(unquote(url))
原文地址:https://www.cnblogs.com/jonas-von/p/9172847.html