Home > Article > Backend Development > How to use Python's HTTP client modules urllib and urllib3
urllib
is the official standard library for requesting url connections in Python. Even if you install python, this library can be used directly Used, it basically covers the basic network request functions. In Python2, they are mainly urllib and urllib2, and in Python3, they are integrated into urllib.
urllib2
was merged into urllib
in Python3.x, and then the package was divided into the following four modules:
urllib.request: It is the most basic http request module, used to simulate sending requests
urllib.error: Exception handling module, if errors occur, these exceptions can be caught
urllib.parse: A tool module that provides many URL processing methods, such as: splitting, parsing, merging, etc.
urllib.robotparser: Mainly used Identify the robots.txt file of the website, and then determine which websites can be crawled
It supports URL processing of the following protocols: file, ftp, gopher,hdl,http,https,imap,mailto,mms,news,nntp,prospero,rsync,rtsp,rtspu,sftp,sip,sips,snews,svn,snv ssh,telnet,wais
Syntax: urllib.parse.urlparse(urlstring,scheme='',allow_fragments=True)
You can pass 3 parameters
urlstring: URL to be parsed, string
scheme: It is the default protocol, such as http or https, if the URL does not have the http protocol, it can be specified through scheme. If the http protocol is specified in the URL, it will take effect in the URL
allow_fragments: Whether to ignore the fragment, that is, the anchor point, if Set to False, the fragment part will be ignored, otherwise it will not be ignored
This method can realize the identification and segmentation of URL, respectively scheme (protocol), netloc (domain name) , path (path), params (parameters), query (query conditions), fragment (anchor)
import urllib.parse url = "http://www.baidu.com" parsed = urllib.parse.urlparse(url) print(parsed) # 输出:ParseResult(scheme='http', netloc='www.baidu.com', path='', params='', query='', fragment='') #返回的是一个parseresult类型的元组对象,可以通过属性或者索引来获取值
Contrary to urlparse(), urlunparse accepts an iterable in the form of a list or tuple Object, implements URL construction
from urllib.parse import urlunparse data=['http','www.baidu.com','index.html','user','a=6','comment'] print(urlunparse(data)) #构造一个完整的URL #output #http://www.baidu.com/index.html;user?a=6#comment
Similar to the urlparse() method, it will return 5 parts, just merging the params into path.
from urllib.parse import urlsplit result = urlsplit('http://www.baidu.com/index.html;user?id=5#comment') print(result) print(result.query) # output # SplitResult(scheme='http', netloc='www.baidu.com', path='/index.html;user', query='id=5', fragment='comment') # id=5
Similar to urlunparse(), it is also a method of combining various parts of the link into a complete link. The parameters passed in are also iterable objects, such as list ancestors, etc. The only difference is that the length must be 5 , it omits params
from urllib.parse import urlsplit,urlunsplit data=['http','www.baidu.com','index.html','a=5','comment'] result=urlunsplit(data) print(result) #output #http://www.baidu.com/index.html?a=5#comment
urlencode() connects the key-value pairs in the dict with the connector & divide.
urlencode() is useful when constructing GET request parameters. It can convert dictionary type request data into URL encoding
import urllib.parse dic = {'name':'melon','age':18} data = urllib.parse.urlencode(dic) print(data) #age=18&name=melon
parse_qs() is just the opposite of urlencode(). It is used Deserialization, such as converting GET parameters back to dictionary format
from urllib.parse import urlencode,parse_qs,urlsplit params = {'username':'zs','password':'123'} base_url='http://www.baidu.com' url=base_url+'?'+urlencode(params) #将字典转化为get参数 query=urlsplit(url).query #获去URL的query参数条件 print(parse_qs(query)) #根据获取的GET参数转换为字典格式 #output #{'username': ['zs'], 'password': ['123']}
quote: URL encoding processing, this method can Content is converted to URL-encoded format.
If the parameters contain Chinese and other non-ASCII codes, sometimes it will cause garbled characters. In this case, use this method to convert Chinese characters into URL encoding
from urllib.parse import quote key='中文' url='https://www.baidu.com/s?key='+quote(key) print(url) #output #https://www.baidu.com/s?key=%E4%B8%AD%E6%96%87
unquote(url): URL Decoding processing, contrary to quote(), the special characters on the URL are restored
from urllib.parse import quote, urlsplit, unquote key = '中文' url = 'https://www.baidu.com/s?key=' + quote(key) print(url) unq = urlsplit(url).query.split('=')[1] # 获取参数值 print(unquote(unq)) # 解码参数
format: urljoin(baseurl,newurl,allowFrag=None)
Constructs a complete URL by combining the base URL (base) with another URL (url). It will use the basic URL components, protocol (schemm), domain name ( netloc), path, to provide the missing parts in the URL, and finally return the result.
base_url provides three items: scheme, netloc, and path. If these three items do not exist in the new link, they will be supplemented. If the new link exists, the new link part will be used. The params in base_url ,query and fragment have no effect.
Link parsing, splicing and generation can be achieved through the urljoin() method.
import urllib.parse url = "http://www.baidu.com" new_path = urllib.parse.urljoin(url, "index.html") print(new_path) # 输出:<a href="http://www.baidu.com/index.html" rel="external nofollow" target="_blank">http://www.baidu.com/index.html</a>
urlretrieve(url,filename,reporthook,data)
If the path filename is not written, it will be saved as a temporary file. You can use urllib.urlcleanup() to clean the cache
file_name = urllib.request.urlretrieve('http://www.baidu.com','%s/baidu.html'%BASE_DIR)
The most commonly used function in the module is urlopen():
urllib.request.urlopen(url, data=None, [timeout, ]*, cafile=None, capath=None, cadefault=False, context=None)
The parameters are as follows:
url: Requested URL, str type, or a request object
data: Data to be sent to the server, the data parameter is optional, and the content is in byte stream encoding format is of bytes type. If the data parameter is passed, urlopen will use the Post method to request.
timeout: Set the website access timeout in seconds. If the request exceeds the set time and has not received a response, an exception will be thrown. HTTP, HTTPS, and FTP requests are supported.
Other parameters: context parameter, she must be of ssl.SSLContext type, used to specify SSL settings. In addition, the two parameters cafile and capath specify the CA certificate and its path respectively. Will be used for https links.
urlopen返回http.client.HTTPResponse对象,提供方法:
read():获取响应返回的数据,只能使用一次。
readline():返回得是二进制格式得页面中得第一行
readlines() :以二进制格式 返回所有得数据 以列表格式保存
fileno():
close() :
info():返回一个httplib.HTTPMessage 对象,表示远程服务器返回的头信息。
getcode():返回Http状态码,如果是http请求,200表示请求成功完成;404表示网址未找到。
getheaders():获取返回响应的响应报头。
geturl():返回请求的url。
在urlopen()方法中,直接写入要访问的url地址字符串,该方法就会主动的访问目标网址,然后返回访问结果。
返回的访问结果是一个http.client.HTTPResponse对象,使用该对象的read()方法即可获取访问网页获取的数据,这个数据是二进制格式的,所以我们还需要使用decode()方法来将获取的二进制数据进行解码,转换成我们可以看的懂得字符串。
import urllib.request req = urllib.request.urlopen('http://www.baidu.com') print(req.read().decode()) print(req.getheaders()) # 以列表元祖对的形式返回响应头信息 print(req.getheader('Content-Type')) # 返回响应头中的Content-Type值 print(req.info()) # 返回网页的头信息 print(req.info()['Content-Type']) # 返回响应头中的Content-Type值
不需要使用read()方法 。
for line in urlopen('https://。。.html'): line = line.decode('utf-8') # Decoding the binary data to text. if 'EST' in line or 'EDT' in line: # look for Eastern Time print(line)
GET请求和我们平常get访问方式一样,直接把参数写到网址上面就好了。
import urllib.request import urllib.parse dic = {'name':'melon','age':18} data = urllib.parse.urlencode(dic) req = urllib.request.urlopen('http://127.0.0.1:8000/index?%s'%data) #通过urlopen方法访问拼接好的url content = req.read()
在urlopen()
方法中,urlopen()
默认的访问方式是GET,当在urlopen()
方法中传入data参数时,则会发起POST请求。
注意:传递的data数据需要为bytes格式,如data=b'word=hello'。
import urllib.request import urllib.parse import json dic = {'name':'melon','age':18} data = urllib.parse.urlencode(dic) req = urllib.request.Request('http://127.0.0.1:8000/index', data.encode()) #encode:将url编码类型的请求数据转变为bytes类型 opener = urllib.request.urlopen(req) content = json.loads(opener.read().decode()) #read()方法是读取返回bytes数据内容,decode转换后为str
当我们需要模拟一些其他的参数的时候,简单的urlopen()
方法已经无法满足我们的需求了,这个时候我们就需要使用下面的urllib.request
中的Request
对象来帮助我们实现一些其它参数的模拟,比如请求头。
Request
对象如下所示:
# Request对象实例化 req = urllib.request.Request(url, data=None, headers={},origin_req_host=None,unverifiable=False, method=None)
url:请求的URL,必须传递的参数,其他都是可选参数
data:上传的数据,必须传bytes字节流类型的数据,如果它是字典,可以先用urllib.parse模块里的urlencode()编码
headers:它是一个字典,传递的是请求头数据,可以通过它构造请求头,也可以通过调用请求实例的方法add_header()来添加
例如:修改User_Agent头的值来伪装浏览器,比如火狐浏览器可以这样设置:
{'User-Agent':'Mozilla/5.0 (compatible; MSIE 5.5; Windows NT)'}
origin_req_host:指请求方的host名称或者IP地址
unverifiable:表示这个请求是否是无法验证的,默认为False,如我们请求一张图片如果没有权限获取图片那它的值就是true
method:是一个字符串,用来指示请求使用的方法,如:GET,POST,PUT等
from urllib import request url='http://httpbin.org/post' headers={ 'User-Agent':'Mozilla/5.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') #req.add_header('User-Agent','Mozilla/5.0 (compatible; MSIE 8.4; Windows NT') #也可以request的方法来添加 resp = request.urlopen(req) print(resp.read().decode())
BaseHandler类:
在urllib.request模块里的BaseHandler类,他是所有其他Handler的父类,他是一个处理器,比如用它来处理登录验证,处理cookies,代理设置,重定向等
BaseHandler的子类包括:
HTTPDefaultErrorHandler:用来处理http响应错误,错误会抛出HTTPError类的异常
HTTPRedirectHandler:用于处理重定向
HTTPCookieProcessor:用于处理cookies
ProxyHandler:用于设置代理,默认代理为空
HTTPPasswordMgr:永远管理密码,它维护用户名和密码表
HTTPBasicAuthHandler:用户管理认证,如果一个链接打开时需要认证,可以使用它来实现验证功能
build_opener(*handlers)方法用于构建一个自定义的OpenerDirector对象。
build.opener(handler1,handler2…)
之前的urlopen()方法就是urllib提供的一个Opener,通过Handler处理器来构建Opener实现Cookies处理,代理设置,密码设置等
Opener的方法包括:
add_handler(handler):添加处理程序到链接中
open(url,data=None[,timeout]):打开给定的URL与urlopen()方法相同
error(proto,*args):处理给定协议的错误
设置全局后既可以用urlopen()方法, 也可以用opener.open() ,不安装的话只能用opener.open()方法
# 将这个opener设置为全局的opener,之后所有的,不管是opener.open()还是urlopen() 发送请求,都将使用自定义 request.install_opener(opener) resp = request.urlopen(url)
HTTPPasswordMgrWithDefaultRealm()类创建一个密码管理对象,用来保存HTTP请求相关的用户名和密码,主要应用两个场景:
验证代理授权的用户名和密码(ProxyBasicAuthHandler())
验证web客户端的用户名和密码(HTTPBasicAuthHandler())
在下面的方法中我们还用到了一个新的东西,即request.build_opener()方法,其实urlopen()就是通过构造好了的opener对象发送请求,在这里我们使用request.build_opener()方法重构了一个opener()对象,我们可以通过这个对象实现urlopen()实现的任何东西。
from urllib.request import HTTPPasswordMgrWithDefaultRealm,HTTPBasicAuthHandler,build_opener from urllib.error import URLError username='username' passowrd='password' url='http://localhost' p=HTTPPasswordMgrWithDefaultRealm() #构造密码管理实例 p.add_password(None,url,username,passowrd) #添加用户名和密码到实例中 auth_handler=HTTPBasicAuthHandler(p) #传递密码管理实例构建一个验证实例 opener=build_opener(auth_handler) #构建一个Opener try: result=opener.open(url) #打开链接,完成验证,返回的结果是验证后的页面内容 html=result.read().decode('utf-8') print(html) except URLError as e: print(e.reason)
使用爬虫来爬取数据的时候,如果过于频繁的访问,而且网站还设有限制的话,很有可能会禁封我们的ip地址,这个时候就需要设置代理,来隐藏我们的真实IP。
urllib提供了urllib.request.ProxyHandler()方法可动态的设置代理IP池。将代理IP以字典形式传入该方法,然后通过urllib.reques.build_opener()创建opener对象,用该对象的open()方法向服务器发送请求。
from urllib import request url = 'http://httpbin.org/ip' proxy = {'http': '218.18.232.26:80', 'https': '218.18.232.26:80'} proxies = request.ProxyHandler(proxy) # 创建代理处理器 opener = request.build_opener(proxies) # 创建opener对象 resp = opener.open(url) print(resp.read().decode())
有时候当我们访问一些网站的时候需要进行翻页或者跳转等其它操作,为了防止无法访问我们想要的数据,需要让网站识别我们是同一个用户。这个时候我们就需要带上cookie进行访问。
在设置cookie的时候由于urllib并没有很好的处理cookie的对象,所以在这里我们需要用到一个别的库,即http库,并使用里面的cookiejar来进行cookie的管理:
CookieJar类关系:CookieJar —-派生—->FileCookieJar —-派生—–>MozillaCookieJar和LWPCookieJar
from http import cookiejar from urllib import request cookie = cookiejar.CookieJar() # 创建一个cookiejar对象 cookies = request.HTTPCookieProcessor(cookie) # 使用HTTPCookieProcessor创建cookie处理器 opener = request.build_opener(cookies) # 并以它为参数创建Opener对象 resp = opener.open('https://www.baidu.com') # 使用这个opener来发起请求 # 查看之前的cookie对象,则可以看到访问百度获得的cookie for i in cookie: print(i)
cookies保存到文件:
1、以Mozilla型浏览器的cookies格式:
cookie=http.cookiejar.MozillaCookieJar(filename=fielname)
import http.cookiejar,urllib.request fielname='cookies.txt' cookie=http.cookiejar.MozillaCookieJar(filename=fielname) #创建保存cookie的实例,保存浏览器类型的Mozilla的cookie格式 handler=urllib.request.HTTPCookieProcessor(cookie) #构建一个handler opener=urllib.request.build_opener(handler) #构建Opener response=opener.open('http://www.baidu.com') #请求 cookie.save(ignore_discard=True,ignore_expires=True)
从文件中读取cookies:
2、也可以保存为libwww-perl(LWP)格式的Cookies文件
cookie=http.cookiejar.LWPCookieJar(filename=fielname)
import http.cookiejar,urllib.request #fielname='cookiesLWP.txt' #cookie=http.cookiejar.LWPCookieJar(filename=fielname) #LWP格式的cookies cookie=http.cookiejar.LWPCookieJar() cookie.load('cookiesLWP.txt',ignore_discard=True,ignore_expires=True) handler=urllib.request.HTTPCookieProcessor(cookie) #构建一个handler opener=urllib.request.build_opener(handler) #构建Opener response=opener.open('http://www.baidu.com') #请求 print(response.read().decode('utf-8'))
当然,如果把上面这个生成的opener对象使用install_opener方法来设置为全局的,opener对象之后的每次访问都会带上这个cookie。
通过添加忽略ssl证书验证关闭证书验证,由于urllib并没有很好的处理ssl的对象,所以在这里我们需要用到一个别的库,即ssl库,如下:
import ssl from urllib import request context = ssl._create_unverified_context() res = urllib.request.urlopen(request, context=context)
当你 urllib.urlopen一个 https 的时候会验证一次 SSL 证书,当目标使用的是自签名的证书时就会出现一个URLError,如果是这样可以在开头加上
import ssl ssl._create_default_https_context = ssl._create_unverified_context
urllib的error模块定义了由request模块产生的异常,如果出现问题,request模块便会抛出error模块中定义的异常。
在urllib中主要设置了两个异常,一个是URLError,一个是HTTPError,HTTPError是URLError的子类。
URLError类来自urllib库的error模块,它继承自OSError类,是error异常模块的基类,由request模块产生的异常都可以通过捕获这个类来处理
它只有一个属性reason,即返回错误的原因
from urllib import request,error try: response=request.urlopen('https://hehe,com/index') except error.URLError as e: print(e.reason) #如果网页不存在不会抛出异常,而是返回捕获的异常错误的原因(Not Found)
reason如超时则返回一个对象
import socket import urllib.request import urllib.error try: response=urllib.request.urlopen('https://www.baidu.com',timeout=0.001) except urllib.error.URLError as e: print(e.reason) if isinstance(e.reason,socket.timeout): print('time out')
它是URLError的子类,专门用来处理HTTP请求错误,比如认证请求失败,它有3个属性:
code:返回HTTP的状态码,如404页面不存在,500服务器错误等
reason:同父类,返回错误的原因
headers:返回请求头
举例:
from urllib import request,error try: response=request.urlopen('http://cuiqingcai.com/index.htm') except error.HTTPError as e: #先捕获子类异常 print(e.reason,e.code,e.headers,sep='\n') except error.URLError as e: #再捕获父类异常 print(e.reason) else: print('request successfully')
利用urllib的robotparser模块,我们可以实现网站Robots协议的分析
也称为爬虫协议、机器人协议,它的全名叫做网络爬虫排除标准(Robots Exclusion Protocol),用来告诉爬虫和搜索引擎哪些网页可以抓取,哪些不可以抓取,它通常是一个robots.txt的文本文件,一般放在网站的根目录下。
当搜索爬虫访问一个站点时,它首先会检查这个站点根目录下是否存在robots.txt文件,如果存在,搜索爬虫会根据其中定义的爬去范围来爬取,如果没有找到,搜索爬虫会访问所有可直接访问的页面
我们来看下robots.txt的样例:
User-agent: * Disallow: / Allow: /public/
它实现了对所有搜索爬虫只允许爬取public目录的功能,将上述内容保存为robots.txt文件放在网站根目录下,和网站的入口文件(index.html)放在一起
1、User-agent描述了搜索爬虫的名称,将其设置为*则代表协议对任何爬虫有效,如设置为Baiduspider则代表规则对百度爬虫有效,如果有多条则对多个爬虫受到限制,但至少需要指定一条
一些常见的搜索爬虫名称:
BaiduSpider 百度爬虫 www.baidu.com
Googlebot Google爬虫 www.google.com
360Spider 360爬虫 www.so.com
YodaoBot 有道爬虫 www.youdao.com
ia_archiver Alexa爬虫 www.alexa.cn
Scooter altavista爬虫 www.altavista.com
2、Disallow指定了不允许抓取的目录,如上例中设置的/则代表不允许抓取所有的页面
3、Allow一般和Disallow一起使用,用来排除单独的某些限制,如上例中设置为/public/则表示所有页面不允许抓取,但可以抓取public目录
设置示例:
#禁止所有爬虫 User-agent: * Disallow: / #允许所有爬虫访问任何目录,另外把文件留空也可以 User-agent: * Disallow: #禁止所有爬虫访问某那些目录 User-agent: * Disallow: /home/ Disallow: /tmp/ #只允许某一个爬虫访问 User-agent: BaiduSpider Disallow: User-agent: * Disallow: /
用来解析robots.txt,该模块提供了一个类RobotFileParser,它可以根据某网站的robots.txt文件来判断一个抓取爬虫时都有权限来抓取这个网页
urllib.robotparser.RobotFileParser(url='')
robotparser类常用的方法:
set_url():用来设置robots.txt文件的连接,如果在创建RobotFileParser对象是传入了连接,就不需要在使用这个方法设置了
read():读取reobts.txt文件并进行分析,它不会返回任何内容,但执行那个了读取和分析操作
parse():用来解析robots.txt文件,传入的参数是robots.txt某些行的内容,并安装语法规则来分析内容
can_fetch():该方法传入两个参数,第一个是User-agent,第二个是要抓取的URL,返回的内容是该搜索引擎是否可以抓取这个url,结果为True或False
mtime():返回上次抓取和分析robots.txt的时间
modified():将当前时间设置为上次抓取和分析robots.txt的时间
from urllib.robotparser import RobotFileParser rp = RobotFileParser() #创建对象 rp.set_url('https://www.cnblogs.com/robots.txt') #设置robots.txt连接,也可以在创建对象时指定 rp.read() #读取和解析文件 print(rp.can_fetch('*','https://i.cnblogs.com/EditPosts.aspx?postid=9170312&update=1')) #判断链接是否可以被抓取
urllib3增加了连接池等功能,两者互相都有补充的部分。许多Python的原生系统已经开始使用urllib3。
urllib3提供了很多python标准库urllib里所没有的重要特性:
线程安全
连接池
客户端SSL/TLS验证
文件分部编码上传
协助处理重复请求和HTTP重定位
支持gzip和deflate压缩编码
支持HTTP和SOCKS代理
100%测试覆盖率
urllib3是一个第三方库,pip安装:
pip install urllib3
通过urllib3访问一个网页,那么必须首先构造一个PoolManager对象,然后通过PoolMagent中的request方法或者 urlopen()方法来访问一个网页,两者几乎没有任何区别。
class urllib3.poolmanager.PoolManager(num_pools = 10,headers = None,** connection_pool_kw )
生成一个PoolManager所需要的参数:
num_pools 代表了缓存的池的个数,如果访问的个数大于num_pools,将按顺序丢弃最初始的缓存,将缓存的个数维持在池的大小。
headers 代表了请求头的信息,如果在初始化PoolManager的时候指定了headers,那么之后每次使用PoolManager来进行访问的时候,都将使用该headers来进行访问。
** connection_pool_kw 是基于connection_pool 来生成的其它设置
当访问网页完成之后,将会返回一个HTTPResponse对象。
使用request()或者urlopen(),获取GET请求的响应内容:
import urllib3 data = json.dumps({'abc': '123'}) http = urllib3.PoolManager(num_pools=5, headers={'User-Agent': 'ABCDE'}) resp1 = http.request('GET', 'http://www.baidu.com', body=data) resp2 = http.urlopen('GET', 'http://www.baidu.com', body=data) print(resp2.data.decode())
使用request()或者urlopen(),进行 POST 请求:
import urllib3 import json data = json.dumps({'abc': '123'}) http = urllib3.PoolManager(num_pools=5, headers={'User-Agent': 'ABCDE'}) resp1 = http.request('POST', 'http://www.httpbin.org/post', body=data,timeout=5,retries=5) #resp2 = http.urlopen('POST', 'http://www.httpbin.org/post', body=data,timeout=5,retries=5) print(resp1.data.decode())
注意事项:urllib3 并没有办法单独设置cookie,所以如果你想使用cookie的话,可以将cookie放入到headers中
urlopen()比request()有三个参数是不一样的,你会发现request()具有fields,headers两个参数。所以更多的也就使用 request() 方法了。
推荐使用request()来进行访问的,因为使用request()来进行访问有两点好处,
可以直接进行post请求,不需要将 data参数转换成JSON格式
直接进行GET请求,不需要自己拼接url参数
语法:
request(self, method, url, fields=None, headers=None, **urlopen_kw)
urlopen(self, method, url, redirect=True, **kw):
如果你需要使用代理来访问某个网站的话, 那么你可以使用 ProxyManager 对象来进行设置
def __init__(self, proxy_url, num_pools=10, headers=None,proxy_headers=None, **connection_pool_kw):
ProxyManager和PoolManager的方法基本完全相同。
import urllib3 import json data = {'abc': '123'} proxy = urllib3.ProxyManager('http://50.233.137.33:80', headers={'connection': 'keep-alive'}) resp1 = proxy.request('POST', 'http://www.httpbin.org/post', fields=data) print(resp1.data.decode())
The above is the detailed content of How to use Python's HTTP client modules urllib and urllib3. For more information, please follow other related articles on the PHP Chinese website!