Python之urlib库的基本使用(填坑)

以下为个人在学习Python过程中做的笔记总结之爬虫常用库urllib

前言

urlib库为python3的HTTP内置请求库

urilib的四个模块:

  1. urllib.request:用于获取网页的响应内容
  2. urllib.error:异常处理模块,用于处理异常的模块
  3. urllib.parse:用于解析url
  4. urllib.robotparse:用于解析robots.txt,主要用于看哪些网站不能进行爬取,不过少用

一、urllib.request

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

url:为请求网址
data:请求时需要发送的参数
**timeou**t:超时设置,在该时间范围内返回请求内容就不会报错

示例代码:

from urllib import request

 # 请求获取网页返回内容
 response = request.urlopen('https://book.douban.com/')
 # 获取网页返回内容
 print(response.read().decode('utf-8'))
 # 获取状态码
 print(response.status)
 # 获取请求头
print(response.getheaders())
# 对请求头进行遍历
for i, j in response.getheaders():
    print(i, '=', j)

可以使用上面的代码对一些网站进行请求了,但是当需要一些反爬网站时,这就不行了,这时我们需要适当地增加请求头进行请求,这时就需要使用复杂一点的代码了,这时我们需要用到Request对象。

代码示例:

# 请求头
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.221 Safari/537.36 SE 2.X MetaSr 1.0'}
requests = request.Request('https://book.douban.com/', headers=headers) # 加入自己的请求头更加接近浏览器
# 进行请求,把Request对象传入urlopen参数中
response = request.urlopen(requests)
print(response.read().decode('utf-8'))

这个我添加了请求头进行请求,使机械爬虫模拟浏览器发送请求,更加接近人为的浏览。可以对应一些反爬网站了。

如果网站需要进行登陆,这时需要用到post方法,用上面的也是可以的。代码如下:

 from urllib import request, parse
 # 使用post方法来进行模拟登陆豆瓣
 data = {'source': 'None',
  'redir': 'https://www.douban.com/',
  'form_email': 'user',
  'form_password': 'passwd',
  'remember': 'on',
  'login': '登录'}
 # 将data的字典类型转换为get请求方式
data = bytes(parse.urlencode(data), encoding='utf-8')
requests = request.Request('https://accounts.douban.com/login', headers=headers, data=data, method='POST')
response = request.urlopen(requests)
print(response.read().decode('utf-8'))

这里我用到了data的参数把登陆需要的参数传进去,还加了个请求方法Method。
parse.urlencode()后面有进行说明


PS:
两种 HTTP 请求方法:GET 和 POST
在客户机和服务器之间进行请求-响应时,两种最常被用到的方法是:GETPOST

  • GET - 从指定的资源请求数据。
  • POST - 向指定的资源提交要被处理的数据

比较 GET 与 POST
Python之urlib库的基本使用(填坑)_第1张图片
简单来说get就是直接请求可以直接看到发送的数据,可以被缓存;post需要将发送的数据生成为form表单文件然后再上传文件进行get,发送的数据无法直接预览也无法被缓存。因此post比get更加安全。


这里还有另外一种添加请求头的方法
Request.add_header(): 参数有两个,分别为请求头对应的键和值,这种方法一次只能添加一个请求头,添加多个需要用到循环或者直接用前面的方法添加多个请求头

在登陆了网站之后,我们需要用到cookie来保存登陆信息,这时就需要获取cookie了。urllib获取cookie比较麻烦。
代码示例如下:

 from http import cookiejar
 # 获取cookie
 cookie = cookiejar.CookieJar()
 # 获取助手把cookie传进去
 handler = request.HTTPCookieProcessor(cookie)
 # 获取opener进行请求网站
 opener = request.build_opener(handler)
 # 请求网页
 response = opener.open('https://book.douban.com/')
# 打印cookie
for item in cookie:
    print(item.name, '=', item.value)

单纯地打印没什么用,我们需要把他存入文件来保存,下次使用时再次加载cookie来登陆

保存cookie为文件:

from http import cookiejar
# 将cookie保存在文件中
filename = 'cookie.txt'
cookie = cookiejar.MozillaCookieJar(filename) # 表示使用Mozilla的cookie方式存储和读取
handler = request.HTTPCookieProcessor(cookie)
opener = request.build_opener(handler)
opener.open('https://book.douban.com/')
# 保存文件
cookie.save(ignore_discard=True, ignore_expires=True)

另一种保存方法:

from http import cookiejar
cookie = cookiejar.LWPCookieJar(filename) # 表示 Set-Cookie3 文件格式存储和读取
handler = request.HTTPCookieProcessor(cookie)
opener = request.build_opener(handler)
opener.open('https://book.douban.com/')
# 保存文件
cookie.save(ignore_discard=True, ignore_expires=True)

这两种保存格式都是不一样的,需要保存的内容一样。

保存可以了,这时就需要用到加载了,当然也可以。代码如下:

from http import cookiejar
# 从cookie文件加载到网页上实现记住登陆
cookie = cookiejar.LWPCookieJar()
# 加载文件
cookie.load(filename, ignore_discard=True, ignore_expires=True)
handler = request.HTTPCookieProcessor(cookie)
opener = request.build_opener(handler)
opener.open('https://book.douban.com/')

