preface

Today is to bring you the hook net simulation login, let us happily start ~

The development tools

Python version: 3.6.4
Related modules:

Requests module;

And some modules that come with Python.

Environment set up

Install Python and add it to the environment variables. PIP installs the required related modules.

Introduction of the principle

Register an account for testing, and then open the login page:

Press F12 to open Chrome developer tools, and manually log in once so that we can capture packages. After the above operation, we can use the rule of thumb to search the login keyword globally and see if we can directly find the simulated login interface we need. After searching, we can find:

Obviously, this is the interface we are looking for to simulate a login request:

The following parameters are required to request this interface:

'isValidate'
'username'
'password'
'request_form_verifyCode'
'submit'
'challenge'
Copy the code

Among them, the fixed parameters were found to be:

'isValidate': 'true'
'username': Login user name in plain text'request_form_verifyCode': ' '
'submit': ' '
Copy the code

Request_form_verifyCode looks like it might be used to put a verification code, but you don’t usually need a verification code to log in to a dragnet. At least when I tried it, I didn’t get a verification code, even though I lost the proxy and switched computers for “remote login”. So I’m just going to ignore this thing, just think of it as a fixed constant. (The source code actually has a captcha situation, but that interface is a Google search, and it is many years ago, it seems that the hook network has been updated several waves since then, so reliability is questionable.)

Without further ado, we now only need to confirm the following two parameters:

'password'
'challenge'
Copy the code

“Password” is a password, but when capturing packets, we can see that this parameter is encrypted:

Check initiator to see how the password is calculated:

Obviously, the js file lgAjax seems to be the most relevant. If you search for the keyword password, you will find:

It is obvious that the password is encrypted by MD5 twice. Python code can easily implement this encryption as follows:

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

Line 6380 of the js file defines:

F = "veenike"
Copy the code

So we don’t need to make a breakpoint to determine this parameter.

Finally, let’s look at the challenge parameter. Let’s try a global search for the value of challenge.

bd89b07f5e4174c55a40557e109c9944
Copy the code

We can see that this value can be obtained by requesting the following API:

It’s obviously a polar API, but whatever it is, it’s a good idea to request this interface to get a dynamic challenge value. To request this interface, you only need to carry two fixed params:

pt: 0
gt: 66442f2f720bfc86799932d8ad2eb6c7
Copy the code

And a fixed data is ok:

(after test, found that the data will be changed, although every time but you always use the same data also doesn’t matter, even after many months still is that can be used effectively, should be visual captcha images related data, but since the same parameter can be used, they will take care of it, analysis is also a waste of time.)

To encapsulate this, write a function that takes the challenge argument:

