urllib简单介绍:
urllib属于Python内置库,分四个模块:request,error,parse,robotparser。
Python官方文档:https://docs.python.org/zh-cn/3/library/urllib.html
urllib.request 请求模块
urlopen()函数
urlopen(url,data=None,[timeout,]*,cafile=None,capath=None,cadefault=False,context=None)
import urllib.request
re=urllib.request.urlopen('https://www.python.org') #请求方式:GET
print(re.read().decode('utf-8')) #输出是Python官网的HTML文档,内容过长,可以自己运行查看结果
#read()方法可以得到网页内容
import urllib.request
re=urllib.request.urlopen('https://www.python.org')
print(type(re)) #结果:<class 'http.client.HTTPResponse'>
由第二段代码可知,urlopen()返回的是HTTPResponse类型的对象。查看文档知,主要包含:read(), readinto(), getheader(name), getheaders(), fileno()等方法,msg, version,status,reason,debuglevel, closed等属性。# 如果觉得插入的图片太模糊,大家可以用print(dir(re))
查看所有方法和属性。
例子:
import urllib.request
re=urllib.request.urlopen('https://www.python.org')
print(re.status) #得到响应状态码 200表示成功
print(re.getheader('Server'))
print(re.getheaders())
#输出
200
nginx
[('Server', 'nginx'), ('Content-Type', 'text/html; charset=utf-8'), ('X-Frame-Options', 'DENY'), ('Via', '1.1 vegur'), ('Via', '1.1 varnish'), ('Content-Length', '48272'), ('Accept-Ranges', 'bytes'), ('Date', 'Tue, 16 Jul 2019 06:26:17 GMT'), ('Via', '1.1 varnish'), ('Age', '2510'), ('Connection', 'close'), ('X-Served-By', 'cache-iad2148-IAD, cache-hnd18742-HND'), ('X-Cache', 'HIT, HIT'), ('X-Cache-Hits', '1, 3353'), ('X-Timer', 'S1563258378.690692,VS0,VE0'), ('Vary', 'Cookie'), ('Strict-Transport-Security', 'max-age=63072000; includeSubDomains')]
我们还可以传递一些参数:(具体在开头写了)
data参数
如果想要添加data参数,需要用bytes()方法把内容转为字节流编码格式。另:如果传递了这个参数,请求方式将变为POST。bytes第一个参数要求是str()类型,第二个指定编码格式
import urllib.request
import urllib.parse #需要用urlencode()将字典转为字符串,所以导入这个模块,具体后面会讲
da=bytes(urllib.parse.urlencode({'world':'hello'}),encoding='utf-8')
re=urllib.request.urlopen('http://httpbin.org/post',data=da)
#这个网站可以用于测试POST请求,网站名就是这个,后面的POST不是定义方法
print(re.read().decode('utf-8')) #结果太长,自己运行。
timeout参数
这个参数用来设置请求的时间,如果请求时间超出设定值,就会报错。不设置,则用全局默认时间。有了这个参数,可以在一个页面长时间无响应的情况下跳过它,以此提高效率。
import urllib.request
import socket
import urllib.error
try:
re=urllib.request.urlopen('http://httpbin.org/post',timeout=0.1) #0.1秒一般无法得到响应
except urllib.error.URLError as e:
if isinstance(e.reason,socket.timeout):
print('TIME OUT')
# 结果: TIME OUT
其他参数
context
它必须是ssl.SSLContext类型,用于指定SSL设置
cafile 和 capath
分别指定CA证书和它的路径,在请求HTTPS链接时会有用。
cadefault 已经弃用,默认值:False
Request
用urlopen()可以发送最基本的请求,但过于简单,有些功能不够完善,这时就需要Request类来构建
class urllib.request.Request(url, data=None, headers={}, origin_req_host=None, unverfiable=False, method=None)
- 第一个参数url为必传参数,用于请求URL。
- 如果想要添加data参数,需要用bytes()方法把内容转为字节流编码格式。
- headers是一个字典,它就是请求头,可以在构造请求时通过该参数直接构造,也可以通过add_header()方法添加
- origin_req_host:指的是请求方的host名称或IP地址
- unverfiable表示这个请求是否是无法验证,默认为False。
- method是一个字符串,用于确定请求的方法GET,POST,PUT等
例子:
from urllib import request,parse
url='https://httpbin.org/post'
headers={
'User-Agent':'Mozilla/5.0(x11; U; Linux i686) Gecko/20071127 Firefox/2.0.0.11'
}
dict={
'name':'Germey'
}
data=bytes(parse.urlencode(dict),encoding='utf-8')
req=request.Request(url=url,data=data,headers=headers,method='POST')
req.add_header('Host','httpbin.org')
response=request.urlopen(req)
print(response.read().decode('utf-8'))
/*结果
{
"args": {},
"data": "",
"files": {},
"form": {
"name": "Germey"
},
"headers": {
"Accept-Encoding": "identity",
"Content-Length": "11",
"Content-Type": "application/x-www-form-urlencoded",
"Host": "httpbin.org",
"User-Agent": "Mozilla/5.0(x11; U; Linux i686) Gecko/20071127 Firefox/2.0.0.11"
},
"json": null,
"origin": "117.32.216.103, 117.32.216.103",
"url": "https://httpbin.org/post"
}*/
Handler
BaseHandler类
它是所有Handler的父类,它提供了最基本的方法,如default_open(), protocol_request()等
- HTTPDefaultErrorHandler: 用于处理HTTP响应错误
- HTTPRedirectHandler:用于处理重定向
- HTTPCookieProcessor:用于处理Cookies
- ProxyHandler:用于设置代理,默认为空
- HTTPPasswordMgr:用于管理密码,它维护了用户名和密码的表
- HTTPBasicAuthHandler:用于解决认证问题
还有其他没列出来的类,可以查看官方文档,在最上面。
例子:
from urllib.request import HTTPPasswordMgrWithDefaultRealm,HTTPBasicAuthHandler,build_opener
from urllib.error import URLError #后面会讲
username='username'
password='password'
url='https://www.baidu.com'
#创建一个密码管理对象,保存HTTP请求的相关用户名和密码
p=HTTPPasswordMgrWithDefaultRealm()
#添加账户信息,第一个参数realm是与远程服务器相关的域信息,一般没人管它都是写None,后面三个参数分别是 Web服务器、用户名、密码
p.add_password(None,url,username,password)
#验证Web用户端的用户名和密码
auth_handler=HTTPBasicAuthHandler(p)
# 通过 build_opener()方法使用这些代理Handler对象,创建自定义opener对象,参数包括构建的 proxy_handler
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)
- Cookie 代理
urllib.error异常处理模块
URLError类
继承自OSError类,是error模块的基类,有一个属性
from urllib import request,error
try:
re=request.urlopen('http://cuiqingcai.com/index.htm')
except error.URLError as e:
print(e.reason) #返回原因
#结果
Not Found
HTTPError
URLError的子类,专门用来处理HTTP请求错误,有三个属性
from urllib import request,error
try:
re=request.urlopen('http://cuiqingcai.com/index.htm')
except error.HTTPError as e:
print(e.reason,e.code,e.headers,sep='\n') #返回原因,HTTP状态码,返回请求头
#结果
Not Found
404
Server: nginx/1.10.3 (Ubuntu)
Date: Tue, 16 Jul 2019 09:16:10 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: close
Set-Cookie: PHPSESSID=s3vh0l6oq998aamggquls21gh3; path=/
Pragma: no-cache
Vary: Cookie
Expires: Wed, 11 Jan 1984 05:00:00 GMT
Cache-Control: no-cache, must-revalidate, max-age=0
Link: <https://cuiqingcai.com/wp-json/>; rel="https://api.w.org/"
parse处理URL模块
urlparse()
urlparse(urlstring, scheme=’’, allow_fragments=True)
URL的识别和分段;标准连接的格式:scheme://netloc/path;params?query#fragment
from urllib.parse import urlparse
#如果不带协议信息,则scheme将会成为默认协议
result=urlparse('www.baidu.com/index.html;user?id=5#comment',scheme='https')
print(result)
#结果:ParseResult(scheme='https', netloc='', path='www.baidu.com/index.html', params='user', query='id=5', fragment='comment')
#如果同时带上scheme和参数,且二者不同
result=urlparse('http://www.baidu.com/index.html;user?id=5#comment',scheme='https')
print(result)
结果:ParseResult(scheme='http', netloc='www.baidu.com', path='/index.html', params='user', query='id=5', fragment='comment')
#如果设置allow_fragments=False,fragment会为空,它的值会成为path,parameters或者query的一部分
result=urlparse('http://www.baidu.com/index.html;user?id=5#comment',allow_fragments=False)
print(result)
#结果:ParseResult(scheme='http', netloc='www.baidu.com', path='/index.html', params='user', query='id=5#comment', fragment='')
#ParseResult的结果实则是元祖,我们可用索引顺序或属性名获取
result=urlparse('http://www.baidu.com/index.html#comment',allow_fragments=False)
print(result.scheme,result[0],result.netloc,result[1],sep='\n')
#结果:
http
http
www.baidu.com
www.baidu.com
urlunparse
和urlparse相对,接受的参数是一个可迭代对象,长度必须是6,否则报错
from urllib.parse import urlunparse
data=['http','www.baidu.com','index.htnl','user','a=6','comment']
#data也可为元祖或其他特定数据结构
print(urlunparse(data))
# http://www.baidu.com/index.htnl;user?a=6#comment
urlsplit()
与urlparse()方法类似,但它不再单独解析params这一部分,只返回5个结果,params和path合并
返回的SplitResult同样为元祖类型,同样可用索引,属性获取值
urlunsplit()
与urlunparse()类似,但传入参数长度必须是5
urljoin()
我们提供一个base_url作为第一个参数,把新链接做第二个参数,该方法会把base_url的scheme, netloc, path这三个在新链接缺失的部分进行补充,params, query, fragment 不起作用。
urlencode()
例子:
from urllib.parse import urlencode
params={
'name':'germy',
'age':'22'
}
base_url='http://www.baidu.com?'
url=base_url+urlencode(params) #把字典转为URL参数
print(url) #http://www.baidu.com?name=germy&age=22
parse_qs()
把GET请求参数转为字典
parse_ql()
把参数转为元祖组成的列表,每个元祖第一个值为参数名,第二个为值。
quote()
把内容转为URL编码格式
unquote()
把URL进行解码
Robots协议
set_url()
设置robots.txt文件链接,在创建RobotFileParser对象时如果有链接就不需要
read()
读取robots.txt文件,必须有,它不会返回任何值。
parse()
解析robots.txt文件,传入的参数是robots.txt某些行内容。
can_fetch()
传入两个参数User-agent, URL返回搜索引擎是否可以抓取这个URL,True和False
mtime()
返回上次抓取和分析robots.txt文件的时间
modified()
将当前时间设置为上次抓取和分析robots.txt文件的时间
例子:
>>> import urllib.robotparser
>>> rp = urllib.robotparser.RobotFileParser()
>>> rp.set_url("http://www.musi-cal.com/robots.txt")
>>> rp.read()
>>> rrate = rp.request_rate("*")
>>> rrate.requests
3
>>> rrate.seconds
20
>>> rp.crawl_delay("*")
6
>>> rp.can_fetch("*", "http://www.musi-cal.com/cgi-bin/search?city=San+Francisco")
False
>>> rp.can_fetch("*", "http://www.musi-cal.com/")
True