天天看點

Python爬蟲實戰,requests子產品,Python模拟登入實作拉勾網資料解析

前言

今天給大家帶來的是拉勾網模拟登入,讓我們愉快地開始吧~

開發工具

** Python版本:**3.6.4

** 相關子產品:**

requests子產品;

以及一些python自帶的子產品。

環境搭建

安裝Python并添加到環境變量,pip安裝需要的相關子產品即可。

原理簡介

先去拉勾網注冊個賬号供測試使用,然後打開拉勾網登入頁面:

Python爬蟲實戰,requests子產品,Python模拟登入實作拉勾網資料解析

按F12打開Chrome浏覽器的開發者工具,并人工進行一次登入操作以便我們進行抓包。上面的操作結束之後,我們可以根據經驗,先全局搜尋一下login這個關鍵詞看看能不能直接找到我們需要的模拟登入接口。搜尋之後我們可以發現:

Python爬蟲實戰,requests子產品,Python模拟登入實作拉勾網資料解析

顯然,這就是我們想要找的模拟登入請求的接口:

Python爬蟲實戰,requests子產品,Python模拟登入實作拉勾網資料解析

請求該接口主要需要以下幾個參數:

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

其中,經測試後發現固定的參數為:

'isValidate': 'true'
'username': 登入使用者名明文
'request_form_verifyCode': ''
'submit': ''
           

request_form_verifyCode這個參數其實看着就像是用來放驗證碼的,但是拉勾網登入一般不需要輸入驗證碼,至少我試的時候一直沒有出現驗證碼,即使挂了代理換了電腦進行"異地登入"。是以這玩意就先不管啦,就當是個固定的常量吧。(源代碼裡其實加了有驗證碼情況的處理,但那個接口是谷歌上搜到的,而且是很多年前的,看樣子在那之後拉勾網應該又更新過好幾波了,是以可靠性存疑。)

言歸正傳,我們現在隻需要确定下面兩個參數了:

'password'
'challenge'
           

顯然password是密碼的意思,但是抓包的時候我們可以發現這個參數是經過加密處理的:

Python爬蟲實戰,requests子產品,Python模拟登入實作拉勾網資料解析

檢視一下initiator,看看密碼是咋算出來的:

Python爬蟲實戰,requests子產品,Python模拟登入實作拉勾網資料解析

顯然lgAjax那個js檔案看起來最相關,打開搜尋一下password這個關鍵詞,可以找到:

Python爬蟲實戰,requests子產品,Python模拟登入實作拉勾網資料解析

顯然就是對密碼明文做兩次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接口就可以獲得該值:

Python爬蟲實戰,requests子產品,Python模拟登入實作拉勾網資料解析

顯然是一個關于極驗的api接口,不過不管他到底是啥,反正通過請求這個接口來獲得一個動态的challenge值就對了。而請求這個接口隻需要攜帶兩個固定的params:

pt: 0
gt: 66442f2f720bfc86799932d8ad2eb6c7
           

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

Python爬蟲實戰,requests子產品,Python模拟登入實作拉勾網資料解析

(經過測試,發現雖然每次這個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)
           

可以發現報錯:

Python爬蟲實戰,requests子產品,Python模拟登入實作拉勾網資料解析

估計是請求頭出了問題,仔細觀察一下請求這個接口的請求頭,可以發現請求頭裡有以下兩個參數很可疑:

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

在js檔案裡也可以搜到:

Python爬蟲實戰,requests子產品,Python模拟登入實作拉勾網資料解析

看來這兩個參數是必不可少的。而搜尋一下類似的關鍵詞,發現:

Python爬蟲實戰,requests子產品,Python模拟登入實作拉勾網資料解析

于是我們可以直接請求:

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爬蟲實戰,requests子產品,Python模拟登入實作拉勾網資料解析

文章到這裡就結束了,感謝你的觀看,關注我每天分享Python模拟登入系列,下篇文章分享抓取微網誌實作資料可視化