Python标准库:Urllib库

Urllib库是Python用于操作Url的标准模块,Python2.x时分为Urllib和Urllib2,Python3.x时合并到Urllib里面。这里把常见的变化列举一下,便于查找修改。
官方文档:https://docs.python.org/3.6/library/urllib.html

Python2.x Python3.x
import urllib2 import urllib.request,urllib.error
import urllib import urllib.request,urllib.error,urllib.parse
import urlparse import urllib.parse
urllib2.urlopen urllib.request.urlopen
urllib2.request urllib.request.Request
urllib.quote urllib.request.quote
urllib.urlencode urllib.parse.urlencode
cookielib.CookieJar http.CookieJar
  1. 简单读取网页信息:urllib需制定内容的解码方式,requests可自动解码。
import urllib.request  
f = urllib.request.urlopen('http://python.org/') 
html1 = f.read()   #urlopen返回的是bytes对象,此时调用read()方法得到的也是bytes对象。
html2 = f.read().decode('utf-8')    #要获取字符串内容,需要指定解码方式。因此,更常用html2的方式。

#还可以写成以下方式:
import urllib.request
with urllib.request.urlopen('http://python.org') as f:
    html = f.read().decode('utf-8')
    print(f.status)
    print(html)

#html等价于requests库的r.text:
import requests
r = requests.get('http://python.org') 
print(r.status_code)
print(r.text)        #调用r.text时,Requests对象会使用其推测的文本编码自动解码。
print(r.encoding)    #查询Requests对象使用的编码方式。
r.encoding = 'utf-8'  #可直接通过赋值语句来改变Requests对象使用的编码方式。

2.urllib对含中文的URL进行手动编码

import urllib.request
a = urllib.request.quote("中文")
b = urllib.request.unquote(a)
print(a,b)

结果为:%E4%B8%AD%E6%96%87 中文

3.使用Request对象添加headers进行请求

import urllib.request
hds = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36'}
req = urllib.request.Request('http://python.org')
req.add_header('User-Agent','Mozilla/5.0')  ##注意参数是用“,”进行分隔。
#req.add_header('User-Agent',hds['User-Agent'])  #另一种写法
with urllib.request.urlopen(req) as f:    ##urlopen可放入url或Request对象
    html = f.read().decode('utf-8')

#requests方法
import requests
hds = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36'}
r = requests.get('http://python.org',headers=hds)

4.超时设置

import urllib.request
#加上timeout参数即可
f = urllib.request.urlopen(req,timeout=1)
f = urllib.request.urlopen('http://python.org',timeout=1)

#完整用法(正常响应1秒,若网站服务器性能不好时可适当调高timeout值)
import urllib.request
for i in range(10):   #若超时,重复请求10次
    try:
        f = urllib.request.urlopen('http://python.org',timeout=1)
        print(f.read().decode('utf-8')[:100])
        break
    except Exception as e:
        print("出现异常: "+str(e))
        # print(type(e))

#requests库类似
for i in range(10):   #若超时,重复请求10次
    try:
        r = requests.get('http://python.org',timeout=0.25)   #响应比urllib.request快
        print(r.text[:100])
        break
    except Exception as e:
        print("第{}次请求出现异常:".format(str(i+1))+str(e))
        print(type(e))


5.下载HTML文件到本地
同理:图片、MP3、视频等文件格式也是用‘wb’形式下载。

#方法一:
import urllib.request

html = urllib.request.urlopen("http://www.baidu.com").read()
with open("1.html","wb") as f:     #使用b模式写入,此时传入的html不需解码
    f.write(html)


#方法二:最方便
#urlretrieve(url, filename=None, reporthook=None, data=None)  
#reporthook(可选)是回调函数,可以显示下载进度。
#data(可选)指post到服务器的数据。

import urllib.request
urllib.request.urlretrieve("http://www.baidu.com",filename="1.html")
#urllib.request.urlretrieve("http://www.baidu.com","1.html") 


#方法三:
import requests

r = requests.get("http://www.baidu.com")
with open("1.html",'wb') as f:
    f.write(r.content)

# 其他格式:
urllib.request.urlretrieve("XXX.jpg",filename="1.jpg")      #XXX表示服务器地址
urllib.request.urlretrieve("XXX.mp3",filename="1.mp3")
urllib.request.urlretrieve("XXX.rmvb",filename="1.rmvb")


6.get请求实例
get请求的url地址格式:http://网址?字段名1=内容1&字段名2=内容2
http://www.baidu.com/s?wd="python"&rqlang=cn # wd代表关键字, rqlang代表区域

import urllib.request

base_url = "http://www.baidu.com/s?wd="
keyword = "Python爬虫"
url = base_url + urllib.request.quote(keyword)
html = urllib.request.urlopen(url).read()
with open("1.html","wb") as f:
    f.write(html)

#requests库
import requests

