以下为个人在学习Python过程中做的笔记总结之爬虫常用库urllib
urlib库为python3的HTTP内置请求库
urilib的四个模块:
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
在客户机和服务器之间进行请求-响应时,两种最常被用到的方法是:GET 和 POST。
比较 GET 与 POST
简单来说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时,都是分五步,如下:
如果有时你在同一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(),这个方法有点重要。
将上面的使用代理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或许也被封了,有可能会抛出异常,所以我们为了让程序运行下去进而进行捕捉程序:
解析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网络爬虫开发实战》学习总结而来