urlib是Python内置的HTTP请求库,它包含以下4个模块:
发送请求request
它是最基本的HTTP请求模块,可以用来模拟发送请求,只需要给库方法传入URL以及其他参数,就可以模拟发送请求。
1. urlopen()
urllib.request模块提供了最基本的构造HTTP请求的方法。利用urlopen()可以模拟浏览器的一个请求发起过程,同时它还可以处理授权验证、重定向、浏览器Cookies等。
import urllib.request
response = urllib.request.urlopen('https://www.csdn.net/')
print(response.read().decode('utf-8'))
运行结果如下图所示:
这是最基本的urlopen()的用法,我们还可以添加data参数。首先看一下urlopen()函数的API:
urllib.request.urlopen(url, data-None, [timeout, ]*, cafile=None, cadafault=False, context=None)
参数 | 用法 |
---|---|
data | 可选,如果添加该参数,并且它是bytes类型,则需要通过bytes()方法转化。另外,如果传递这个参数,它的请求方式变为POST方式 |
timeout | 可选,用于设置超时时间,单位为秒,它支持HTTP、HTTPS、FTP请求 |
其他参数 | context参数,必须是ssl.SSLContext类型,用来指定SSL设置;cafile和capath分别指定CA证书和它的路径。 |
2. request
import urllib.request
request = urllib.request.Request('https://python.org')
respomse = urllib.request.urlopen(request)
print(response.read().decode('utf-8'))
首先我们看下request的API:
class 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()方法添加。from urllib import request, parse
url = 'http://httpbin.org/post'
headers = {
'User-Agent': 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)',
'Host': 'httpbin.org'
}
dict = {
'name': 'Germey'
}
data = bytes(parse.urlencode(dict), encoding='utf-8')
req = request.Request(url=url, data=data, headers=headers, method='POST')
response = request.urlopen(req)
print(response.read().decode('utf-8'))
这里用4个参数构造了一个请求,其中url请求URL,headers中指定了User-Agent和Host,参数data用urlencode()和bytes()方法转成字节流,还指定了请求方式为POST
运行结果:
3. 高级用法 Handler工具
(1) Handler工具
首先,urllib.request模块里的BaseHandler类是所有其他Handler的父类。
接下来,有各种Handler子类继承这个BaseHandler类
还有其他的类,详情可参考官方文档:https://docs.python.org/3/library/urllib.request.html#urllib.request.BaseHandler
(2) OpenerDirector类
简称为Opener。Opener可以使用open()方法,返回类型和urlopen()一致。我们可以使用Handler构建Opener。
验证:使用HTTPBasicAuthHandler就可以完成。
from urllib.request import HTTPPasswordMgrWithDefaultRealm, HTTPBasicAuthHandler, build_opener
from urllib.error import URLError
username = 'username'
password = 'passowrd'
url = 'http://localhost:5000/'
p = HTTPPasswordMgrWithDefaultRealm()
p.add_password(None, url, username, password)
auth_handler = HTTPBasicAuthHandler(p)
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)
首先实例化HTTPBasicAuthHandler对象,参数是HTTPPasswordMgrWithDefaultRealm对象,它利用add_password()添加用户名和密码,这样既建立了一个处理验证的Handler。
接下来,利用这个Handler并使用build_opener()方法构建一个Opener。
然后利用Opener的open()方法打开链接。
代理
from urllib.error import URLError
from urllib.request import ProxyHandler, build_opener
proxy_handler = ProxyHandler({
'http':'http://127.0.0.1:6564',
'https':'https://127.0.0.1:6594'
})
opener = build_opener(proxy_handler)
try:
response = opener.open('https://www.baidu.com')
print(response.read().decode('utf-8'))
except URLError as e:
print(e.reason)
这里在本地搭建了一个代理。运行在6564端口上。这里使用ProxyHandler,参数是一个字典,键名是协议类型,键值是代理链接,可添加多个代理。然后,利用这个Handler以及build_opener()方法构造一个Opener,之后发送请求
Cookies
(1)获取网站Cookie
import http.cookiejar, urllib.request
cookie = http.cookiejar.CookieJar()
handler = urllib.request.HTTPCookieProcessor(cookie)
opener = urllib.request.build_opener(handler)
response = opener.open('http://www.baidu.com')
for item in cookie:
print(item.name + "=" + item.value)
运行结果
(2)保存网站Cookies
import http.cookiejar, urllib.request
filename = 'cookies.txt'
cookie = http.cookiejar.MozillaCookieJar(filename=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)
MozillaCookieJar是CookieJar的子类,可以用来处理Cookies和文件相关事件。
运行之后,生成一个cookies.txt文件,内容如下:
LWPCookieJar同样可以读取和保存Cookies,但是格式不同。
cookie = http.cookiejar.LWPCookieJar(filename)
运行结果:
(3)读取Cookies
import http.cookiejar, urllib.request
cookie = http.cookiejar.LWPCookieJar()
cookie.load('cookies.txt', ignore_discard=True, ignore_expires=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'))
这里使用load()方法读取本地Cookies文件,获取到内容后构建Handler和Opener得到百度网页的源代码。
error
异常处理模块,若出现请求错误,可以捕获这些异常,然后进行重试或者其他操作,从而防止程序意外终止。
parse
工具模块,提供处理URL的方法。
robotparser
识别网站的robots.txt文件,判断网站是否允许爬取。
urllib的errow模块定义了由request模块产生的异常。如果出现异常,request模块会抛出error模块中定义的异常
(1)URLError
URLError类来自urllib库的error模块,继承自OSError类。是error异常模块的基类。
它有一个属性reason,返回错误的原因
from urllib import request, error
try:
response = request.urlopen('https://cuiqingcai.com/index.htm')
except error.URLError as e:
print(e.reason)
运行结果:Not Found
(2)HTTPError
是URLError的子类,处理HTTP请求错误。它有以下三个属性:
from urllib import request, error
try:
response = request.urlopen('https://cuiqingcai.com/index.htm')
except error.HTTPError as e:
print(e.reason)
print(e.code)
print(e.headers)
运行结果:
异常处理写法:
from urllib import request, error
try:
response = request.urlopen('https://cuiqingcai.com/index.htm')
except error.HTTPError as e:
print(e.reason)
print(e.code)
print(e.headers)
except error.URLError as e:
print(e.reason)
else:
print('Resquest Successfully')
解析链接
1. urlparse()
这个方法可以实现URL的识别和分段
from urllib.parse import urlparse
result = urlparse('http://www.baidu.com/index.html;user?id=5#comment')
print(type(result), result)
运行结果如下:
ParseResult(scheme='http', netloc='www.baidu.com', path='/index.html', params='user', query='id=5', fragment='comment')
这里利用urlparse()方法进行了一个URL解析。输出了解析结果类型,之后输出结果。
返回的结果是一个ParseResult类型的对象,包含6个部分,scheme、netloc、path、params、query和fragment。
则一个标准的链接格式为:
scheme://netloc/path;params?query#fragment
urlparse()函数API:
urllib.parse.urlparse(urlstring, scheme='', allow_fragments=True)
urlstring:必选,待解析的URL
scheme:默认的协议。
allow_fragments:是否忽略fragment。
(2)urlunparse()
接受的参数是可迭代对象,长度必须为6。
from urllib.parse import urlunparse
data = ['http', 'www.baidu.com', 'index.html', 'user', 'a=6', 'comment']
print(urlunparse(data))
运行结果:
(3)urlsplit()
和urlparse()相似,但是不单独解析params这个部分,只返回5个结果
(4)urlunsplit()
和urlunparse()相似,但是长度必须为5
(5)urljoin()
两个参数,base_url和新的链接。方法会分析base_url的scheme、netloc和path,这3个内容并对新链接缺失的部分进行补充。
(6)urlencode()
构造GET请求
from urllib.parse import urlencode
params = {
'name':'germey',
'age':22
}
base_url = 'http://baidu.com?'
url = base_url + urlencode(params)
print(url)
运行结果:
(7)parse_qs()
利用parse_qs()方法,可以将GET请求参数转化为字典。
from urllib.parse import parse_qs
query = 'name=germey&age=22'
print(parse_qs(query))
运行结果:
(8)parse_qsl()
它用于将参数转化为元祖组成的列表。
from urllib.parse import parse_qsl
query = 'name=germey&age=22'
print(parse_qsl(query))
运行结果;
(9)quote()
此方法可以将内容转化为URL编码的格式。例如,可以将中文字符转化为URL编码。
from urllib.parse import quote
keyword = '中文'
url = 'https://www.baidu.com/s?wd=' + quote(keyword)
print(url)
运行结果:
(10)unquote()
他可以进行URL解码。
from urllib.parse import unquote
url = 'https://www.baidu.com/s?wd=%E4%B8%AD%E6%96%87'
print(unquote(url))
运行结果:
1. Robots协议
Robots协议也称作爬虫协议,用来告诉爬虫和搜索引擎哪些页面可以抓取,通常是一个robots.txt的文本文件。当访问一个站点时,首先会检查站点根目录下是否存在robots.txt文件,如果存在,则爬虫会根据其中定义的爬取范围来爬取,如果没有找到文件,则会访问所有可能直接访问的页面。
robots.txt文件:
User-agent: *
Disallow: /
Allow: /public/
则搜索爬虫只允许爬取public目录。
User-agent描述了搜索爬虫的名称,这里为*则代表该协议对任何爬取爬虫都有效。但是至少要指定一条规则。 Disallow指定了不允许爬取的目录 Allow一般和Disallow一起使用,用来排除某些限制。2. 爬虫名称
爬虫名称 | 名称 | 网站 |
---|---|---|
BaiduSpider | 百度 | www.baidu.com |
Googlebot | 谷歌 | www.google.com |
360Spider | 360搜索 | www.so.com |
YodaoBot | 有道 | www.youdao.com |
ia_archiver | Alexa | www.alexa.com |
Scooter | altavista | www.altavista.com |
3. robotparser
robotparser模块提供了一个类RoobotFileParser,它可以根据某网站的robots.txt文件来判断一个爬取爬虫是否有权限来爬取这个网页。
只需要在构造方法里传入robots.txt的链接即可使用。它的声明如下;
urllib.robotparser.RobotFileParser(url='')
也可以不传入,之后使用set_url()方法设置即可
以下是这个类常用的方法:
1. requests库安装
requests库是第三方库,需要安装。
Win:pip install requests
Linunx:sudo pip3 install requests
2. requests实例
import requests
r = requests.get('https://www.baidu.com/')
print(type(r))
print(r.status_code)
print(type(r.text))
print(r.text)
print(r.cookies)
运行结果:
这里的get()方法实现与urlopen()一致,得到一个Response对象,然后分别输出Response类型,状态码,响应体的类型,内容以及Cookies。
3. GET请求
实例:import requests
r = requests.get('http://httpbin.org/get')
print(r.text)
运行结果:
这个网站会判断客户端发起的是否是GET请求,如果是,则返回相应的请求信息。
返回结果中包含请求头、URL、IP等信息。
GET请求中往往会添加额外的信息。这里我们使用字典来存储:
import requests
data = {
'name':'germey',
'age':22
}
r = requests.get('http://httpbin.org/get', params=data)
print(r.text)
运行结果;
通过返回内容可以判断,请求链接自动构造成了:
http://httpbin.org/get?age=22&name=germey
网页返回的类型是str类型,是JSON格式,如果想要解析返回结果,得到一个自己单格式的话,可以直接调用json()方法:
import requests
r = requests.get('http://httpbin.org/get')
print(type(r.text))
print(r.json())
print(type(r.json))
运行结果:
import requests
import re
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36'
}
r = requests.get('https://www.zhihu.com/explore', headers=headers)
print(r.text)
运行结果:
import requests
r = requests.get("https://github.com/favicon.ico")
print(r.text)
print(r.content)
运行结果:
r.text发生了乱码,r.content结果前有个b,表示bytes类型的数据。
我们将刚才提取到的内容保存下来:
import requests
r = requests.get("https://github.com/favicon.ico")
with open('favicon.ico','wb') as f:
f.write(r.content)
运行结果:
这里使用了open()方法,第一个参数是文件名称,第二个参数代表以二进制写的形式打开,可以向文件中写入二进制数据。
同样,音频也可以这样获取。
4. POST请求
import requests
data = {'name':'germey', 'age':'22'}
r = requests.post('http://httpbin.org/post', data=data)
print(r.text)
运行结果:
1. 文件上传
import requests
files = {'file':open('favicon.ico', 'rb')}
r = requests.post('http://httpbin.org/post', files=files)
print(r.text)
运行结果:
2. Cookies
import requests
r = requests.get('https://www.baidu.com')
print(r.cookies)
for key, value in r.cookies.items():
print(key + '=' + value)
运行结果:
先调用cookies属性即可得到Cookies,它是RequestCookieJar类型。然后使用items()方法将其转化为元祖组成的列表,遍历输出每一个Cookies的名称和值。
3. 会话维持
requests中每次请求都是相当于打开新的浏览器,如果是要获取登录后的个人信息,则需要先获取登录后的Cookies,然后通过Cookies进入获取信息。解决这个问题的方法是通过维持同一个会话,即只打开一个浏览器选项卡:Session对象。
import requests
requests.get('http://httpbin.org/cookies/set/number/123456789')
r = requests.get('http://httpbin.org/cookies')
print(r.text)
运行结果:
我们请求这个网址时,设置了一个cookies,名称叫做number,内容为123456789,随后又请求了网址,获取当前的Cookies。但是,并没有获取到。
使用Session:
import requests
s = requests.Session()
s.get('http://httpbin.org/cookies/set/number/123456789')
r = s.get('http://httpbin.org/cookies')
print(r.text)
运行结果:
成功获取!
4. 代理设置
当爬取某个网站的时候,如果大规模爬取,会弹出验证码或者跳转到登录验证界面,甚至会封禁客户端IP,为了避免这个情况,我们可以使用代理来解决这个问题,这里使用proxies参数:
import requests
proxies = {
'http':'http://10.10.1.10:3128',
'https':'https://10.10.1.10:1080',
}
request.get('https://www.baidu.com', proxies=proxies)
5. 超时设置
在网络不好或者服务器网络响应缓慢甚至无响应时,我们可能会等很久时间才能得到响应,甚至是无响应。为了防止出现这种情况,我们可以设置timeout参数:
import requests
r = requests.get('https://www.taobao.com', timeout = 1)
print(r.status_code)
这里设置超时时间为1秒,如果超出1秒未响应,则会抛出异常。
6. 身份认证
在访问网站时,我们可能会遇见认证界面,那么可以使用requests自带的身份认证功能:
import requests
from requests.auth import HTTPBasicAuth
r = requests.get('http://localhost:5000', auth=HTTPBasicAuth('username', 'passowrd'))
print(r.status_code)
如果用户名和密码正确,则会返回200状态码。如果失败,返回401状态码。
也可以使用下面的方法:
import requests
r = requests.get('http://localhost:5000', auth=('username', 'passowrd'))
print(r.status_code)
更详细的功能可以参考requests_oauthlib的官方文档:https://requests-oauthlib.readthedocs.org/
下一篇博客讲解非HTML网页如何爬取 Thanks♪(・ω・)ノ