base_url = "http://www.baidu.com/s?wd="
keyword = "Python爬虫"
url = base_url + keyword     #requests模块自动解析含中文的url
r = requests.get(url)
#print(r.url)                #可查看解析后的url
with open("2.html","wb") as f:
    f.write(r.content)


7.使用代理:urllib.request.ProxyHandler

import urllib.request  
 
# 创建代理字典
proxy1={'sock5': 'localhost:1080'}
proxy2={'http': '183.51.191.203:9797'}
# 使用ProxyHandler方法生成处理器对象
proxy_handler = urllib.request.ProxyHandler(proxy1) 
# 创建代理IP的opener实例
opener = urllib.request.build_opener(proxy_handler)  
# 创建全局默认的open对象,使用urlopen()时会自动使用已经安装的opener对象
urllib.request.install_opener(opener) 
  
a = urllib.request.urlopen("http://www.baidu.com").read().decode("utf8")  
print(len(a))


8.开启Debuglog:urllib.request.HTTPHandler,urllib.request.HTTPSHandler

import urllib.request

http_handler = urllib.request.HTTPHandler(debuglevel=1)
https_handler = urllib.request.HTTPSHandler(debuglevel=1)
opener = urllib.request.build_opener(http_handler,https_handler)
urllib.request.install_opener(opener)
urllib.request.urlopen("https://www.baidu.com")


9.异常处理:URLError,子类HTTPError

  • 触发URLError的原因有以下四种可能:
    ①连接不上服务器
    ②远程URL不存在
    ③无网络
    ④触发HTTPError
  • #写法一:
    import urllib.request
    import urllib.error
    
    try:
        # urllib.request.urlopen("http://www.google.com")       #对应URLError
        urllib.request.urlopen("https://login.taobao.com/member")   #对应HTTPError
    except urllib.error.HTTPError as e:
        print(e.code,e.reason)
    except urllib.error.URLError as e:
        print(e.reason)
    
    #写法二:
    import urllib.request
    import urllib.error
    
    try:
        #urllib.request.urlopen("http://www.google.com")
        urllib.request.urlopen("https://login.taobao.com/member")
    except urllib.error.URLError as e:
        if hasattr(e,"code"):        #hasattr是自带函数,详见下方。
            print(e.code)
        if hasattr(e,"reason"):
            print(e.reason)
    
    '''
    hasattr(obj, name, /)
        Return whether the object has an attribute with the given name.
        
        This is done by calling getattr(obj, name) and catching AttributeError.
    '''
  • HTTP状态码以及含义
状态码 (e.code) 英文(e.reason) 含义
200 OK 一切正常
301 Moved Permanently 重定向到新的URL,永久性
302 Found 重定向到新的URL,非永久性
304 Not Modified 请求的资源未更新
400 Bad Request 非法请求
401 Unauthorized 请求未经授权
403 Forbidden 禁止访问
404 Not Found 没有找到对应页面
500 Internal Server Error 服务器内部错误
501 Not Implemented 服务器不支持实现请求所需要的功能

10.post请求

import urllib.request
import urllib.parse

url = "https://www.douban.com/accounts/login"
params = {'source':'index_nav',
          'form_email':'XXXX',     #账号
          'form_password':'XXXX'   #密码
          }
postdata = urllib.parse.urlencode(params).encode('utf-8')  #对数据进行编码
req = urllib.request.Request(url,postdata)
html = urllib.request.urlopen(req).read()
with open('1.html','wb') as f:
    f.write(html)

#requests库
import requests
url = "https://www.douban.com/accounts/login"
params = {'source':'index_nav',
          'form_email':'XXXX',     #账号
          'form_password':'XXXX'   #密码
          }
r = requests.post(url,params)
with open('1.html','wb') as f:
    f.write(r.content)


#注:
urlencode:对key-value的字典数据进行编码转换,返回类似“a=XXX&b=XXX”的结果。
quote:对单个字符串进行编码转换,返回编码后的一串字符,多用于中文字符的编码。

11.使用cookies

import urllib.request
import urllib.parse
import http.cookiejar
url = "https://www.douban.com/accounts/login"
params = {'source':'index_nav',
          'form_email':'XXXX',     #账号
          'form_password':'XXXX'   #密码
          }
postdata = urllib.parse.urlencode(params).encode('utf-8')  #对数据进行编码
req = request.Request(url, postdata, method="POST")  # 构建Request对象

#创建CookieJar对象
cj = http.cookiejar.CookieJar()
pro = urllib.request.HTTPCookieProcessor(cj)
opener = urllib.request.build_opener(pro)
# 创建全局默认的open对象,使用urlopen()时会自动使用已经安装的opener对象
urllib.request.install_opener(opener)

html1 = urllib.request.urlopen(req).read()
with open('1.html', 'wb') as f:
    f.write(html1)


#requests库
import requests
url = "https://www.douban.com/accounts/login"
headers = {
    'Cookie':'xxxxxxx'
}
r = requests.get(url,headers=headers)
print(r.text)

作者:橄榄的世界
链接:https://www.jianshu.com/p/d68d3cbce5a0
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。