cookie小总结:在操作cookie时,都是分五步,如下:

  1. 进行导包,至关重要的一步,不导包直接出错。
  2. 获取cookie处理对象,使用cookiejar包
  3. 创建cookie处理器,使用request.HTTPCookieJarProcessor()
  4. 利用cookie处理器构建opener,使用request.build_opener()
  5. 进行请求网站,用opener.open(),这个不能用request.urlopen()

如果有时你在同一ip连续多次发送请求,会有被封ip的可能,这时我们还需要用到代理ip进行爬取,代码如下:

import urllib.request

proxy_handler = urllib.request.ProxyHandler({
    'http': 'http://127.0.0.1:9743',
    'https': 'https://127.0.0.1:9743'
})
opener = urllib.request.build_opener(proxy_handler)
response = opener.open('http://book.douban.com/',timeout=1)
print(response.read())

可以看到越复杂的请求都需要用到request.build_opener(),这个方法有点重要。


二、urllib.error

将上面的使用代理ip的请求进行异常处理,如下:

from urllib import request, error
try:
    proxy_handler = urllib.request.ProxyHandler({
        'http': 'http://127.0.0.1:9743',
        'https': 'https://127.0.0.1:9743'
    })
    opener = urllib.request.build_opener(proxy_handler)
    response=opener.open('https://movie.douban.com/', timeout=1)
except error.HTTPError as e:
    print(e.reason(), e.code(), e.headers())
except error.URLError as e:
    print(e.reason)

因为有时这个ip或许也被封了,有可能会抛出异常,所以我们为了让程序运行下去进而进行捕捉程序:

  • error.URLError: 这个是url的一些问题,这个异常只有一个reason属性
  • error.HTTPError:这个是error.URLError的子类,所以在与上面的混合使用时需要将这个异常放到前面,这个异常是一些请求错误,有三个方法,.reason(), .code(), .headers(),所以在捕捉异常时通常先使用这个

三、urllib.parse

解析url:urllib.parse.urlparse(url, scheme=”, allow_fragments=True)

简单的使用:

from urllib import request, parse
# 解析url
print(parse.urlparse('https://book.douban.com/'))
print(parse.urlparse('https://book.douban.com/', scheme='http'))
print(parse.urlparse('book.douban.com/', scheme='http'))
# 下面是结果
ParseResult(scheme='https', netloc='book.douban.com', path='/', params='', query='', fragment='')
ParseResult(scheme='https', netloc='book.douban.com', path='/', params='', query='', fragment='')
ParseResult(scheme='http', netloc='', path='book.douban.com/', params='', query='', fragment='')

可以看出加了scheme参数和没加的返回结果是有区别的。而当scheme协议加了,而前面的url也包含协议,一般会忽略后面的scheme参数。

既然后解析url,那当然也有反解析url,就是把元素串连成一个url

from urllib.parse import urlunparse
# 将列表元素拼接成url
data = ['http', 'www.baidu.com', 'index.html', 'user', 'a=6', 'comment']
print(urlunparse(data))
# 下面是结果
http://www.baidu.com/index.html;user?a=6#comment

urlparse()接收一个列表的参数,而且列表的长度是有要求的,是必须六个参数以上,要不会抛出异常

ValueError: not enough values to unpack (expected 7, got 6)

urllib.parse.urljoin():这个是将第二个参数的url缺少的部分用第一个参数的url补齐

from urllib.parse import urljoin

print(urljoin('http://www.baidu.com', 'FAQ.html'))
print(urljoin('http://www.baidu.com', 'https://cuiqingcai.com/FAQ.html'))
print(urljoin('http://www.baidu.com/about.html', 'https://cuiqingcai.com/FAQ.html'))
print(urljoin('http://www.baidu.com/about.html', 'https://cuiqingcai.com/FAQ.html?question=2'))
print(urljoin('http://www.baidu.com?wd=abc', 'https://cuiqingcai.com/index.php'))
print(urljoin('http://www.baidu.com', '?category=2#comment'))
print(urljoin('www.baidu.com', '?category=2#comment'))
print(urljoin('www.baidu.com#comment', '?category=2'))

输出结果:

http://www.baidu.com/FAQ.html
https://cuiqingcai.com/FAQ.html
https://cuiqingcai.com/FAQ.html
https://cuiqingcai.com/FAQ.html?question=2
https://cuiqingcai.com/index.php
http://www.baidu.com?category=2#comment
www.baidu.com?category=2#comment
www.baidu.com?category=2

urllib.parse.urlencode():这个方法是将字典类型的参数转为请求为get方式的字符串

from urllib.parse import urlencode

params = {
    'name': 'germey',
    'age': 22
}
base_url = 'http://www.baidu.com?'
url = base_url + urlencode(params)
print(url)

输出结果:

http://www.baidu.com?name=germey&age=22

四、总结

还有个urllib.robotparse库少用,就不说了,如果需要的话再去查官方文档吧。
上面的只是我在学习过程中的总结,如果有什么错误的话,欢迎在留言区指出,还有就是需要查看更多用法的请查看官方文档文档https://docs.python.org/3/library/urllib.html

需要代码的可以去我的github上面fork,给个star也行!
https://github.com/ldz0/Python-jupyter-notebooks
PS:笔记需要使用jupyter notebook打开,之前的文章已经介绍了jupyter的简单安装和使用,是非常方便记录笔记的工具。

本文主要参考崔庆才先生《Python3网络爬虫开发实战》学习总结而来

你可能感兴趣的:(学习,笔记,网络爬虫,python)