问题起源:公司买的java开发的项目没有源码,提供不了额外的接口,需要用爬虫单点登录之后获取数据。由于selenium要启动webdriver太慢,所以用urllib2实现登录。
1.首先需要理解cas授权和sso的原理,这个网上很多,自己看。关键是如何才能获取最终的SESSION。
2.urilib的post form貌似是不能实现自己携带cookie和转发的(java的httpclient貌似也是这样,需要自己处理response的location)
3.urllib2的handler可以实现诸如cookie存取、转发请求的的功能,所以需要子类去实现一下才能使用。
贴一波代码:
cj = cookielib.CookieJar();
class NewHTTPRedirectHandler(urllib2.HTTPRedirectHandler):
def http_error_302(self, req, fp, code, msg, headers):
return urllib2.HTTPRedirectHandler.http_error_302(self, req, fp, code, msg, headers)
http_error_301 = http_error_303 = http_error_307 = http_error_302
def create_cookie_handler():
global cj
# 创建cookie处理器
cookieprocessor = urllib2.HTTPCookieProcessor(cj)
# 创建RedirectHandler和cookiehander
opener = urllib2.build_opener(NewHTTPRedirectHandler, cookieprocessor)
urllib2.install_opener(opener);
cookielib是存取cookie的相当于浏览器上面的功能,NewHTTPRedirectHandler处理30*之类的转发请求。
问题:
最终我们能从以下代码获取到cookie的值。
for index, cookie in enumerate(cj):
cookie_dict.setdefault(cookie.name, cookie.value)
cookie_str = cookie_str + cookie.name+"="+cookie.value+";"
最终你可以在结果里面看到的有SESSION,但是这个SESSION不能用,登录不了。然后对比F12的网络请求和代码里面的def http_error_302(self, req, fp, code, msg, headers)的req和headers。最终发现req(代表下一次请求)没有SESSION,所以是不是response里面的set-cookie没有被下一个request获取到呢?
然后代码稍作改动:
class NewHTTPRedirectHandler(urllib2.HTTPRedirectHandler):
def http_error_302(self, req, fp, code, msg, headers):
# print req.get_header("Cookie"), code, msg
# print headers
set_cookie = headers.getheader("Set-Cookie")
if set_cookie is not None and 'SESSION' in set_cookie:
req.add_header("Cookie", set_cookie)
return urllib2.HTTPRedirectHandler.http_error_302(self, req, fp, code, msg, headers)
http_error_301 = http_error_303 = http_error_307 = http_error_302
这个就是拦截带有session的response,然后将setcookie的值放到request里面,最终好了。(不知道是不是cookielib不太完善还是这个转发请求的源码的问题,导致这种问题。浏览器是不会这样的。)
注:验证码大家可以去百度的图片中识别接口验证,图片转base64和utf-8就行。
这个问题熬了我两天,说明以后还是要静下心来分析问题的原因,这样才能一步步走向胜利。