发送请求 - urllib.request
使用urllib.request模块,提供了最基本的构造HTTP请求的方法,利用它可以模拟浏览器的一个请求发起过程,同时还带有处理授权验证(authentication)、重定向(redirection)、浏览器Cookies 以及其他内容。
urlopen()
urlopen() 的基本使用
1 | import urllib.request |
报错:urllib.error.URLError:
解决:Python 坑之CERTIFICATE_VERIFY_FAILED
1 | import urllib.request |
- class ‘http.client.HTTPResponse’
- 是一个HTTPResponse类型的对象
- 包含read()、readinto()、getheader(name)、getheaders()、fileno()等方法
- 包含msg、version、status、reason、debuglevel、closed等属性
urlopen()函数的API
1 | urllib.request.urlopen(url, data=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, |
data
- data=bytes(data),data接收的内容必须是bytes类型
一旦使用这个参数,请求方式变为POST
1
2
3
4
5
6import urllib.request
import urllib.parse
data = bytes(urllib.parse.urlencode({'Hello':'World'}),encoding='utf-8')
response = urllib.request.urlopen('http://httpbin.org/post',data=data)
print(response.read())
timeout
timeout参数用于设置超时时间,单位为秒,请求超过这个设置时间,还没有得到响应,就会抛出异常。
1
2
3
4
5
6
7
8
9
10
11
12import urllib.request
response = urllib.request.urlopen('http://httpbin.org/get',timeout=0.1)
print(response.read())
'''
运行结果:
urllib.error.URLError: <urlopen error timed out>
错误原因超时
设置为超时时间为0.1秒,0.1秒过后,程序无响应,于是抛出URLError异常
URLError属于urllib.error模块,
'''设置超时时间来控制一个网页如果长时间未响应,就跳过它的抓取。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21import urllib.request
import urllib.error
import socket
try:
response = urllib.request.urlopen('http://httpbin.org/get',timeout=0.1)
except urllib.error.URLError as e:
if isinstance(e.reason, socket.timeout):
print('TIME OUT')
'''
判断异常是不是socket.timeout类型,就是超时异常,从而确定它确实是因为超时而报错
isinstance(object,classinfo):
判断一个对象是否是一个已知的类型
object == classinfo
isinstance 和 type() 的区别:
type()不能判断子类的实例化对象是不是属于父类
推荐使用isinstance()
'''context:必须是ssl.SSLContext类型,用来指定SSL设置
- cafile:指定CA证书
capth:指定CA证书的路径
Request()
使用urlopen()方法可以实现最基本的请求的发起,在之前的学习中, 就已经发现,它有一定的限制条件,并且可以从它的API接口中发现,参数也十分的简单,不足以构建一个完整的请求,那么Request类就能构建一个完整的需求。
Request()的基本使用
1
2
3
4
5
6
7import urllib.request
# 将请求独立成一个对象,这样可以丰富、灵活的配置参数
request = urllib.request.Request('http://httpbin.org/get')
# 依然使用urlopen来发送请求
response = urllib.request.urlopen(request)
print(response.read().decode('utf-8'))Request()函数的API
1
2
3urllib.request.Request(url, data=None, headers={},
origin_req_host=None, unverifiable=False,
method=None)url:
- 请求url,必传参数,其他都是可选
- data:
- 和urllib.request.urlopen()中一样,必须传bytes类型
- 如果传的类型是字典,可以先用urllib.parse.urlencode()编码
- headers:
- 是字典类型,请求头
- 可以在构造请求时通过headers参数直接构造
- 另一种方式通过调用add_headers()方法添加,动态添加
- origin_req_host:
- 请求方的host名称或者ip地址
- unverifiable:
- 表示这个请求是否是无法验证的,默认为False,意思就是用户没有足够的权限来选择接受这个请求的结果
method:
- 用来指示请求使用的方法,比如GET、POST、PUT等
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41from urllib import request,parse
# url
url = 'http://httpbin.org/post'
# 请求头
headers = {
'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'
}
# post请求数据
data = {
'name':'David'
}
# 传的类型是字典,所以要先用urllib.parse.urlencode()编码,指定编码格式为utf-8
data = bytes(parse.urlencode(data),encoding='utf-8')
# 构建POST请求
request = request.Request(url=url,data=data,headers=headers,method='POST')
response = request.urlopen(request)
# bytes用utf-8解码
print(response.read().decode('utf-8'))
'''
返回结果:
{
"args": {},
"data": "",
"files": {},
"form": {
"name": "David" # data传入的数据出现在form中,只有post请求才有
},
"headers": {
"Accept-Encoding": "identity",
"Content-Length": "10",
"Content-Type": "application/x-www-form-urlencoded",
"Host": "httpbin.org",
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36"
},
"json": null,
"origin": "61.171.88.179, 61.171.88.179",
"url": "https://httpbin.org/post"
}
'''Handler
Handler中有各种处理器,例如专门处理登陆验证,处理cookies的,处理代理设置等,利用这些我们可以做到HTTP请求中的所有事情。
BaseHandler类
BaseHandler类是,所有其他Handler的父类,它提供了最基本的方法,例如:default_open()、protocol_request()等
HTTPDefaultErrorHandler: 用于处理http响应错误,错误抛出HTTPError类型的异常
- HTTPRedirectHandler:用于处理重定向
- HTTPCookieProcessor:用于处理Cookies
- ProxyHandler:用于设置代理,默认代理为空
- HTTPPasswordMgr:用于管理密码,它维护用户名和密码表
HTTPBasicAuthHandler:用于管理认证,当链接需要认证时,它可以解决认证问题
OpenerDirector类
通常称OpenerDirector为Opener,之前的urlopen()和Request就是urllib为我们封装了极其常用的请求方法,更多功能需要用到底层的实例来完成操作,所以要用到Opener。
验证
请求网站时,弹出提示框,提示你需要输入用户名和密码,验证后才能查看页面
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22from urllib.request import HTTPPasswordMgrWithDefaultRealm,HTTPBasicAuthHandler,build_opener
from urllib.error import URLError
username = 'username'
password = 'password'
url = 'http://0.0.0.0/#/Auth/get_basic_auth__user___passwd_'
p = HTTPPasswordMgrWithDefaultRealm()
# 利用add_password添加进去用户名和密码
p.add_password(None,url,username,password)
# 建立一个处理验证的Handler
# 实例化HTTPBasicAuthHandler对象,其参数是HTTPPasswordMgrWithDefaultRealm对象
auth_handler = HTTPBasicAuthHandler(p)
# 利用Handler使用build_opener()方法构建一个Opener
opener = build_opener(auth_handler)
try:
result = opener.open(url)
html = result.read().decode('utf-8')
print(html)
except URLError as e:
print(e.reason)代理
爬虫免费代理
1
2
3
4
5
6
7
8
9
10
11
12
13
14from urllib.request import ProxyHandler,build_opener
from urllib.error import URLError
proxy_handler = ProxyHandler({
'http':'http://0.0.0.0:9999',
# 可以去西刺copy两个注意区分http和https,当然还有socks服务器
'https':'https://0.0.0.0:9999'
})
opener = build_opener(proxy_handler)
try:
response = opener.open('http://www.baidu.com')
print(response.read().decode('utf-8'))
except URLError as e:
print(e.reason)爬虫付费代理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17# 方式一
import urllib.request
#1.用户名密码和代理
username = 'username'
password = 'password'
proxy = '127.0.0.1:8080'
#2.创建密码管理器,添加用户名和密码
password_manager = urllib.request.HTTPPasswordMgrWithDefaultRealm()
password_manager.add_password(None,proxy_money,use_name,pwd)
#3.创建可以验证代理ip的处理器
handle_auth_proxy = urllib.request.ProxyBasicAuthHandler(password_manager)
#4.根据处理器创建opener
opener_auth = urllib.request.build_opener(handle_auth_proxy)
#5.发送请求
response = opener_auth.open("http://www.baidu.com")
print(response.read())1
2
3
4
5
6
7
8
9# 方式二
#1.代理ip
money_proxy ={"http":"username:password@192.168.12.11:8080"}
#2.代理的处理器
proxy_handler=urllib.request.ProxyHandler(money_proxy)
#3.通过处理器创建opener
opener = urllib.request.build_opener(proxy_handler)
#4.open发送请求
opener.open("http://www.baidu.com")Cookies
获取网站cookies
1
2
3
4
5
6
7
8
9
10
11
12
13import http.cookiejar
import urllib.request
# 声明一个CookieJar对象
cookies = http.cookiejar.CookieJar()
# 利用HTTPCookieProcessor构建一个handler
handler = urllib.request.HTTPCookieProcessor(cookies)
# 构建opener
opener = urllib.request.build_opener(handler)
response = opener.open('http://www.baidu.com')
print(type(cookies))
for cookie in cookies:
print(cookie.name + '=' + cookie.value)将cookies保存为文件
1
2
3
4
5
6
7
8
9
10
11import urllib.request
import http.cookiejar
# 保存cookies的文件名
filename = 'cookies.txt'
# 生成文件时,需要用到MozillaCookieJar 是 CookieJar的子类,处理和cookies和文件有关的事件
cookie = http.cookiejar.MozillaCookieJar(filename)
handler = urllib.request.HTTPCookieProcessor(cookie)
opener = urllib.request.build_opener(handler)
response = opener.open('http://www.baidu.com')
cookie.save(ignore_discard=True, ignore_expires=True)从文件中读取cookies
1
2
3
4
5
6
7
8
9
10
11import urllib.request
import http.cookiejar
# 什么格式存的 就选什么格式
cookie = http.cookiejar.MozillaCookieJar()
# 用load()方法读取本地的cookies文件,获取cookies内容
cookie.load('cookies.txt', ignore_expires=True, ignore_discard=True)
handler = urllib.request.HTTPCookieProcessor(cookie)
opener = urllib.request.build_opener(handler)
response = opener.open('http://www.baidu.com')
print(response.read().decode('utf-8'))