Python爬虫实战,requests模块,Python模拟登录实现拉勾网数据解析


前言

今天给大家带来的是拉勾网模拟登录,让我们愉快地开始吧~

开发工具

** Python版本:**3.6.4

** 相关模块:**

requests模块;

以及一些python自带的模块。

环境搭建

安装Python并添加到环境变量,pip安装需要的相关模块即可。

原理简介

先去拉勾网注册个账号供测试使用,然后打开拉勾网登录页面:

按F12打开Chrome浏览器的开发者工具,并人工进行一次登录操作以便我们进行抓包。上面的操作结束之后,我们可以根据经验,先全局搜索一下login这个关键词看看能不能直接找到我们需要的模拟登录接口。搜索之后我们可以发现:

显然,这就是我们想要找的模拟登录请求的接口:

请求该接口主要需要以下几个参数:

'isValidate'
'username'
'password'
'request_form_verifyCode'
'submit'
'challenge'

其中,经测试后发现固定的参数为:

'isValidate': 'true'
'username': 登录用户名明文
'request_form_verifyCode': ''
'submit': ''

request_form_verifyCode这个参数其实看着就像是用来放验证码的,但是拉勾网登录一般不需要输入验证码,至少我试的时候一直没有出现验证码,即使挂了代理换了电脑进行"异地登录"。所以这玩意就先不管啦,就当是个固定的常量吧。(源代码里其实加了有验证码情况的处理,但那个接口是谷歌上搜到的,而且是很多年前的,看样子在那之后拉勾网应该又更新过好几波了,所以可靠性存疑。)

言归正传,我们现在只需要确定下面两个参数了:

'password'
'challenge'

显然password是密码的意思,但是抓包的时候我们可以发现这个参数是经过加密处理的:

查看一下initiator,看看密码是咋算出来的:

显然lgAjax那个js文件看起来最相关,打开搜索一下password这个关键词,可以找到:

显然就是对密码明文做两次md5加密,python代码可以很轻松地实现这个加密,具体实现如下:

password = hashlib.md5(password.encode('utf-8')).hexdigest()
password = 'veenike' + password + 'veenike'
password = hashlib.md5(password.encode('utf-8')).hexdigest()

其中我们可以看到js文件第6380行定义了:

F = "veenike"

所以我们就不需要通过打个断点来确定这个参数了。

最后再来看challenge这个参数,我们尝试全局搜索一下这个challenge的值,比如值为:

bd89b07f5e4174c55a40557e109c9944

我们可以发现请求下面这个api接口就可以获得该值:

显然是一个关于极验的api接口,不过不管他到底是啥,反正通过请求这个接口来获得一个动态的challenge值就对了。而请求这个接口只需要携带两个固定的params:

pt: 0
gt: 66442f2f720bfc86799932d8ad2eb6c7

以及一个可以固定的data就ok啦:

(经过测试,发现虽然每次这个data会变,但你一直用同一个data也无所谓,即使过了好多个月仍然是有效可以使用的,目测应该是验证码图片相关的数据,不过既然同一个参数一直可以用,就不用管它了,分析下去也是浪费时间。)

封装一下,写个获取challenge参数的函数,就是:

