一 前言
urllib 相比于,requests模块会更加底层,有时候如果使用requests模块无法满足需求,替换为urllib是一个不错的选择;一般学请求都是为了爬虫服务,这边提醒读者的是,在绝对要对一个网站使用爬虫的时候,应该先请求该网站的robot,如果允许则可以爬取数据,否则都是非法。读者对文章的肯定就是对作者创作的最大支持;随手点赞关注谢谢!
通常urllib学习主要分为四大模块
- request请求模块
- 异常处理
- url解析
- robot协议
二 urlopen
2.1 发送get请求
使用urlopen
会打开一个链接,默认情况下就是get操作,如果加了参数则是post操作;
# -*- coding: utf-8 -*-
import urllib.request
response = urllib.request.urlopen('https://www.baidu.com/')
# 读取页面
print(response.read().decode('utf-8'))
输出
<html>
<head>
<script>
location.replace(location.href.replace("https://","http://"));
</script>
</head>
<body>
<noscript><meta http-equiv="refresh" content="0;url=http://www.baidu.com/"></noscript>
</body>
2.2 获得响应头和状态码
对于发送请求后获得的响应可以使用 属性 status
获得 响应状态码,如果是200表名响应成功,然后在进行后续操作,否则就应该做其它判定处理;
# -*- coding: utf-8 -*-
import urllib.request
response = urllib.request.urlopen('https://www.baidu.com/')
# 状态码
print(response.status)
# 头信息 返回的是元组
print(response.getheaders())
输出
200
[('Accept-Ranges', 'bytes'), ('Cache-Control', 'no-cache'), ('Content-Length', '227'), ('Content-Type', 'text/html'), .......]
2.3 发送post请求
使用字典的方式作为参数就可以转为发送post请求,对于获得响应使用read()
函数读取,通常的编码都是utf-8
;如果出现乱码,则应指定其它编码,比如 gb18030
编码;
# -*- coding: utf-8 -*-
import urllib.request
from urllib import parse
# 传参
dic = {'zszxz': 'hello'}
data = bytes(urllib.parse.urlencode(dic), encoding='utf-8')
# psot请求
url = 'http://httpbin.org/post'
response = urllib.request.urlopen(url, data=data)
print(response.read().decode('utf-8'))
输出
{
"args": {},
"data": "",
"files": {},
"form": {
"zszxz": "hello"
},
"headers": {
"Accept-Encoding": "identity",
"Content-Length": "11",
"Content-Type": "application/x-www-form-urlencoded",
"Host": "httpbin.org",
"User-Agent": "Python-urllib/3.8",
"X-Amzn-Trace-Id": "Root=1-5e4ddf64-d93930be4a5a12ec8e1b15b2"
},
"json": null,
"origin": "124.72.37.2",
"url": "http://httpbin.org/post"
}
2.4 超时异常处理
异常这块知识追寻者从简,读者如果要深入学习,可以查阅官网或者其它书籍网络资源;通常使用 urllib.error.URLError
就可以捕获所有发送请求时的异常;
# -*- coding: utf-8 -*-
import urllib.request
from urllib import error
try:
response = urllib.request.urlopen('http://httpbin.org/get', timeout=0.1)
except urllib.error.URLError as e:
print('read time out')
输出
read time out
三 request模块
3.1 使用request模块发送完整请求
前面一节中使用的urllib功能较为单一,满足不了日常的需求;使用urllib中的request 模块封装请求再传送给
urlopen
就可以达到很好的预期效果;以下示例中模拟一个比较全面的发送请求获得响应的过程;
# -*- coding: utf-8 -*-
from urllib import parse, request
# 请求的url
url = 'http://httpbin.org/post'
# 设置请求头
headers = {
'Host': 'httpbin.org',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36'
}
# 参数字典
dic = {
'name':'zszxz'
}
data= bytes(parse.urlencode(dic), encoding='utf8')
# 设置请求参数
req = request.Request(url=url, data=data, headers=headers, method ='POST')
response = request.urlopen(req)
print(response.read().decode('utf-8'))
输出
{
"args": {},
"data": "",
"files": {},
"form": {
"name": "zszxz"
},
"headers": {
"Accept-Encoding": "identity",
"Content-Length": "10",
"Content-Type": "application/x-www-form-urlencoded",
"Host": "httpbin.org",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36",
"X-Amzn-Trace-Id": "Root=1-5e4de0fc-6e2846d0412d37f4267c03a6"
},
"json": null,
"origin": "124.72.37.2",
"url": "http://httpbin.org/post"
}
3.2 登陆认证
在发送请求时难免有些网站需要登陆后才可以访问相关资源,此时可以使用urllib中HTTPPasswordMgrWithDefaultRealm
对象创建认证实例,将实例传给HTTPBasicAuthHandler 处理, 使用build_opener 建立请求信息,就可以达到登陆认证效果;
# -*- coding: utf-8 -*-
from urllib import parse, request,error
from urllib.request import HTTPBasicAuthHandler,HTTPPasswordMgrWithDefaultRealm,build_opener
username = 'zszxz'
password = ''
url = 'https://github.com/zszxz'
# 创建认证实例
realm = HTTPPasswordMgrWithDefaultRealm()
# 添加认证信息
realm.add_password(None, url, username, password)
# 将认证信息添加至请求头
hander = HTTPBasicAuthHandler(realm)
# 创建open
opener = build_opener(hander)
try:
response = opener.open(url)
html = response.read().decode('utf-8')
print(html)
except error.URLError as e:
print(e.reason)
输出
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<link rel="dns-prefetch" href="https://github.githubassets.com">
.............
3.3 代理设置
在进行相关网页请求的时候,如果要进行匿名访问,不想服务器获得本地的真实ip可以使用代理ip;当然没有绝对的安全,只有相对的安全,至少使用代理会减轻被禁止ip的风险;
# -*- coding: utf-8 -*-
from urllib import parse, request,error
from urllib.request import ProxyHandler,build_opener
httpproxy_handler = ProxyHandler({
'http': 'http://127.0.0.1:8088',
'https': 'https://127.0.0.1:8089'
})
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36'
}
# 获得opener
opener = build_opener(httpproxy_handler)
# 封装请求
try:
# 打开请求获得响应
request.install_opener(opener)
req = request.Request(url='http://httpbin.org/get',headers=headers,method='GET')
response = request.urlopen(req)
print(response.read().decode('utf-8'))
except error.URLError as e:
print(e.reason)
3.4 获取cookie
请求登陆认证成功后可以保存登陆的cookie进行下次访问,避免短时间内再次登陆;故熟悉cookie的存储形式也是必备技能,需要引入 http.cookiejar
模块;
# -*- coding: utf-8 -*-
from urllib import parse, request,error
from urllib.request import ProxyHandler,build_opener
import http.cookiejar
url = 'https://www.baidu.com/'
cookie = http.cookiejar.CookieJar()
handler = request.HTTPCookieProcessor(cookie)
openner = request.build_opener(handler)
response = openner.open(url)
for item in cookie:
print(item.name,'=',item.value)
输出
BAIDUID = 74C3ABAC91163C679A5FBF2327C70797:FG=1
BIDUPSID = 74C3ABAC91163C67D24147EFB5469FBE
PSTM = 1582166990
BD_NOT_HTTPS = 1
3.5 保存cookie
对某个网站进行保存cookie可以使用cookie.save()
函数
# -*- coding: utf-8 -*-
from urllib import parse, request,error
from urllib.request import ProxyHandler,build_opener
import http.cookiejar
filename = 'cookies.txt'
url = 'https://www.baidu.com/'
cookie = http.cookiejar.MozillaCookieJar(filename)
handler = request.HTTPCookieProcessor(cookie)
openner = request.build_opener(handler)
response = openner.open(url)
cookie.save(ignore_discard=True,ignore_expires=True)
四 parse模块
urllib的parse模块是指对url的操作,比如切割,重组,参数分离等等;
4.1 urlparse解析url
将一个url进行调用urlparse
方法解析会返回一个元组,具体的组成内容可以看输出结果;一般比较重要的就是协议,域名,路径,参数;
# -*- coding: utf-8 -*-
from urllib import parse, request,error
url = 'https://www.baidu.com/index.html;user?id=666#zszxz'
result = parse.urlparse(url)
print(result)
输出
ParseResult(scheme='https', netloc='www.baidu.com', path='/index.html', params='user', query='id=666', fragment='zszxz')
4.2urlunparse构造url
urlparse 是解析 url ; urlunparse 则是对应的构造url
# -*- coding: utf-8 -*-
from urllib import parse, request,error
data = ['https', 'www.baidu.com', '/index.html', 'user', 'id=66', 'zszxz']
result = parse.urlunparse(data)
print(result)
输出
https://www.baidu.com/index.html;user?id=66#zszxz
4.3 url拼接
使用urljoin 可以将两个部分组成一个整体
# -*- coding: utf-8 -*-
from urllib import parse, request,error
print(urllib.parse.urljoin('https://www.baidu.com/','FAQ.html'))
输出
https://www.baidu.com/FAQ.html
4.4 get参数构造
对已知的url进行get参数构造,就可以达到发送带有参数get请求的效果;
# -*- coding: utf-8 -*-
from urllib import parse, request,error
params = {
'name': 'zszxz',
'age': '23'
}
base_url = 'https://blog.csdn.net/youku1327?'
encode_param = parse.urlencode(params)
url = base_url + encode_param
print(url)
输出
https://blog.csdn.net/youku1327?name=zszxz&age=23
4.5 获取参数为字典
将url中的参数转为字典可以使用parse_qs
函数
# -*- coding: utf-8 -*-
from urllib import parse, request,error
query = 'name=zszxz&age=23'
reuslt = parse.parse_qs(query)
# {'name': ['zszxz'], 'age': ['23']}
print(reuslt)
4.6 获取参数为元组
将url中的参数转为元组可以使用parse_qsl()
函数
# -*- coding: utf-8 -*-
from urllib import parse, request,error
query = 'name=zszxz&age=23'
reuslt = parse.parse_qsl(query)
# [('name', 'zszxz'), ('age', '23')]
print(reuslt)
4.7 url编码
一般网站的url参数都是有固定的编码格式,比如 空格表示为20%,为了解析url为人类可读的模式,就可以使用
quote()
进行解码;
# -*- coding: utf-8 -*-
from urllib import parse, request,error
url = 'https://www.baidu.com/index.html;user?id=5#comment'
q = parse.quote(url)
# https%3A//www.baidu.com/index.html%3Buser%3Fid%3D5%23comment
print(q)
4.8 url解码
同理有url解码,就有url编码,处于安全考虑可以使用;
# -*- coding: utf-8 -*-
from urllib import parse, request,error
url = 'https%3A//www.baidu.com/index.html%3Buser%3Fid%3D5%23comment'
q = parse.unquote(url)
# https://www.baidu.com/index.html;user?id=5#comment
print(q)
五 robot协议
robot协议是重中之重,希望知识追寻者的读者都是理性的人,不要觉得学习了一些技术就胡乱爬取网站数据,应当先请求网站的robot协议,如果返回是true就是可以爬取,反之不可爬取;robot的url构造也很简单,就是在url后面加上robots.txt
即可;
# -*- coding: utf-8 -*-
from urllib.robotparser import RobotFileParser
# 设置robot解析
rp = RobotFileParser()
# 设置协议路径
rp.set_url('https://www.baidu.com/robots.txt')
# 读取协议
rp.read()
# 是否可爬取
fet = rp.can_fetch('*', 'https://www.baidu.com/')
print(fet)
输出
False
转载:https://blog.csdn.net/youku1327/article/details/104580525