做者:xiaoyu
微信公众号:Python数据科学
知乎:Python数据分析师html
前情回顾,urllib的基本用法web
具体内容参见Python从零学爬虫。urllib库除了以上基础的用法外,还有不少高级的功能,能够更加灵活的适用在爬虫应用中,好比:segmentfault
本次将会对这些内容进行详细的分析和讲解。windows
POST是HTTP协议的请求方法之一,也是比较经常使用到的一种方法,用于向服务器提交数据。博主先介绍进行post请求的一些准备工做,而后举一个例子,对其使用以及更深层概念进行详细的的剖析。浏览器
既然要提交信息给服务器,咱们就须要知道信息往哪填,填什么,填写格式是什么?带这些问题,咱们往下看。服务器
一样提交用户登陆信息(用户名和密码),不一样网站可能须要的东西不同,好比淘宝反爬机制较复杂,会有其它一大串的额外信息。这里,咱们以豆瓣为例(相对简单),目标是弄清楚POST是如何使用的,复杂内容会在后续实战部分与你们继续分享。微信
抛出上面像淘宝同样须要的复杂信息,若是仅考虑用户名和密码的话,咱们的准备工做其实就是要弄明白用户名和密码标签的属性name是什么,如下两种方法能够实现。app
废话很少说了,让咱们看看到底如何找到name?socket
经过浏览器F12元素逐层查看到(我是用的Chrome),邮箱/手机号标签的name="form_email", 密码的标签name="form_email",以下图红框所示。工具
但要说明的是,两个标签的name名称并非固定的,上面查看的name名称只是豆瓣网站定义的,不表明全部。其它的网站可能有会有不一样的名称,好比name="username", name="password"之类的。所以,针对不一样网站的登陆,须要每次查看name是什么。
博主推荐使用fiddler工具,很是好用。爬虫自己就是模拟浏览器工做,咱们只须要知道浏览器是怎么工做的就能够了。
fiddler会帮助咱们抓取浏览器POST请求的全部内容,这样咱们获得了浏览器POST的信息,把它填到爬虫程序里模拟浏览器操做就OK了。另外,也能够经过fiddler抓到浏览器请求的headers,很是方便。
安装fiddler的小伙伴们注意:fiddler证书问题的坑(没法抓取HTTPs包),能够经过Tools —> Options —>HTTPS里面打勾Decrypt HTTPS traffic修改证书来解决。不然会一直显示抓取 Tunnel 信息包...
好了,完成了准备工做,咱们直接上一段代码理解下。
# coding: utf-8 import urllib.request import urllib.error import urllib.parse # headers 信息,从fiddler上或你的浏览器上可复制下来 headers = {'Accept': 'text/html,application/xhtml+xml, application/xml;q=0.9,image/webp,image/apng, */*;q=0.8', 'Accept-Language': 'zh-CN,zh;q=0.9', 'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)Chrome/48.0 .2564.48 Safari/537.36' } # POST请求的信息,填写你的用户名和密码 value = {'source': 'index_nav', 'form_password': 'your password', 'form_email': 'your username' } try: data = urllib.parse.urlencode(value).encode('utf8') response = urllib.request.Request( 'https://www.douban.com/login', data=data, headers=headers) html = urllib.request.urlopen(response) result = html.read().decode('utf8') print(result) except urllib.error.URLError as e: if hasattr(e, 'reason'): print('错误缘由是' + str(e.reason)) except urllib.error.HTTPError as e: if hasattr(e, 'code'): print('错误编码是' + str(e.code)) else: print('请求成功经过。')
运行结果:
<!DOCTYPE HTML> <html lang="zh-cmn-Hans" class="ua-windows ua-webkit"> <head> <meta charset="UTF-8"> <meta name="description" content="提供图书、电影、音乐唱片的 推荐、评论和价格比较,以及城市独特的文化生活。"> ..... window.attachEvent('onload', _ga_init); } </script> </body> </html>
注意:复制header的时候请去掉 这一项'Accept-Encoding':' gzip, deflate, 不然会提示decode的错误。
咱们来分析一下上面的代码,与urllib库request的使用基本一致,urllib库request的基本用法可参考上篇文章Python从零学爬虫,这里多出了post的data参数和一些解析的内容,着重讲解一下。
data = urllib.parse.urlencode(value).encode('utf8')
这句的意思是利用了urllib库的parse来对post内容解析,为何要解析呢?
这是由于post内容须要进行必定的编码格式处理后才能发送,而编码的规则须要听从RFC标准,百度了一下RFC定义,供你们参考:
*
Request ForComments(RFC),是一系列以编号排定的文件。文件收集了有关互联网相关信息,以及UNIX和互联网社区的软件文件。目前RFC文件是由InternetSociety(ISOC)赞助发行。基本的互联网通讯协议都有在RFC文件内详细说明。RFC文件还额外加入许多的论题在标准内,例如对于互联网新开发的协议及发展中全部的记录。所以几乎全部的互联网标准都有收录在RFC文件之中。
*
而parse的urlencode方法是将一个字典或者有顺序的二元素元组转换成为URL的查询字符串(说白了就是按照RFC标准转换了一下格式)。而后再将转换好的字符串按UTF-8的编码转换成为二进制格式才能使用。
注:以上是在Python3.x环境下完成,Python3.x中编码解码规则为 byte—>string—>byte的模式,其中byte—>string为解码,string—>byte为编码
为何要使用代理IP?由于各类反爬机制会检测同一IP爬取网页的频率速度,若是速度过快,就会被认定为机器人封掉你的IP。可是速度过慢又会影响爬取的速度,所以,咱们将使用代理IP取代咱们本身的IP,这样不断更换新的IP地址就能够达到快速爬取网页而下降被检测为机器人的目的了。
一样利用urllib的request就能够完成代理IP的使用,可是与以前用到的urlopen不一样,咱们须要本身建立订制化的opener。什么意思呢?
urlopen就好像是opener的通用版本,当咱们须要特殊功能(例如代理IP)的时候,urlopen知足不了咱们的需求,咱们就不得不本身定义并建立特殊的opener了。
request里面正好有处理各类功能的处理器方法,以下:
ProxyHandler, UnknownHandler, HTTPHandler, HTTPDefaultErrorHandler, HTTPRedirectHandler, FTPHandler, FileHandler, HTTPErrorProcessor, DataHandler
咱们要用的是第一个ProxyHandler来处理代理问题。
让咱们看一段代码如何使用。
# coding:utf-8 import urllib.request import urllib.error import urllib.parse # headers信息,从fiddler上或浏览器上可复制下来 headers = {'Accept': 'text/html,application/xhtml+xml, application/xml;q=0.9,image/webp,image/apng, */*;q=0.8', 'Accept-Language': 'zh-CN,zh;q=0.9', 'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)Chrome/48.0.2564.48 Safari/537.36' } # POST请求的信息 value = {'source': 'index_nav', 'form_password': 'your password', 'form_email': 'your username' } # 代理IP信息为字典格式,key为'http',value为'代理ip:端口号' proxy = {'http': '115.193.101.21:61234'} try: data = urllib.parse.urlencode(value).encode('utf8') response = urllib.request.Request( 'https://www.douban.com/login', data=data, headers=headers) # 使用ProxyHandler方法生成处理器对象 proxy_handler = urllib.request.ProxyHandler(proxy) # 建立代理IP的opener实例 opener = urllib.request.build_opener(proxy_handler) # 将设置好的post信息和headers的response做为参数 html = opener.open(response) result = html.read().decode('utf8') print(result) except urllib.error.URLError as e: if hasattr(e, 'reason'): print('错误缘由是' + str(e.reason)) except urllib.error.HTTPError as e: if hasattr(e, 'code'): print('错误编码是' + str(e.code)) else: print('请求成功经过。')
在上面post请求代码的基础上,用本身建立的opener替换urlopen便可完成代理IP的操做,代理ip能够到一些免费的代理IP网站上查找,博主整理出几个,如:
运行获得的结果与使用本机IP同样。
# 这个代理IP数据类型为字典,若是是http协议,key值就为**"http"**,value值应为**"代理IP:端口号"的格式**。 proxy = {'http': '115.193.101.21:61234'} # 使用ProxyHandler方法建立proxy处理器对象 proxy_handler = urllib.request.ProxyHandler(proxy) # 建立代理IP的opener实例,参数为proxy处理器对象 opener = urllib.request.build_opener(proxy_handler) # 用代理IP的opener打开指定状态的URL信息 html = opener.open(response)
设置超时的目的是为了防止爬取网站的时候,等待时间过长而致使效率的下降。有效的超时设置能够强制结束等待而进行下一次的爬取,下面来一段代码看如何使用。
# coding:utf-8 import urllib.request import urllib.error import urllib.parse import socket # headers信息,从fiddler上或浏览器上可复制下来 headers = {'Accept': 'text/html,application/xhtml+xml, application/xml;q=0.9,image/webp,image/apng, */*;q=0.8', 'Accept-Language': 'zh-CN,zh;q=0.9', 'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)Chrome/48.0 .2564.48 Safari/537.36' } # POST请求的信息 value = {'source': 'index_nav', 'form_password': 'your password', 'form_email': 'your username' } # 代理IP为字典格式,key为'http',value为'代理ip:端口号' proxy = {'http': '115.193.101.21:61234'} # 设置超时为2秒,单位为秒 timeout = 2 try: # 设置socket超时 socket.setdefaulttimeout(timeout) data = urllib.parse.urlencode(value).encode('utf8') response = urllib.request.Request( 'https://www.douban.com/login', data=data, headers=headers) # 使用ProxyHandler方法生成处理器对象 proxy_handler = urllib.request.ProxyHandler(proxy) # 建立代理IP的opener实例 opener = urllib.request.build_opener(proxy_handler) # 将设置好的post信息和headers的response做为参数 html = opener.open(response) result = html.read().decode('utf8') print(result) except urllib.error.URLError as e: if hasattr(e, 'reason'): print('错误缘由是' + str(e.reason)) except urllib.error.HTTPError as e: if hasattr(e, 'code'): print('错误编码是' + str(e.code)) except socket.timeout: print('socket超时') else: print('请求成功经过。')
在post和代理IP使用的基础上又增长了超时的使用。
# 设置超时为2秒,单位为秒 timeout = 2 #设置socket超时时间,若是不设置,则会使用默认时间。 socket.setdefaulttimeout(timeout) # 同时对socket超时timeout的错误设置了异常,timeout错误属于OSerror的子类,时间超出指定timeout就会提示socket超时。 except socket.timeout: print('socket超时')
除了上面提到的urlencode方法,urllib库的parse中还有不少其它的方法可使用,如:
#urlparse:把URL解析成6个部分 <scheme>://<netloc>/<path>;<params>?<query>#<fragment> #urlsplit:把URL解析成5个部分 <scheme>://<netloc>/<path>?<query>#<fragment> # urlunsplit,urlunparse:进行URL的重组 # 还有urljoin,urldefrag等。
更多用法能够查找官方request源码,也会在后续实战例子中陆续使用介绍。
主要介绍了urllib库的一些高级使用用法:
关注微信公众号Python数据科学,获取 120G
人工智能 学习资料。