'''获得challenge参数'''
def __getChallenge(self):
  params = {'pt': '0', 'gt': '66442f2f720bfc86799932d8ad2eb6c7'}
  data = 'nLYvtlnNYdUU68IXi84sdryl9ucQ2skF5u8LBLKXarWE41fPrzcL7yxmf2fYN2XDG1CyhqjVaXyi2Q)3oBs537a1dNTMv4w)U5b23FFwHcWMk(3gtb8VHP7U0ltLOistf5IoI5Bt11GMavQSlQJ(ga)AsFh0wTLAC9yNwbdBfZExS0TT)Ojw010QuOFPQg2sj2jvTEER1LRMLHmQKR0KjWN)4Cq2o2WUzhwPy7sFFxJuCxUO)5377hbgo5tdjTOFHwgkUqZrY1lkmsPmexujXXIgpN9p2aa5OQ)iMRZ(p0zfuAnBYAEBOy6H6vSopUiWGeNg(IO(ppE7X0b6Zpul)GqoNs3nuVCdlamTyui5qKhr8fyFSgzxiYWamJ5xR8PbvM9XQLEPZnxqvL(2P3nuRwa4S8qTzbMTwN3fw)KvEXUC2iatqz4G6ExOcfcUbQtRp7I1fEgjNb7Y8DEAZwmqyBG0qUVc3moKM8KZrWLZxR14Wp8AaG3WzJ)s4z9ouViog8nAt1PI6xlPHWKazr7bH1mfpKYmz8z2k)TKYeQtG9XAjjWtab(dr5AsPjQk1njJmgAI(48Bh7pLzZwJIW93YAtExbuCHGauxyEU28ZrKrqTjlgqu7KeurQU5hu(DhlIdMkmRqI(xguC8GjkYAlXF7aOjSvDwkxLUrLEE44CBe2gGNEFn6uax6HhvcUHIRMtIq0BB5Va4i)hnTK)WzcH2jetHMn4KVgFykF8NTKpWIkt(qIhiW)V1DNlfbmQi0ZmpUbLyOnLX42cjxwFh5Rnxrq(4WsPVm(Y8Oz0WtPaniTrAE6hFrdXS8PKyyefa49QcTFDJr9nrCgv5bu1dg6m5jVvypdt7mKGRpy3DILQ)TZ0LX6OHBwl)4375P0X9QEXf6Dl4r9)0gNi(xSfT0FYLNJVzMfk)cNulnhOzjpDisiUu5oZHtAK0ue9BiFa40lwSXDmAHxm5DcCmkaK1eINzFTplJt9Gk5KcDxqJPCYhNX1gvXmLBpKRcgqXZmIWRU6nYmkF76WLImaEhN)HK4RYPiGCvUt3(23sAmuJoFyHEsmTLbq13KRWY0tUbKhJjcPlOJUHduT1aSiWalhY0GTfhTiHfAu09zqENSHxVMAxtzi8FVSSZfPP82eIOyphvu(gukLDRaARVVAB4QFfgAxPSDWjRAT28IkMd1SiPug(fuJ9M61l2PzMiNxfZ6TXCtgUvmkOHgIybDYdPM6PB4ObXbV2wQf0q939Mkm8eVNsMvNPRZ0b1oJo0AnCz1IsxFn4JfCpB8M328wtH)7ve1jOBB4KulYQlXJuI3HUCJoUU5I0V)xAZhRI)nX0cepkfkCMwOjKmIihoLXA3y2Z8p3r04s9NZc8ngBkdacFpqYtnR19EmDeMoKgay8PGQ)(zZf1hHhWXuZWXTXdyR)KDvRdlx9wjG2FhV95QAH3aG85Dxufapym)b6kWJzKFw(qmsSpvUwUDhVQN2lfeUjR27eb2JZ0WP1GkQfG4LZ1CJYrBcfTx3zLD))kwiq3ScaVbT)B1GVfXqEP68zeLs9J)xwU7NgsI(QKtNw7WpymPl(g(FmDmxzrAMarwdqdoG2)KJRX5Qjz)ke8VnU8A09PVsdEwWKtkXjMUbvB)7Z3OFFOA(2EoKwthpb(mMyiUghjLD9(JXfqGm2k4RVF8vATKIo7YGKgadiI5vwzs0EOdpChJVk5E7c3MMCiuUHm9axWXP0i0)PmW(ZxoiT0ZJvnyCCn60nwyjKHpp5nXnN2SKZS8WBliyhdc8RUqVRnZeh0pH27jiPUGXYkRiAuoKDzl8S6l3NWm6xPPQw1MbldzTqmMTUsOuoR5CBzlU)TJl2gCSRgE1j(ChpXGSUfUvuTwaGBFfKWyQWsWdSbcC2tSEF2WP4lSdgEntDioWtRFeGUNg8tlnswrkfS6JhgE7BgfC36H(X1fytovT3vuTwilxGIt2xWuD9iY1Qxf9CtgSvo7vJTWmYneAQEyOUyqwcF5e6un(GCrMa7sizPHqf)gPseC2CeCQH9anwH7ZHiLiMRznWM(mH1CJEt52ez)IeiVTaDFpy1oYhURRwGoxMU2MkqIkw4LBR59MuKpBUdS6kZWcr(GwZ7VBLE3GAsX8ndtwoLAmeifdRQIonF7L1qozAKBU7lyJM2oqYXs(7gLJZyIWmTXVskE8iAIXp)yRtajPfnTintzNxGHEKCyVZQrr0XBEvt3UtksAv9(1V2N8EBn7Hkb8VKw5u6BdFnc0dMQqgum(zQaTb(URg4(O9EmTXcQSpLTm4IRX(Pm)44ZYezGD(8BZoukh7Mhko6a1LizgNMdmizc)F9YBHLXXdwec1wK8OAnQcZt7rbVfIl6Vd3HqoQdcId8B)NiAT4YWhJM39jEYbgBVzBhunEFV8DjTVSqudgf009qrFN(xrIo(EP5Wo6fYmTd7X4NMjElvOOm(2SV00ftg7d7(oUwkCHcEvQieQSZe(lmxeuIS0UMLAJ0nlyfFvrf0wr2oTKek1wu0)p17viMriD8ONEOqY9bqsKZBhtiGxgzN3pTYlj3vYDMSbylh02H5iFn)efqRTD8s8amfw645BqAGI65uTRAeGLTTq6tAZex(Cfo4r21MQxKgkREGGhoky)3cKWA97jirImA..4f0ae6c11327e4367bff580c5b909a03039cf44f566fad8680886dd52987bd4956933bdd2376e53c282edd8a5b79e38d2d078bc9a1eb186462d24ed2bc4cba3b2eda457b80a6dd8b1394e159b1a2d72d2f500a2b2703e372ade0e97fd741d75d6f401801e1022fd8772a463a15ce646ca0d00efe04500dfddd33f46e037bdb20'
  res = requests.post(self.challenge_url, data=data, params=params)
  res_json = res.json()
  if res_json['status'] == 'success':
    challenge = res_json.get('challenge')
  else:
    raise RuntimeError('Get the param named challenge error, error info is %s...' % res_json.get('error'))
  return challenge