Get the challenge parameter.
def __getChallenge(self) :
  params = {'pt': '0'.'gt': '66442f2f720bfc86799932d8ad2eb6c7'}
  data = 'nLYvtlnNYdUU68IXi84sdryl9ucQ2skF5u8LBLKXarWE41fPrzcL7yxmf2fYN2XDG1CyhqjVaXyi2Q)3oBs537a1dNTMv4w)U5b23FFwHcWMk(3gtb8VHP7 U0ltLOistf5IoI5Bt11GMavQSlQJ(ga)AsFh0wTLAC9yNwbdBfZExS0TT)Ojw010QuOFPQg2sj2jvTEER1LRMLHmQKR0KjWN)4Cq2o2WUzhwPy7sFFxJuCxU O)5377hbgo5tdjTOFHwgkUqZrY1lkmsPmexujXXIgpN9p2aa5OQ)iMRZ(p0zfuAnBYAEBOy6H6vSopUiWGeNg(IO(ppE7X0b6Zpul)GqoNs3nuVCdlamTyui 5qKhr8fyFSgzxiYWamJ5xR8PbvM9XQLEPZnxqvL(2P3nuRwa4S8qTzbMTwN3fw)KvEXUC2iatqz4G6ExOcfcUbQtRp7I1fEgjNb7Y8DEAZwmqyBG0qUVc3mo KM8KZrWLZxR14Wp8AaG3WzJ)s4z9ouViog8nAt1PI6xlPHWKazr7bH1mfpKYmz8z2k)TKYeQtG9XAjjWtab(dr5AsPjQk1njJmgAI(48Bh7pLzZwJIW93YAt ExbuCHGauxyEU28ZrKrqTjlgqu7KeurQU5hu(DhlIdMkmRqI(xguC8GjkYAlXF7aOjSvDwkxLUrLEE44CBe2gGNEFn6uax6HhvcUHIRMtIq0BB5Va4i)hnTK )WzcH2jetHMn4KVgFykF8NTKpWIkt(qIhiW)V1DNlfbmQi0ZmpUbLyOnLX42cjxwFh5Rnxrq(4WsPVm(Y8Oz0WtPaniTrAE6hFrdXS8PKyyefa49QcTFDJr9 nrCgv5bu1dg6m5jVvypdt7mKGRpy3DILQ)TZ0LX6OHBwl)4375P0X9QEXf6Dl4r9)0gNi(xSfT0FYLNJVzMfk)cNulnhOzjpDisiUu5oZHtAK0ue9BiFa40l wSXDmAHxm5DcCmkaK1eINzFTplJt9Gk5KcDxqJPCYhNX1gvXmLBpKRcgqXZmIWRU6nYmkF76WLImaEhN)HK4RYPiGCvUt3(23sAmuJoFyHEsmTLbq13KRWY0 tUbKhJjcPlOJUHduT1aSiWalhY0GTfhTiHfAu09zqENSHxVMAxtzi8FVSSZfPP82eIOyphvu(gukLDRaARVVAB4QFfgAxPSDWjRAT28IkMd1SiPug(fuJ9M6 1l2PzMiNxfZ6TXCtgUvmkOHgIybDYdPM6PB4ObXbV2wQf0q939Mkm8eVNsMvNPRZ0b1oJo0AnCz1IsxFn4JfCpB8M328wtH)7ve1jOBB4KulYQlXJuI3HUCJ oUU5I0V)xAZhRI)nX0cepkfkCMwOjKmIihoLXA3y2Z8p3r04s9NZc8ngBkdacFpqYtnR19EmDeMoKgay8PGQ)(zZf1hHhWXuZWXTXdyR)KDvRdlx9wjG2FhV 95QAH3aG85Dxufapym)b6kWJzKFw(qmsSpvUwUDhVQN2lfeUjR27eb2JZ0WP1GkQfG4LZ1CJYrBcfTx3zLD))kwiq3ScaVbT)B1GVfXqEP68zeLs9J)xwU7N gsI(QKtNw7WpymPl(g(FmDmxzrAMarwdqdoG2)KJRX5Qjz)ke8VnU8A09PVsdEwWKtkXjMUbvB)7Z3OFFOA(2EoKwthpb(mMyiUghjLD9(JXfqGm2k4RVF8v ATKIo7YGKgadiI5vwzs0EOdpChJVk5E7c3MMCiuUHm9axWXP0i0)PmW(ZxoiT0ZJvnyCCn60nwyjKHpp5nXnN2SKZS8WBliyhdc8RUqVRnZeh0pH27jiPUGX YkRiAuoKDzl8S6l3NWm6xPPQw1MbldzTqmMTUsOuoR5CBzlU)TJl2gCSRgE1j(ChpXGSUfUvuTwaGBFfKWyQWsWdSbcC2tSEF2WP4lSdgEntDioWtRFeGUNg 8tlnswrkfS6JhgE7BgfC36H(X1fytovT3vuTwilxGIt2xWuD9iY1Qxf9CtgSvo7vJTWmYneAQEyOUyqwcF5e6un(GCrMa7sizPHqf)gPseC2CeCQH9anwH7Z HiLiMRznWM(mH1CJEt52ez)IeiVTaDFpy1oYhURRwGoxMU2MkqIkw4LBR59MuKpBUdS6kZWcr(GwZ7VBLE3GAsX8ndtwoLAmeifdRQIonF7L1qozAKBU7lyJ M2oqYXs(7gLJZyIWmTXVskE8iAIXp)yRtajPfnTintzNxGHEKCyVZQrr0XBEvt3UtksAv9(1V2N8EBn7Hkb8VKw5u6BdFnc0dMQqgum(zQaTb(URg4(O9EmT XcQSpLTm4IRX(Pm)44ZYezGD(8BZoukh7Mhko6a1LizgNMdmizc)F9YBHLXXdwec1wK8OAnQcZt7rbVfIl6Vd3HqoQdcId8B)NiAT4YWhJM39jEYbgBVzBhu nEFV8DjTVSqudgf009qrFN(xrIo(EP5Wo6fYmTd7X4NMjElvOOm(2SV00ftg7d7(oUwkCHcEvQieQSZe(lmxeuIS0UMLAJ0nlyfFvrf0wr2oTKek1wu0)p17 viMriD8ONEOqY9bqsKZBhtiGxgzN3pTYlj3vYDMSbylh02H5iFn)efqRTD8s8amfw645BqAGI65uTRAeGLTTq6tAZex(Cfo4r21MQxKgkREGGhoky)3cKWA9 7jirImA.. 4f0ae6c11327e4367bff580c5b909a03039cf44f566fad8680886dd52987bd4956933bdd2376e53c282edd8a5b79e38d2d078bc9a1eb186462d24ed2 bc4cba3b2eda457b80a6dd8b1394e159b1a2d72d2f500a2b2703e372ade0e97fd741d75d6f401801e1022fd8772a463a15ce646ca0d00efe04500dfd dd33f46e037bdb20'
  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
Copy the code

At this point, we have the parameters we need to carry with the simulated login interface at the top of all requests:

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

Try asking:

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

Errors can be found:

If you look at the request header, you can find the following two parameters in the request header:

X-Anit-Forge-Token
X-Anit-Forge-Code
Copy the code

You can also search in the js file:

It seems that these two parameters are essential. A search for similar keywords reveals:

So we can ask directly:

https://passport.lagou.com/login/login.html
Copy the code

Then use the regular expression to extract it from the returned page:

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
Copy the code

Add these two parameters to the headers of the request interface:

login_headers.update(anit_forge)
Copy the code

You can see that the returned data becomes:

In the next article, I will share all of her (or his) tweets

All done~ Complete source code see personal profile or private letter to obtain relevant files.