飞道的博客

原来urllib是这样学会的

339人阅读  评论(0)

一 前言

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
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场