至此,我们获得了所有请求最上面那个模拟登录接口所需携带的参数:

data = {
              'isValidate': 'true',
              'username': username,
              'password': password,
              'request_form_verifyCode': '',
              'submit': '',
              'challenge': self.__getChallenge()
            }

试着请求一下:

self.login_url = 'https://passport.lagou.com/login/login.json'
self.session.post(self.login_url, data=data, headers=login_headers)

可以发现报错:

估计是请求头出了问题,仔细观察一下请求这个接口的请求头,可以发现请求头里有以下两个参数很可疑:

X-Anit-Forge-Token
X-Anit-Forge-Code

在js文件里也可以搜到:

看来这两个参数是必不可少的。而搜索一下类似的关键词,发现:

于是我们可以直接请求:

https://passport.lagou.com/login/login.html

然后在返回的页面里用正则表达式提取就ok了:

def __getAnitForge(self):
  res = self.session.get(self.home_url, headers=self.headers)
  token = re.findall(r"window.X_Anti_Forge_Token = '(.*?)';", res.text)[0]
  code = re.findall(r"window.X_Anti_Forge_Code = '(.*?)';", res.text)[0]
  anit_forge = {
            'X-Anit-Forge-Code': code,
            'X-Anit-Forge-Token': token
          }
  return anit_forge

在请求登录接口的headers里添加一下这两个参数:

login_headers.update(anit_forge)

可以发现返回的数据变成了:

文章到这里就结束了,感谢你的观看,关注我每天分享Python模拟登录系列,下篇文章分享抓取微博实现数据可视化