03—小白学Python爬虫之urllib的基本和进阶使用及Get、Post示例
2018-03-06 20:12
1006 查看
urllib库官方文档地址:https://docs.python.org/3/library/urllib.html
python3.X —> urllib
在Pytho2.x中使用import urllib——-对应的,在Python3.x中会使用import urllib.request,urllib.error,urllib.parse
在Pytho2.x中使用import urlparse——-对应的,在Python3.x中会使用import urllib.parse
在Pytho2.x中使用import urlopen——-对应的,在Python3.x中会使用import urllib.request.urlopen
在Pytho2.x中使用import urlencode——-对应的,在Python3.x中会使用import urllib.parse.urlencode
在Pytho2.x中使用import urllib.quote——-对应的,在Python3.x中会使用import urllib.request.quote
在Pytho2.x中使用cookielib.CookieJar——-对应的,在Python3.x中会使用http.CookieJar
在Pytho2.x中使用urllib2.Request——-对应的,在Python3.x中会使用urllib.request.Request
urllib.error 异常处理模块
urllib.parse url解析模块
urllib.robotparser robots.txt解析模块
先来个入门示例:
如上,短短几行代码,就可以把baidu首页面的信息抓取下来。
其中post数据,需要进行urlencode,如data=bytes(parse.urlencode(data)
示例:
执行如上代码,会抛出如下异常:
so,需要对异常进行处理,修改代码如下:
输入结果为:
如上,超时异常就拦截了,可以做自己的相关处理。
但是基本的urlopen()方法不支持代理、cookie等其他的HTTP/HTTPS高级功能。所以要支持这些功能:
使用相关的 Handler处理器 来创建特定功能的处理器对象;
然后通过 urllib.request.build_opener()方法使用这些处理器对象,创建自定义opener对象;
使用自定义的opener对象,调用open()方法发送请求。
如果程序里所有的请求都使用自定义的opener,可以使用urllib.request.install_opener() 将自定义的 opener 对象 定义为 全局opener,表示如果之后凡是调用urlopen,都将使用这个opener(根据自己的需求来选择)
示例:
如果在 HTTPHandler()增加 debuglevel=1参数,还会将 Debug Log 打开,这样程序在执行的时候,会把收包和发包的报头在屏幕上自动打印出来,方便调试,有时可以省去抓包的工作。
示例一:
示例二:
创建一个密码管理对象,用来保存HTTP请求相关的用户名和密码。
主要两个场景:
1. 验证代理授权的用户名和密码(proxyBasicAuthHandler)
2. 验证web客户端的用户名和密码(HttpBasicAuthHandler)
ProxyBasicAuthHandler(代理授权验证)
如果我们使用之前的代码来使用私密代理,会报 HTTP 407 错误,表示代理没有通过身份验证:
所以我们需要改写代码,通过:
HTTPPasswordMgrWithDefaultRealm():来保存私密代理的用户密码
ProxyBasicAuthHandler():来处理代理的身份验证。
示例:
HTTPBasicAuthHandler处理器(Web客户端授权验证)
有些Web服务器(包括HTTP/FTP等)访问时,需要进行用户身份验证,爬虫直接访问会报HTTP 401 错误,表示访问身份未经授权:
如果我们有客户端的用户名和密码,我们可以通过下面的方法去访问爬取:
在访问网页的过程中,可能会出现一些异常,比如404 500 超时等,程序需要对这些信息做异常处理
分类
URLError 只有一个属性reason,即异常发生的时候只能打印错误信息
HTTPError 是URLError的子类,有三个属性,code reason headers三个信息
示例
示例一(URLError)
输出为:
示例二(HTTPError)
输出结果为:
通过reason做异常分析
可以通过捕获到的异常reason进行分析,比如超时,示例如下 :
输出结果为:
指某些网站为了辨别用户身份、进行 session 跟踪而储存在用户本地终端上的数据
可以保持用户登录信息,与服务端进行通信
Cookie原理
HTTP是无状态的面向连接的协议, 为了保持连接状态, 引入了Cookie机制 Cookie是http消息头中的一种属性,包括:
Cookie由变量名和值组成,根据 Netscape公司的规定,Cookie格式如下:
Cookie应用
Cookies在爬虫方面最典型的应用是判定用户是否已经登录,如果登录,在后续访问网站其他页面,需要携带server返回的cookie数据,这样就不需要重复登录了。
示例:
如上,通过查看控制台,就能发现确实返回我的收藏内容,此处略。
但是这样过于复杂,需要先登录页面,通过工具抓包才能拿到cookie信息,那么有木有简单一点的呢?当然是有喽~
cookielib库和HTTPCookiePorcessor处理器
在Python处理Cookie,一般是通过cookielib模块和 urllib模块的HTTPCookieProcessor处理器类一起使用。
cookielib库简介
该模块主要的对象有CookieJar、FileCookieJar、MozillaCookieJar、LWPCookieJar。
CookieJar:管理HTTP cookie值、存储HTTP请求生成的cookie、向传出的HTTP请求添加cookie的对象。整个cookie都存储在内存中,对CookieJar实例进行垃圾回收后cookie也将丢失。
FileCookieJar (filename,delayload=None,policy=None):从CookieJar派生而来,用来创建FileCookieJar实例,检索cookie信息并将cookie存储到文件中。filename是存储cookie的文件名。delayload为True时支持延迟访问访问文件,即只有在需要时才读取文件或在文件中存储数据。
MozillaCookieJar (filename,delayload=None,policy=None):从FileCookieJar派生而来,创建与Mozilla浏览器 cookies.txt兼容的FileCookieJar实例。
LWPCookieJar (filename,delayload=None,policy=None):从FileCookieJar派生而来,创建与libwww-perl标准的 Set-Cookie3 文件格式兼容的FileCookieJar实例。
大多数情况下,我们只用CookieJar(),如果需要和本地文件交互,就用 MozillaCookjar() 或 LWPCookieJar()
示例一(获取Cookie保存到CookieJar对象中)
输出结果为:
示例二(获取Cookie,并保存到本地文件中)
执行完成后,会发现在当前目录下创建cookie_file.txt,内容为:
示例三(从文件中获取Cookie,并作为请求的一部分去访问)
登录人人网,然后再获取某人的页面数据信息
如上,当用户名密码输入错误时,会返回如下信息:
当不登录直接访问目标页面时,会跳转到登录页面,提示需要登录才可以访问。
当输入正确用户名密码,通过cookieJar保存Cookie信息,再去获取主页面信息时,会发现可以拿到数据了,如下:
so,基于CookieJar和post模拟登录就搞定了。
注意事项
登录一般都会先有一个HTTP GET,用于拉取一些信息及获得Cookie,然后再HTTP POST登录。
HTTP POST登录的链接有可能是动态的,从GET返回的信息中获取。
password 有些是明文发送,有些是加密后发送。有些网站甚至采用动态加密的,同时包括了很多其他数据的加密信息,只能通过查看JS源码获得加密算法,再去破解加密,非常困难。
大多数网站的登录整体流程是类似的,可能有些细节不一样,所以不能保证其他网站登录成功。
当然,我们也可以直接发送账号密码到登录界面模拟登录,但是当网页采用JavaScript动态技术以后,想封锁基于 HttpClient 的模拟登录就太容易了,甚至可以根据你的鼠标活动的特征准确地判断出是不是真人在操作。
想做通用的模拟登录还得选别的技术,比如用内置浏览器引擎的爬虫(关键词:Selenium ,PhantomJS),这个我们将在后续说到。
输入要抓取的贴吧名以及起始页和结束页,然后对页面进行爬取,并下载到本地。
通过Chrome浏览器开发者工具,监控发现,其Request Header, Response Header以及form data如下:
根据上面拦截到的信息,拼装自己的请求,然后发送:
输入”hello”,运行结果为:
so,这样就完成了一个简单的post请求。
不过上述代码只对”hello”有效,因为form参数中有sign签名校验,目前还不知道怎么破解,不过这也难不倒我们,后续我们会介绍如何从爬到的HTML中获取我们关心的数据信息。
urllib库的基本使用和参数介绍就到这了,休息,休息一下~
urllib简介
概述
urllib是python内置的HTTP请求库。版本
python2.X —> urllib和urllib2python3.X —> urllib
变化
在Pytho2.x中使用import urllib2——-对应的,在Python3.x中会使用import urllib.request,urllib.error在Pytho2.x中使用import urllib——-对应的,在Python3.x中会使用import urllib.request,urllib.error,urllib.parse
在Pytho2.x中使用import urlparse——-对应的,在Python3.x中会使用import urllib.parse
在Pytho2.x中使用import urlopen——-对应的,在Python3.x中会使用import urllib.request.urlopen
在Pytho2.x中使用import urlencode——-对应的,在Python3.x中会使用import urllib.parse.urlencode
在Pytho2.x中使用import urllib.quote——-对应的,在Python3.x中会使用import urllib.request.quote
在Pytho2.x中使用cookielib.CookieJar——-对应的,在Python3.x中会使用http.CookieJar
在Pytho2.x中使用urllib2.Request——-对应的,在Python3.x中会使用urllib.request.Request
urllib基本使用
接下来示例代码都是以python3.X中使用的urllib模块
urllib.request 请求模块urllib.error 异常处理模块
urllib.parse url解析模块
urllib.robotparser robots.txt解析模块
urlopen
方法参数:urllib.request.urlopen(url, data=None, [timeout, ]*, cafile=None, capath=None, cadefault=False, context=None)
先来个入门示例:
from urllib import request def demo(): """ 直接使用urlopen打开网页,返回结果可以作为一个文件对象进行操作 :return: """ with request.urlopen('http://www.baidu.com') as f: # 读取返回的数据 data = f.read() # 请求code码 200 404 500 403 print('code:', f.getcode()) # 返回实际数据的URL print('url:', f.geturl()) # 服务器返回的http报头信息 print('info:', f.info()) print('Status:', f.status, f.reason) for k, v in f.getheaders(): print('%s: %s' % (k, v)) print('Data:', data.decode('utf-8')) if __name__ == '__main__': demo()
如上,短短几行代码,就可以把baidu首页面的信息抓取下来。
构建urlrequest.Request对象
除了上面直接使用urlopen传入url打开网页,还可以通过构造Request对象来完成def demo2(): """ 构建一个request对象,URL作为构造参数传入 :return: """ req = request.Request('http://www.baidu.com') resp = request.urlopen(req) print('resp:', resp.read().decode('utf-8'))
Header
上篇文章说过request header相关信息,在header中,使用最多的就是User-Agent,有些网页为了防止别人恶意采集信息而做了一些反爬虫的设置,而我们在爬取时可以通过设置UA来模拟成浏览器来访问。def demo3(): headers = { 'User-Agent': 'Mozilla/5.0' } req = request.Request('http://www.baidu.com', headers=headers) resp = request.urlopen(req) print(resp.read().decode('utf-8'))
data参数-区别post和get
urlopen中,data参数如果为空,代表get请求,如果不为空,则代表post请求。其中post数据,需要进行urlencode,如data=bytes(parse.urlencode(data)
示例:
def demo3(): """ urlopen方法中增加data参数代表是一个post请求 设置headers,比如UA :return: """ req = request.Request('http://www.baidu.com') req.add_header('User-Agent', 'Mozilla/5.0') data = { 'name': 'wangcai' } resp = request.urlopen(req, data=bytes(parse.urlencode(data), encoding='utf-8')) print(resp.read().decode('utf-8'))
timeout
有时候,网络不好或者服务器响应比较慢 请求异常等,需要给请求设置一个超时时间,及时做出反应,而不是让程序无限制等待。def demo4(): resp = request.urlopen("http://www.baidu.com", timeout=0.01) print(resp.read().decode('utf-8'))
执行如上代码,会抛出如下异常:
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/urllib/request.py", line 1321, in do_open r = h.getresponse() File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/http/client.py", line 1331, in getresponse response.begin() File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/http/client.py", line 297, in begin version, status, reason = self._read_status() File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/http/client.py", line 258, in _read_status line = str(self.fp.readline(_MAXLINE + 1), "iso-8859-1") File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/socket.py", line 586, in readinto return self._sock.recv_into(b) socket.timeout: timed out
so,需要对异常进行处理,修改代码如下:
def demo4(): try: resp = request.urlopen("http://www.baidu.com", timeout=0.001) print(resp.read().decode('utf-8')) except error.URLError as e: if isinstance(e.reason, socket.timeout): print('timeout , stop')
输入结果为:
timeout , stop
如上,超时异常就拦截了,可以做自己的相关处理。
自定义opener
opener是 urllib2.OpenerDirector 的实例,我们之前一直都在使用的urlopen,它是一个特殊的opener(也就是模块帮我们构建好的)。但是基本的urlopen()方法不支持代理、cookie等其他的HTTP/HTTPS高级功能。所以要支持这些功能:
使用相关的 Handler处理器 来创建特定功能的处理器对象;
然后通过 urllib.request.build_opener()方法使用这些处理器对象,创建自定义opener对象;
使用自定义的opener对象,调用open()方法发送请求。
如果程序里所有的请求都使用自定义的opener,可以使用urllib.request.install_opener() 将自定义的 opener 对象 定义为 全局opener,表示如果之后凡是调用urlopen,都将使用这个opener(根据自己的需求来选择)
示例:
from urllib import request def demo(): # 构建一个HTTPHandler处理器对象,支持HTTP请求 http_handler = request.HTTPHandler() # 调用urllib.request的build_opener方法,创建支持http请求的opener对象 opener = request.build_opener(http_handler) # 构建request请求 req = request.Request("http://www.baidu.com") # 使用自定义opener对象的open方法,发送request请求 response = opener.open(req) # 获取server响应 print(response.read().decode('utf-8')) if __name__ == '__main__': demo()
如果在 HTTPHandler()增加 debuglevel=1参数,还会将 Debug Log 打开,这样程序在执行的时候,会把收包和发包的报头在屏幕上自动打印出来,方便调试,有时可以省去抓包的工作。
# 构建一个HTTPHandler 处理器对象,支持处理HTTP请求,同时开启Debug Log,debuglevel 值默认 0 http_handler = urllib2.HTTPHandler(debuglevel=1) # 构建一个HTTPSHandler 处理器对象,支持处理HTTPS请求,同时开启Debug Log,debuglevel 值默认 0 https_handler = urllib2.HTTPSHandler(debuglevel=1)
Handler处理器
很多网站会检测某一段时间某个IP的访问次数(通过流量统计 系统日志等方法),如果监测不正常的话,那就会封掉这个IP的访问。这个时候,我们可以通过设置代理服务器,定时更换IP进行爬取解决。示例一:
def handler_demo(): # 构建两个Handler,一个有代理IP,一个无 httpproxy_handler = request.ProxyHandler({"http": "192.168.1.1:80"}) nullproxy_handler = request.ProxyHandler() # 通过build_opener方法使用Handler代理对象,创建自定义opener opener = request.build_opener(httpproxy_handler) # 构建request请求 req = request.Request("http://www.baidu.com") # 使用代理,只有opener.open才会生效,urlopen无效 response = opener.open(req) print(response.read().decode('utf-8')) # 如果使用request.install_opener(opener),那么不管使用opener.open()还是urlopen()都将使用代理
示例二:
def handler_demo2(): """ 代理足够多,可以随机选择一个去访问 :return: """ proxy_list = [ {"http": "101.200.24.123:80"}, {"http": "101.200.24.123:80"}, {"http": "101.200.24.123:80"}, {"http": "101.200.24.123:80"}, ] proxy = random.choice(proxy_list) handler = request.ProxyHandler(proxy) opener = request.build_opener(handler) req = request.Request("http://www.baidu.com") response = opener.open(req) print(response.read().decode('utf-8'))
HTTPPasswordMgrWithDefaultRealm
HTTPPasswordMgrWithDefaultRealm创建一个密码管理对象,用来保存HTTP请求相关的用户名和密码。
主要两个场景:
1. 验证代理授权的用户名和密码(proxyBasicAuthHandler)
2. 验证web客户端的用户名和密码(HttpBasicAuthHandler)
ProxyBasicAuthHandler(代理授权验证)
如果我们使用之前的代码来使用私密代理,会报 HTTP 407 错误,表示代理没有通过身份验证:
HTTPError: HTTP Error 407: Proxy Authentication Required
所以我们需要改写代码,通过:
HTTPPasswordMgrWithDefaultRealm():来保存私密代理的用户密码
ProxyBasicAuthHandler():来处理代理的身份验证。
示例:
def pwd_demo(): # 私密代理授权的账户 密码 user = 'demo' pwd = '1234' # 私密代理IP proxy_server = '119.129.99.29:1231' # 构建一个密码管理对象,保存用户名和密码 pwdmgr = request.HTTPPasswordMgrWithDefaultRealm() # 添加账户信息 pwdmgr.add_password(None, proxy_server, user=user, passwd=pwd) # 构建一个代理基础用户名/密码验证的ProxyBasicAuthHandler对象,参数是创建的密码管理对象 proxy_handler = request.ProxyBasicAuthHandler(pwdmgr) # 通过build_opener方法使用Handler创建自定义opener opener = request.build_opener(proxy_handler) # 构造request请求 req = request.Request("http://www.baidu.com") # 发送请求并打印响应 response = opener.open(req) print(response.read().decode('utf-8'))
HTTPBasicAuthHandler处理器(Web客户端授权验证)
有些Web服务器(包括HTTP/FTP等)访问时,需要进行用户身份验证,爬虫直接访问会报HTTP 401 错误,表示访问身份未经授权:
HTTPError: HTTP Error 401: Unauthorized
如果我们有客户端的用户名和密码,我们可以通过下面的方法去访问爬取:
def pwd_demo2(): # 私密代理授权的账户 密码 user = 'wangcai' pwd = '12345qwertyui' # web客户端IP web_server = '10.0.2.101:80' # 构建一个密码管理对象,保存用户名和密码 pwdmgr = request.HTTPPasswordMgrWithDefaultRealm() # 添加账户信息 pwdmgr.add_password(None, web_server, user=user, passwd=pwd) # 构建一个代理基础用户名/密码验证的HttpBasicAuthHandler对象,参数是创建的密码管理对象 proxy_handler = request.HTTPBasicAuthHandler(pwdmgr) # 通过build_opener方法使用Handler创建自定义opener opener = request.build_opener(proxy_handler) # 构造request请求 req = request.Request("http://www.baidu.com") # 发送请求并打印响应(requesr.install_opener()执行后,全局生效) response = opener.open(req) print(response.read().decode('utf-8'))
异常处理
概念在访问网页的过程中,可能会出现一些异常,比如404 500 超时等,程序需要对这些信息做异常处理
分类
URLError 只有一个属性reason,即异常发生的时候只能打印错误信息
HTTPError 是URLError的子类,有三个属性,code reason headers三个信息
示例
示例一(URLError)
def demo(): try: resp = request.urlopen("http://www.baiduasw.com") print(resp.read().decode('utf-8')) except error.URLError as e: print(e.reason)
输出为:
[Errno 8] nodename nor servname provided, or not known
示例二(HTTPError)
def demo2(): try: resp = request.urlopen("http://www.csdn.net/abcs.html") print(resp.read().decode('utf-8')) except error.HTTPError as e: print(e.reason, e.code, e.headers) except error.URLError as e: print(e.reason) else: print('success')
输出结果为:
Not Found 404 Server: openresty Date: Tue, 06 Mar 2018 12:06:58 GMT Content-Type: text/html; charset=utf-8 Content-Length: 4144 Connection: close Vary: Accept-Encoding Set-Cookie: uuid_tt_dd=10_18754355060-1520338018722-773220; Expires=Thu, 01 Jan 2025 00:00:00 GMT; Path=/; Domain=.csdn.net; Set-Cookie: dc_session_id=10_1520338018722.227796; Expires=Thu, 01 Jan 2025 00:00:00 GMT; Path=/; Domain=.csdn.net; ETag: "5a324c78-1030"
通过reason做异常分析
可以通过捕获到的异常reason进行分析,比如超时,示例如下 :
def demo3(): try: request.urlopen("http://www.baidu.com", timeout=0.001) except error.URLError as e: print(type(e.reason)) if isinstance(e.reason, socket.timeout): print('连接超时')
输出结果为:
<class 'socket.timeout'> 连接超时
Cookie
概念指某些网站为了辨别用户身份、进行 session 跟踪而储存在用户本地终端上的数据
可以保持用户登录信息,与服务端进行通信
Cookie原理
HTTP是无状态的面向连接的协议, 为了保持连接状态, 引入了Cookie机制 Cookie是http消息头中的一种属性,包括:
Cookie名字(Name) Cookie的值(Value) Cookie的过期时间(Expires/Max-Age) Cookie作用路径(Path) Cookie所在域名(Domain), 使用Cookie进行安全连接(Secure)。 前两个参数是Cookie应用的必要条件,另外,还包括Cookie大小(Size,不同浏览器对Cookie个数及大小限制是有差异的)。
Cookie由变量名和值组成,根据 Netscape公司的规定,Cookie格式如下:
Set-Cookie: NAME=VALUE;Expires=DATE;Path=PATH;Domain=DOMAIN_NAME;SECURE
Cookie应用
Cookies在爬虫方面最典型的应用是判定用户是否已经登录,如果登录,在后续访问网站其他页面,需要携带server返回的cookie数据,这样就不需要重复登录了。
示例:
from urllib import request import http.cookiejar import ssl def demo(): # 通过Chrome开发者工具获取到的headers信息 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', 'Connection': 'keep-alive', # 如果没有这个数据,会获取不到内容 'Cookie': 'SINAGLOBAL=14451465401860.67.1489663918038; UOR=,,www.cidu.com.cn; ULV=15126380274353:39:2:1:654449358996.8848.15312638074260:1512122654080; YF-Page-G0=3d55e256bde550ac7b0d32a2ad7d6fa53; __ln4krntdmcvrd=-1; login_sid_t=764ees242ec6c2c671008097fe81d9776; cross_origin_praoto=SSL; YF-Ugrow-G0=ad8a3bc19dc1269e709f753b172bddb094; YF-V5-G0=020421dd53s5a1c903e89d913fb8a2988; WBStorage=c5ff51a335af29d81|undefined; WBtopGlobal_register_version=d7a77880fa9c5f84; SCF=ApB-0Hdxe1pH2EVUwj6T7lnFDhHVmpTrGutTGUCBqAxNpYokCZKUXDXjFb7jnhhuX52vPbRLRqP7Q1qC5LF6HDE.; SUB=_2A253mhxmDeRhGeVG71AR-SjEzz-IHXVU7gqurDV8asdasPUNbmtANLUOjkW9NT7lHG3qdhhmQlBxLcF_jvJiQRxBGY_6P; SUBP=0033WrSXqPxfM725Ws9jqgMF55529P9D9Wh1676ff2MDLHTsnQwjrekN9-b5JpX5KzhUgL.FoeRShadaz71KqRShe2dJLoIEXLxK-LBo5L12235qLxKqLBoBL12zLxKBLB.2LB.2LxKqL1-eL1hWQqPW7wKz7eKnt; SUHB=0FQbL0-bhmNpOg; ALF=1551867826; SSOLoginState=1520331826; wvr=6; wb_timefeed_3842096843=1', 'Host': 'weibo.com', 'Referer': 'https://weibo.com/u/3842096843/home?leftnav=1', 'Upgrade-Insecure-Requests': '1', 'User-Agent': 'ozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36', } url = 'https://weibo.com/fav?leftnav=1&pids=plc_main&ajaxpagelet=1&ajaxpagelet_v6=1&__ref=%2Fu%2F3842096843%2Fhome%3Fleftnav%3D1&_t=FM_152033182791241' # 构建request对象 req = request.Request(url, headers=headers) # 不验证https context = ssl._create_unverified_context() # 发送请求 response = request.urlopen(req, context=context) # 打印响应内容 print(response.read().decode('utf-8')) if __name__ == '__main__': demo()
如上,通过查看控制台,就能发现确实返回我的收藏内容,此处略。
但是这样过于复杂,需要先登录页面,通过工具抓包才能拿到cookie信息,那么有木有简单一点的呢?当然是有喽~
cookielib库和HTTPCookiePorcessor处理器
在Python处理Cookie,一般是通过cookielib模块和 urllib模块的HTTPCookieProcessor处理器类一起使用。
cookielib模块:主要作用是提供用于存储cookie的对象 HTTPCookieProcessor处理器:主要作用是处理这些cookie对象,并构建handler对象。
cookielib库简介
该模块主要的对象有CookieJar、FileCookieJar、MozillaCookieJar、LWPCookieJar。
CookieJar:管理HTTP cookie值、存储HTTP请求生成的cookie、向传出的HTTP请求添加cookie的对象。整个cookie都存储在内存中,对CookieJar实例进行垃圾回收后cookie也将丢失。
FileCookieJar (filename,delayload=None,policy=None):从CookieJar派生而来,用来创建FileCookieJar实例,检索cookie信息并将cookie存储到文件中。filename是存储cookie的文件名。delayload为True时支持延迟访问访问文件,即只有在需要时才读取文件或在文件中存储数据。
MozillaCookieJar (filename,delayload=None,policy=None):从FileCookieJar派生而来,创建与Mozilla浏览器 cookies.txt兼容的FileCookieJar实例。
LWPCookieJar (filename,delayload=None,policy=None):从FileCookieJar派生而来,创建与libwww-perl标准的 Set-Cookie3 文件格式兼容的FileCookieJar实例。
大多数情况下,我们只用CookieJar(),如果需要和本地文件交互,就用 MozillaCookjar() 或 LWPCookieJar()
示例一(获取Cookie保存到CookieJar对象中)
from urllib import request import http.cookiejar import ssl def demo2(): """ 获取cookie,并保存在cookieJar对象中 :return: """ # 构建cookieJar对象来保存cookie cookie_jar = http.cookiejar.CookieJar() # 使用httpCookiePorcessor创建Cookie处理器对象,参数为cookieJar http_cookie_processor = request.HTTPCookieProcessor(cookiejar=cookie_jar) # 构建opener opener = request.build_opener(http_cookie_processor) # 构建request req = request.Request("http://www.baidu.com") # 发送请求 response = opener.open(req) # 打印cookie信息 for item in cookie_jar: print(item.name + '=' + item.value) print('done')
输出结果为:
BAIDUID=88BA4BF20ED5C2838A1C96CE468B767B:FG=1 BIDUPSID=88BA4BF20ED5C2838A1C96CE468B767B H_PS_PSSID=1435_21106_17001_20718 PSTM=1520334302 BDSVRTM=0 BD_HOME=0 done
示例二(获取Cookie,并保存到本地文件中)
def demo3(): """ 获取cookie,并保存到cookie文件中 :return: """ # 文件名 cookie_filename = 'cookie_file.txt' # 构建cookieJar对象来保存cookie cookie_jar = http.cookiejar.MozillaCookieJar(filename=cookie_filename) # 使用httpCookiePorcessor创建Cookie处理器对象,参数为cookieJar http_cookie_processor = request.HTTPCookieProcessor(cookiejar=cookie_jar) # 构建opener opener = request.build_opener(http_cookie_processor) # 构建request req = request.Request("http://www.baidu.com") # 发送请求 response = opener.open(req) # 保存cookie信息 cookie_jar.save() print('done')
执行完成后,会发现在当前目录下创建cookie_file.txt,内容为:
# Netscape HTTP Cookie File # http://curl.haxx.se/rfc/cookie_spec.html # This is a generated file! Do not edit. .baidu.com TRUE / FALSE 3667818295 BAIDUID E06113B9C530BDC0B53043B8D3E8E964:FG=1 .baidu.com TRUE / FALSE 3667818295 BIDUPSID E06113B9C530BDC0B53043B8D3E8E964 .baidu.com TRUE / FALSE 3667818295 PSTM 1520334648
示例三(从文件中获取Cookie,并作为请求的一部分去访问)
def demo4(): """ 从文件中获取Cookie,并作为请求的一部分 :return: """ # 创建MozillaCookieJar对象 cookie_jar = http.cookiejar.MozillaCookieJar() # 文件名 cookie_filename = 'cookie_file.txt' # 读取cookie内容 cookie_jar.load(cookie_filename) # 使用httpCookiePorcessor创建Cookie处理器对象,参数为cookieJar http_cookie_processor = request.HTTPCookieProcessor(cookiejar=cookie_jar) # 构建opener opener = request.build_opener(http_cookie_processor) # 构建request req = request.Request("http://www.baidu.com") # 发送请求 response = opener.open(req) print('done')
使用Cookielib和post登录人人网
示例登录人人网,然后再获取某人的页面数据信息
import http.cookiejar from urllib import request, parse def demo(): # 1. 构建一个CookieJar对象实例来保存cookie cookie = http.cookiejar.CookieJar() # 2. 使用HTTPCookieProcessor()来创建cookie处理器对象,参数为CookieJar()对象 cookie_handler = request.HTTPCookieProcessor(cookie) # 3. 通过 build_opener() 来构建opener opener = request.build_opener(cookie_handler) # 4. addheaders 接受一个列表,里面每个元素都是一个headers信息的元祖, opener将附带headers信息 opener.addheaders = [("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36")] # 5. 需要登录的账户和密码 data = {"email": "xxx@163.com", "password": "123456opmhsa"} # 6. 通过urlencode()转码 postdata = bytes(parse.urlencode(data), encoding='utf-8') # 7. 构建Request请求对象,包含需要发送的用户名和密码 req = request.Request("http://www.renren.com/PLogin.do", data=postdata) # 8. 通过opener发送这个请求,并获取登录后的Cookie值, opener.open(req) # 9. opener包含用户登录后的Cookie值,可以直接访问那些登录后才可以访问的页面 response = opener.open("http://www.renren.com/410043129/profile") # 10. 打印响应内容 print(response.read().decode('utf-8'))
如上,当用户名密码输入错误时,会返回如下信息:
<a class="close" href="javascript:closeError();"></a> <p class="wrong">您的用户名和密码不匹配</p> <p class="worp">为了账号安全,已向您的邮箱: <strong id="sendemail"></strong>发送了一封确认信,请通过邮件内链接登录。</p> <p class="m-26"><a id="gotoEmail" href="#" target="_blank">打开邮箱查收确认信</a></p> <p class="m-26"><a href="javascript:closeError();">重新输入</a></p>
当不登录直接访问目标页面时,会跳转到登录页面,提示需要登录才可以访问。
当输入正确用户名密码,通过cookieJar保存Cookie信息,再去获取主页面信息时,会发现可以拿到数据了,如下:
<head> <meta name="Description" content="人人网 校内是一个真实的社交网络,联络你和你周围的朋友。 加入人人网校内你可以:联络朋友,了解他们的最新动态;和朋友分享相片、音乐和电影;找到老同学,结识新朋友;用照片和日志记录生活,展示自我。"/> <meta name="Keywords" content="Xiaonei,Renren,校内,大学,同学,同事,白领,个人主页,博客,相册,群组,社区,交友,聊天,音乐,视频,校园,人人,人人网"/> <title>人人网 - 邓**❤</title> <meta charset="utf-8"/>
so,基于CookieJar和post模拟登录就搞定了。
注意事项
登录一般都会先有一个HTTP GET,用于拉取一些信息及获得Cookie,然后再HTTP POST登录。
HTTP POST登录的链接有可能是动态的,从GET返回的信息中获取。
password 有些是明文发送,有些是加密后发送。有些网站甚至采用动态加密的,同时包括了很多其他数据的加密信息,只能通过查看JS源码获得加密算法,再去破解加密,非常困难。
大多数网站的登录整体流程是类似的,可能有些细节不一样,所以不能保证其他网站登录成功。
当然,我们也可以直接发送账号密码到登录界面模拟登录,但是当网页采用JavaScript动态技术以后,想封锁基于 HttpClient 的模拟登录就太容易了,甚至可以根据你的鼠标活动的特征准确地判断出是不是真人在操作。
想做通用的模拟登录还得选别的技术,比如用内置浏览器引擎的爬虫(关键词:Selenium ,PhantomJS),这个我们将在后续说到。
get示例
贴吧爬取程序功能:输入要抓取的贴吧名以及起始页和结束页,然后对页面进行爬取,并下载到本地。
from urllib import request, parse import ssl """ 通过浏览器抓取URL发现,其真实URL为:http://tieba.baidu.com/f?kw=python&ie=utf-8&pn=50 kw为关键词 ie为编码格式 pn为查询列表起始位置,计算公式为:(current_page -1) * 50 """ def spiderHtml(page, fullurl): print('*' * 15 + '正在爬取第' + str(page) + '页数据') headers = { 'User-Agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Mobile Safari/537.36' } context = ssl._create_unverified_context() req = request.Request(fullurl, headers=headers) response = request.urlopen(req, context=context) print('*' * 15 + '第' + str(page) + '页数据爬取完成') return response.read() def savehtml(page, html): """ 保存抓取的页面数据 :param page: 当前页 :param html: 页面数据 :return: """ with open('num' + str(page) + '.html', mode='wb+') as f: print('正在保存第%d页信息' % page) f.write(html) print('第%d页信息保存成功' % page) def mainEntrance(url, startpage, endpage): """ 爬虫主入口 :param url: 基础URL :param startpage: 起始页 :param endpage: 结束页 :return: """ for page in range(startpage, endpage + 1): pn = (page - 1) * 50 fullurl = url + '&' + str(pn) html = spiderHtml(page, fullurl) savehtml(page, html) if __name__ == '__main__': keyword = input("请输入贴吧名:") startpage = int(input("请输入起始页:")) endpage = int(input("请输入结束页:")) data = { 'kw': keyword } encodeData = parse.urlencode(data) url = 'http://tieba.baidu.com/f?' + encodeData mainEntrance(url, startpage, endpage)
post示例
以有道字典,翻译”hello”为例。通过Chrome浏览器开发者工具,监控发现,其Request Header, Response Header以及form data如下:
""" General: Request URL:http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule Request Method:POST Status Code:200 OK Remote Address:220.181.76.84:80 Referrer Policy:no-referrer-when-downgrade Response Headers: Connection:keep-alive Content-Encoding:gzip Content-Type:application/json; charset=utf-8 Date:Fri, 02 Mar 2018 02:18:25 GMT Server:nginx Set-Cookie:YOUDAO_MOBILE_ACCESS_TYPE=0; domain=.youdao.com; expires=Sat, 02-Mar-2019 02:18:25 GMT Transfer-Encoding:chunked Vary:Accept-Encoding Request Headers: Accept:application/json, text/javascript, */*; q=0.01 Accept-Encoding:gzip, deflate Accept-Language:zh-CN,zh;q=0.9 Connection:keep-alive Content-Length:205 Content-Type:application/x-www-form-urlencoded; charset=UTF-8 Cookie:OUTFOX_SEARCH_USER_ID_NCOO=901526923.248523; _ntes_nnid=d2c9f3c0ad87edc2a18d8baf7493468a,1489816879253; P_INFO=sijipingzaojia@126.com|1507340542|0|other|00&99|shd&1506756788&other#shd&370100#10#0#0|&0||sijipingzaojia@126.com; OUTFOX_SEARCH_USER_ID=1202025429@123.58.182.244; _ga=GA1.2.1223743331.1511144818; _ym_uid=1517990399796278715; DICT_UGC=be3af0da19b5c5e6aa4e17bd8d90b28a|; JSESSIONID=abce35wgNPW3r7TqipGhw; __lnkrntdmcvrd=-1; ___rl__test__cookies=1519957105235 Host:fanyi.youdao.com Origin:http://fanyi.youdao.com Referer:http://fanyi.youdao.com/?keyfrom=dict2.top User-Agent:Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Mobile Safari/537.36 X-Requested-With:XMLHttpRequest Quert String Parameyters: smartresult:dict smartresult:rule Form Data: i:hello from:AUTO to:AUTO smartresult:dict client:fanyideskweb salt:1519957105239 sign:8576918dd13c8c792aabc6986380a8bb doctype:json version:2.1 keyfrom:fanyi.web action:FY_BY_CLICKBUTTION typoResult:false """
根据上面拦截到的信息,拼装自己的请求,然后发送:
def doDict(keyword): headers = { 'Accept': 'application/json, text/javascript, */*; q=0.01', "Connection": "keep - alive", 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', 'User-Agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Mobile Safari/537.36', 'Host': 'fanyi.youdao.com', 'Origin': 'http: // fanyi.youdao.com', 'Referer': 'http://fanyi.youdao.com/?keyfrom=dict2.top', 'X-Requested-With': 'XMLHttpRequest', 'Cookie': 'OUTFOX_SEARCH_USER_ID_NCOO=901526923.248523; _ntes_nnid=d2c9f3c0ad87edc2a18d8baf7493468a,1489816879253; P_INFO=sijipingzaojia@126.com|1507340542|0|other|00&99|shd&1506756788&other#shd&370100#10#0#0|&0||sijipingzaojia@126.com; OUTFOX_SEARCH_USER_ID=1202025429@123.58.182.244; _ga=GA1.2.1223743331.1511144818; _ym_uid=1517990399796278715; DICT_UGC=be3af0da19b5c5e6aa4e17bd8d90b28a|; JSESSIONID=abce35wgNPW3r7TqipGhw; __lnkrntdmcvrd=-1; YOUDAO_MOBILE_ACCESS_TYPE=0; ___rl__test__cookies=1519960368231', } req = request.Request("http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule", headers=headers) data = { 'i': keyword, 'from': 'AUTO', 'to': 'AUTO', 'smartresult': 'dict', 'client': 'fanyideskweb', 'salt': '1519960368238', 'sign': '1078dab49931bac7081851a7da7320b2', 'doctype': 'json', 'version': '2.1', 'keyfrom': 'fanyi.web', 'action': 'FY_BY_CLICKBUTTION', 'typoResult': 'false', } encode_data = bytes(parse.urlencode(data), encoding='utf-8') response = request.urlopen(req, data=encode_data) print(response.read().decode('utf-8')) if __name__ == '__main__': keyword = input("请输入要翻译的单词:") doDict(keyword)
输入”hello”,运行结果为:
{"translateResult":[[{"tgt":"你好","src":"hello"}]],"errorCode":0,"type":"en2zh-CHS","smartResult":{"entries":["","n. 表示问候, 惊奇或唤起注意时的用语\r\n","int. 喂;哈罗\r\n","n. (Hello)人名;(法)埃洛\r\n"],"type":1}}
so,这样就完成了一个简单的post请求。
不过上述代码只对”hello”有效,因为form参数中有sign签名校验,目前还不知道怎么破解,不过这也难不倒我们,后续我们会介绍如何从爬到的HTML中获取我们关心的数据信息。
urllib库的基本使用和参数介绍就到这了,休息,休息一下~
相关文章推荐
- urllib库的简单使用 && 一个简单的Python爬虫示例
- Python爬虫入门之Urllib库的基本使用
- python爬虫get和post方法的使用以及cookie
- python爬虫(四)_urllib2库的基本使用
- python爬虫(五)_urllib2:Get请求和Post请求
- [Python] - 爬虫之Urllib库的基本使用
- Python中使用urllib2模块编写爬虫的简单上手示例
- [Python爬虫] 使用urllib2库检测代理ip是否可用,并使用代理提交GET、POST请求
- Python爬虫之Urllib库的基本使用
- Python爬虫之pandas基本安装与使用方法示例
- 03Python爬虫---延时以及GET和POST请求
- Python爬虫学习--urllib的基本使用笔记
- Python爬虫入门一之Urllib库的基本使用
- python爬虫之urllib3的使用示例
- Python3爬虫进阶urllib模块的使用笔记
- Python中使用urllib2模块编写爬虫的简单上手示例
- Python3爬虫之urllib爬取异步Ajax数据,使用post请求!
- python3.6通过urllib模块使用post/get方法
- Python爬虫入门之Urllib库的基本使用 (三)
- [UIA]Python使用UIA基本示例