Python 从零开始爬虫(九)——模拟登录,cookie的使用

某些网站,登录和没登录,用户的权限是不一样的,帐号登录之后才能获取更多的信息。更有甚者一上来就是登录界面,不登录就不给你进去(如p站)。爬取目标不用登录固然是好,但需要时也没办法啊,这时如果还想爬取信息,就必须让爬虫学会登录。

Cookie

说到这里就要介绍一下本文的小主角cookie了,简单的说,cookie是服务器安在客户端的“监视器”,记录了包括登录状态在内的所有信息,这些信息由服务器生成和解释,服务器通过客户端携带的cookie来识别用户。cookie存在生命周期,短的关掉浏览器就失效,长的能若干天免登陆,一旦失效就要重新获取。所以只要得到登录后的cookie并必要时进行更新,服务器就会认定其为登录状态。本文将介绍几种主流方法来模拟登录

注意:并不是说学会这几种方法你就完全掌握了模拟登录,加密,验证系统也可能成为模拟登录的头号劲敌,如果查遍全网都没得到满意的答案,selenium大佬也被识别了,那估计是没救了

从浏览器获取

这是最简单也是最容易见效的方法,在浏览器上登录并进行足够多操作后获得便能得到足量的cookie,打开F12捉包观其headers即可
图片描述

图中上方的set-cookie是响应cookie,也就是服务器要保存在客户端的cookie;下方的cookie则是要提交给服务器的cookie,也是我们的目标,让requests使用这个cookie有两种方法,一是原封不动把cookie字符串放入headers字典中提交,二是把cookie字符串变成字典再由cookies参数提交,转换方法如下。

def cookie_to_dict(cookie):
    cookie_dict = {}
    items = cookie.split(';')
    for item in items:
        key = item.split('=')[0].replace(' ', '')
        value = item.split('=')[1]
        cookie_dict[key] = value
    return cookie_dict

这种直接获取的方法缺点也很明显,就是不能追踪set-cookie并更新,原来的cookie一旦失效,就要从新手动获取

session维持

session名为“会话”,即多个请求的行为。requests库提供了会话对象(requests.Session)让使用者能跨请求保持某些参数如cookie,而且能自动处理服务器发来的cookie,使得同一个会话中的请求都带上最新的cookie,非常适合模拟登录。使用上也非常简单,实例化后几乎相当于一个requests对象拥有get,post等方法,text,cotent等属性。为了方便下次登录,还可以把第一次session登录后的cookie通过cookiejar保存到本地供下次读取免去登录

import requests
import http.cookiejar as cj
r = requests.session()
r.cookies = cj.LWPCookieJar()  # 接入容器
r.get(url,headers=,cookie=) # 不过需要注意,就算使用了会话,方法级别的参数也不会被跨请求保持,此cookie只发送给该请求
print(r.text)
r.post(url,headers=,data=,)
#请求x N
r.cookies.save(filename='cookies.txt', ignore_discard=True, ignore_expires=True)  # 保存cookie到本地,忽略关闭浏览器丢失,忽略失效
r.close() # 对话支持with打开以实现自动close


'''#载入本地cookie
s = requests.session()
s.cookies = cj.LWPCookieJar(filename='cookies.txt')
s.cookies.load(filename='cookies.txt', ignore_discard=True)
'''

虽说session使cookie管理变得一劳永逸,但登录包中post参数的构造可能是一个深坑,post的是帐号密码明文那简单;蛋疼的是如果帐号密码连同其他数据经js加密成密文作为post数据,那你就得从js中挑选并分析加密算法,还要用python实现(某些加了混淆的js像天书一样)。如果无法破译加密,requests登录就是一张白纸,cookie就更不用谈了,给你再牛逼的管理工具也没用。同时对方程序员的勤奋程度也是一个考虑因素,别人经常改算法,你也要从新看js改代码。

-----------------------------看看人家知乎,加密到连名字都没有了,js还混淆,如何下手?-------------------------------
图片描述

综上,session适用于没有加密的登录或者加密算法比较简单并且不常更新的网站。遇上无解的加密算法?要么手操拷贝cookie,要么请selenium大佬出场。

selenium大法

大佬虽然是慢了点,但永远是你大佬。借助浏览器完备的js解析能力,你根本不用考虑它是如何加密的,只要输入账号密码,最多再加个验证码,浏览器直接运行js把他们直接变成密文并post过去,完成登录,就像我们平时操作那么简单。所以有一种巧妙的方法是先用selenium进行模拟登录,然后再提取cookie给session用免去session模拟登录的过程(当然也可以继续selenium下去)。在代码中,往往就是定位,点击,定位,发送帐号密码,Enter(或者定位点击登录键),等待一段时间让cookie加载完后将其打包成RequestsCookieJar给session用就可以了。如对付知乎可以这样做:

import requests
from selenium import webdriver
import time
from selenium.webdriver.common.keys import Keys

driver = webdriver.Chrome()
driver.maximize_window()
driver.get('https://www.zhihu.com/')
# 不考虑验证码的情况
driver.find_element_by_xpath('//button[@data-za-detail-view-id="2278"]').click() #点击登录进入登录界面
driver.find_element_by_xpath('//input[@name="username"]').send_keys('account') #发送帐号名
driver.find_element_by_xpath('//input[@name="password"]').send_keys('password',Keys.ENTER) #发送密码并回车
time.sleep(10) # 等待cookie加载完成
cookies = driver.get_cookies()
print(cookies)

s=requests.Session()
c = requests.cookies.RequestsCookieJar()
for item in cookies:
    c.set(item["name"],item["value"])
print(c)
s.cookies.update(c) # 载入cookie
#s.get()
#s.post()

'''
'''

但就算是大佬,也不是万能的,有些网站能识别人操作的浏览器和selenium操作的浏览器,使登录受到拒绝,譬如用selenium模拟登录网易云音乐就会提示登录异常。如果不能对js进行逆向工程分析出其识别算法,那只能放弃selenium走requests那条要分析加密的老路

后记

到系列第十篇文章,爬虫系列也将接近尾声,最后的内容是多线程,多进程及协程的介绍及使用。至于scrapy应该就不会讲了,半年前刚入爬虫坑学的,学得浅,现在忘得差不多了,如今又被深度学习带跑了,但不排除突然复活的可能。心急的小伙伴可以去观摩大佬们的代码自学。本人就去挖DeepLearning的坑了。

阅读 29.5k

推荐阅读

基于python3.X,主要使用requests进行自由定制,适合兴趣向的爬虫教学

63 人关注
11 篇文章
专栏主页