1 添加头信息 {#1-}
1.1 User-Agent {#1-1-user-agent}
有些网站,如果你按照urllib.request.urlopen('https://www.baidu.com') 这种方式打开,服务器有可能不会响应,所以要完全模仿浏览器访问,我们需要加入User-Agent信息,示例代码如下:
[sourcecode language="plain"]
from urllib import request
req = request.Request('https://www.baidu.com')
req.add_headers('User-Agent', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:57.0) Gecko/20100101 Firefox/57.0') ①
response = request.urlopen(req)
[/sourcecode]
①通过 Request.add_header(key, val)添加字典形式的头信息,不能传多个头信息,前面的会被后面的覆盖。User-Agent 首部包含了一个特征字符串,用来让网络协议的对端来识别发起请求的用户代理软件的应用类型、操作系统、软件开发商以及版本号。如何获取User-Agetn信息呢?
可以用火狐或者谷歌浏览器,F12打开调试模式,我用的火狐,截图如下:
1.2 Referer {#1-2-referer}
Referer 首部包含了当前请求页面的来源页面的地址,即表示当前页面是通过此来源页面里的链接进入的。服务端一般使用 Referer 首部识别访问来源,可能会以此进行统计分析、日志记录以及缓存优化等。有些服务器会识别headers中的referer是不是它自己,如果不是,不会响应,所以我们还可以在headers中加入referer。
可以打开F12看下Referer具体效果,我手动输入网址打开百度后,头信息如下:
我在直接点击网页上的新闻连接,看下头信息内容:
是不是多了Referer,显示来源页面是我手动打开的百度首页。
添加Referer方式与添加User-Agent一样,如下:
[sourcecode language="plain"]
略
req.add_headers('Referer', 'https://www.baidu.com')
略
[/sourcecode]
2 ProxyHandler {#2-proxyhandler}
[sourcecode language="plain"]
proxy_handler = urllib.request.ProxyHandler({'http': 'http://www.example.com:3128/'}) ①
opener = urllib.request.build_opener(proxy_handler) ②
This time, rather than install the OpenerDirector, we use it directly:
opener.open('http://www.example.com/login.html') ③
[/sourcecode]
①创建一个代理处理器ProxyHandler,接收的参数类型为字典{'协议': '代理ip: 端口'}
②从一个proxy_handler程序列表中创建一个opener对象,urllib.request.urlopen()函数实际上是使用的是默认的opener,这里相当于定制了自己的opener
③通过opener对象打开url
3 异常处理urllib.error {#3-urllib-error}
urllib.error模块定义了由urllib.request引起的异常的异常类。基本的异常类是URLError。
3.1 URLError {#3-1-urlerror}
URLError是OSError的一个子类,HTTPError是URLError的一个子类我们先来看URLError异常
[sourcecode language="plain"]
-*- coding: utf-8 -*-
from urllib import request
from urllib import error
if name == "main":
req = request.Request('http://www.demo.com')
try:
response = request.urlopen(req)
html = response.read().decode('utf-8')
print(html)
except error.URLError as e:
print(e.reason)
[/sourcecode]
执行结果返回如下图:
3.2 HTTPError异常 {#3-2-httperror-}
[sourcecode language="plain"]
-*- coding: utf-8 -*-
from urllib import request
from urllib import error
if name == 'main':
req = request.Request('http://mirrors.163.com/centos/7.4.1708/isos/x86_64/sha2sum.txt')
try:
response = request.urlopen(req)
except error.HTTPError as e:
print(e)
[/sourcecode]
执行文件结果:
3.3 urllib.error.ContentTooShortError {#3-3-urllib-error-contenttooshorterror}
urllib.error.ContentTooShortError异常是因为文件下载不完全导致的错误,这个错误不好复现,就简单举例说明:
[sourcecode language="plain"]
-*- coding: utf-8 -*-
from urllib import request
from urllib import error
if name == "main":
req = request.Request('https://download.demo.com')
filename = 'E:\test3.txt'
try:
request.urlretrieve(req, filename)
except error.ContentTooShortError as e:
print(e)
[/sourcecode]
3.4 HTTPError和URLError同时使用 {#3-4-httperror-urlerror-}
同时使用,需要将HTTPError放在URLError的前面,因为HTTPError是URLError的一个子类。如果URLError放在前面,出现HTTP异常会先响应URLError,这样HTTPError就捕获不到错误信息了。
如果不用上面的方法,也可以使用hasattr函数判断URLError的属性,如果含有reason属性表明是URLError,如果含有code属性表明是HTTPError。