七.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)
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,830评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,992评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,875评论 0 331
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,837评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,734评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,091评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,550评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,217评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,368评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,298评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,350评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,027评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,623评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,706评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,940评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,349评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,936评论 2 341

推荐阅读更多精彩内容