你 urlib库为python3的HTTP内置请求库
urilib的四个模块:
- urllib.request:它是最基本的HTTP请求模块,可以用来模拟发送请求。就像在浏览器里输入网址然后回车一样,只需要给库方法传入URL以及额外的参数,就可以模拟实现这个过程了。
- urllib.error:异常处理模块,用于处理异常的模块
- urllib.parse:用于解析url,一个工具模块,提供了许多URL处理方法,比如拆分、解析、合并等。
- urllib.robotparse:用于解析robots.txt,主要用于看哪些网站不能进行爬取,不过少用
urllib的用法
urllib.request.urlopen(url, data=None, [timeout, ]*, cafile=None, capath=None, cadefault=False, context=None)
urllib.request.urlopen(url, data=None, timeout=<object object at 0x000002407EBBC770>, *, cafile=None, capath=None, cadefault=False, context=None)
- url:为请求网址
- data:请求时需要发送的参数
- timeout:超时设置,在该时间范围内返回请求内容就不会报错
发送请求
urlopen()它可以模拟浏览器的一个请求发起过程,同时它还带有处理授权验证(authenticaton)、重定向(redirection)、浏览器Cookies以及其他内容
import urllib.request # 导入urllib.request模块,提供了最基本的构造HTTP请求的方法
response = urllib.request.urlopen('http://www.baidu.com') # 以python官网为例,把这个页面爬取下来
print(response.read().decode('utf-8')) # read()方法得到返回的网页内容
运行结果:输出的是网页的源代码。得到代码后,我们想要的链接、图片地址、文本信息就都可以提取出来。
print(type(response)) # 输出响应类型
print(',,,,,,,,,,,,')
print(response.status) # 返回结果的状态码
print(',,,,,,,,,,,,')
print(response.getheaders()) # 响应的头信息
print(',,,,,,,,,,,,')
print(response.getheader('Server')) # 响应头中的Server值,nginx意思是服务器用nginx搭建的
- HTTPResponse类型对象,主要包含:read()、readinto()、getheader(name)、getheaders()、fileno()等方法,以及msg、version、status、debuglevel、closed等属性,得到这个对象之后,我们把它赋值为response变量,然后就可以调用这些方法和属性,得到返回结果的一系列信息了。
- 调用read()方法可以得到返回的网页内容,调用status属性可以得到返回结果的状态码,如:200代表请求成功,404代表网页未找到等。
- 前两个输出分别输出了响应的状态码和响应的头信息,最后一个输出通过调用getheader()方法并传递一个参数Server获取了响应头中的Server值,结果是nginx,意思是服务器是用Nginx搭建的。利用最基本的urlopen()方法,可以完成最基本的简单网页的GET请求抓取。
- data参数
请求时加载数据
data参数是可选的,参数需是bytes类型,如果不是,则需要通过bytes()方法转化,另外传递了 这个参数,则它的请求方式就不再是GET方式,而是POST方式
import urllib.parse
import urllib.request
data = bytes(urllib.parse.urlencode({'word':'hello'}), encoding = 'utf8') # 传递一个参数word,值为hello,需要被转码为bytes类型
response = urllib.request.urlopen('http://httpbin.org/post',data=data)
print(response.read())
- timeout参数
timeout参数,如果不指定,就会使用全局默认时间,超时设置,在该时间范围内返回请求内容就不会报错,单位为秒,超过设置的时间,还没有得到响应,就会抛出异常,该异常属于urllib.error模块,错误原因是超时。
判断超时请求,一个网页如果长时间未响应,就跳过它的抓取。
import socket
import urllib.error
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')
运行结果:TIME OUT
按照常理来说,0.1秒内基本不可能得到服务器响应,通过设置timeout这个参数来实现超时处理,因此输出了TIMEOUT的提示
context参数,它必须是ssl.SSLContext类型,用来指定SSL设置
caflie和capath这两个参数分别指定CA证书和它的路径,这个在请求HTTPS链接时会有用
cadefault已经弃用,默认为False
如果希望返回与当前环境有关的信息,我们可以使用info()返回,比如可以执行
>>>response.info()
<http.client.HTTPMessage object at 0x0000000003623D68>
- 可以看到,输出了对应的info,调用格式则为:“爬取的网页.info()”,我们之前爬取到的网页赋给了变量response,所以此时通过response调用。
- 如果想要获取当前所爬取的URL地址,我们可以使用geturl()来实现
>>>response.geturl()
'http://www.baidu.com'
quote() unquote()
一般来说,URL标准中只会允许一部分ASCII字符比如数字、字母、部分符号等,而其他的一些字符,比如汉字等,是不符合URL标准的。此时,我们需要编码。
如果要进行编码,我们可以使用urllib.request.quote()进行,对编码的网址进行解码
urllib.request.unquote
#对百度网址进行编码
>>>urllib.request.quote('http://www.baidu.com')
'http%3A//www.baidu.com'
#对编码的网址进行解码
>>>urllib.request.unquote('http%3A//www.baidu.com')
'http://www.baidu.com'
from urllib.parse import quote
keyword = '洪远的博客'
url = 'www.baidu.com/s?wd=' + quote(keyword)
print(url)
运行结果:
www.baidu.com/s?wd=%E6%B4%AA%E8%BF%9C%E7%9A%84%E5%8D%9A%E5%AE%A2
from urllib.parse import unquote
url = 'www.baidu.com/s?wd=%E6%B4%AA%E8%BF%9C%E7%9A%84%E5%8D%9A%E5%AE%A2'
print(unquote(url))
运行结果:
www.baidu.com/s?wd=洪远的博客
Request方法
urlopen()方法可以实现最基本的发送,但如果想要构建一个完整的请求,在请求中需要加入Headers等信息,就可以利用更强大的Request类来构建
使用Request来请求网页,将请求独立成一个对象
import urllib.request
request = urllib.request.Request('https://python.org')
response = urllib.request.urlopen(request)#还用urlopen()方法来发送请求,只不过这次该方法的参数不再是URL,而是一个Request类型的对象
print(response.read().decode('utf-8'))
Request基本格式:
urllib.request.Request(url, data=None, headers={}, origin_req_host=None, unverifiable=False, method=None)
- url:用于请求URL,必传参数
- data:如果要传,必须传bytes类型,如果它是字典,可以先用urllib.parse模块里的urlencode()编码
- headers:请求头,我们可以在构造请求时通过headers参数值构造,也可以通过调用请求实例的add_header()方法添加,常用于通过修改User-Agent来伪装浏览器
- origin_req_host:指的是请求方的host名称或者IP地址
- unverifiable:这个请求是否是无法验证,默认False,即用户没用足够权限来选取接受这个请求的结果
- method:是一个字符串,用来只是请求的方法,比如:GET、POST、PUT等
浏览器的模拟—Headers属性
任意打开一个网页,比如打开http://httpbin.org/post。然后按F12(或者Fn+F12),会出现一个窗口。切换到Network(网络)标签页:
然后让网页发生一个动作。
我们可以观察到右边的窗口出现了一些数据。将界面右上方的标签切换到“Headers”(标头)中,即可以看到了对应的头信息,此时往下拖动,在请求标头中的最后一行,就可以找到User-Agent字样的一串信息。这一串信息即是我们下面模拟浏览器所需要用到的信息。我们将其复制出来。
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/18.17763
#通过Request请求参数来请求网页
from urllib import request,parse
url = 'http://httpbin.org/post' # 请求URL
headers = { # headers指定User-Agent,Host
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36',
'Host':'httpbin.org'
}
dict = {
'name':'Germey'
}
data = bytes(parse.urlencode(dict), encoding='utf8') # 参数转化为字节流
req = request.Request(url=url, data=data, headers=headers, method='POST') # 指定请求方式为POST
response = request.urlopen(req)
print(response.read().decode('utf-8'))
#通过Request.add_header方法来请求网页
from urllib import request,parse
url = 'http://httpbin.org/post' # 请求URL
dict= {
'name':'Germey'
}
data = bytes(parse.urlencode(dict), encoding='utf8') # 参数转化为字节流
req = request.Request(url = url, data = data, method='POST')
req.add_header('User-Agent','Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36')
response = request.urlopen(req)
print(response.read().decode('utf-8'))
运行结果:
首先,导入urllib中的request,parse,设置要爬取的网址,然后调用request.Request()函数创建一个req对象,该函数第一个参数传入url,第二个参数可以传入数据,默认是传入0数据,第三个参数是传入头部,该参数也是有默认值的,默认是不传任何头部。
我们需要创建一个dict,将头部信息以键值对的形式存入到dict对象中,然后将该dict对象传入request.Request()函数第二个参数。
此时,已经成功设置好报头,然后我们使用urlopen()打开该Request对象即可打开对应的网址。