分享

模拟登录

 昵称57252909 2018-06-28



2014/06/28修改

之前的写得实在太烂了, 所以重写了代码

流程:

1. 访问一次框架的源码(地址), 获取login_sig, appid, pt_version, mibao, pt_lang等参数;


2. 访问获取验证码的地址, 获取验证码(如果需要输入验证码, 则需要再访问其返回的获取验证码的地址, 通常不用验证码的话, 第二个参数就是验证码);


3. 根据QQ号, QQ密码, 验证码的值计算得出p的值(第一次登录需要用到, 计算方法在PSWEncrypt模块中);


4. 构建相关的Form, 并对地址(https://ssl.ptlogin2.qq.com/login)发送请求(必须使用Get方法, Post会出错),  登录成功后会返回一些参数, 例如二次登录需要访问的地址等, 其中ptwebqq在cookie中, 需要另外获取。。;


5. 访问一次第一次登录时返回的地址, 构建相关的Form(参数大多在之前已经得到了, 其中clientid参数在数字10000000-99999999中随便选一个就行了), 并向地址(http://d.web2.qq.com/channel/login2)发送请求, 登录成功后会返回相关的参数, 如uin, status, vfwebqq, psessionid等, 保存下来, 后面其他操作会用到的。


6.至此, webqq登录已经完成。


相关代码:

WebQQLogin.py

  1. #coding=utf-8
  2. import re;
  3. import json;
  4. import http;
  5. import urllib;
  6. import random;
  7. import http.cookiejar;
  8. import urllib.request;
  9. from urllib.parse import urlencode;
  10. from PSWEncrypt import PSWEncrypt;
  11. from Queryable import *;
  12. URL_LOGIN = "https://ssl.ptlogin2.qq.com/login?";
  13. URL_LOGIN2 = "http://d.web2.qq.com/channel/login2";
  14. #打开Chrome访问w.qq.com后右键查看框架源码就能看到这个了, 这个里面包含了登录时要用到的大部分信息
  15. URL_LOAD_INFO = "https://ui.ptlogin2.qq.com/cgi-bin/login?daid=164&target=self&style=16&mibao_css=m_webqq&appid=501004106&enable_qlogin=0&no_verifyimg=1&s_url=http%3A%2F%2Fw.qq.com%2Fproxy.html&f_url=loginerroralert&strong_login=1&login_state=10&t=20131024001";
  16. URL_VERYCODE = "https://ssl.ptlogin2.qq.com/check?";
  17. URL_VERYCODE_IMG = "https://ssl.captcha.qq.com/getimage?";
  18. webQQHeader = {
  19. "Host":"ui.ptlogin2.qq.com",
  20. "Referer":"http://w.qq.com/",
  21. "User-Agent":"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.1916.153 Safari/537.36",
  22. };
  23. #后面大多数模块都要用到这个header.....
  24. webQQHeader2 = {
  25. "Referer":"http://d.web2.qq.com/proxy.html?v=20130916001&callback=1&id=2",
  26. "User-Agent":"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36"
  27. }
  28. class WebQQLogin(Queryable):
  29. def __init__(self):
  30. #先保存一个clientid(8位), 第二次登录的时候要将这个id上传
  31. Queryable.__init__(self, {"clientid":str(random.randint(10000000, 99999999))});
  32. self._cookie = http.cookiejar.LWPCookieJar();
  33. self._opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(self._cookie));
  34. #多次正则, 感觉效率应该会很低, 但又没有更好的抓取办法
  35. def _readInfo(self, url):
  36. request = urllib.request.Request(URL_LOAD_INFO, headers = webQQHeader);
  37. ret = self._opener.open(request).read().decode("utf-8");
  38. login_sig = re.compile("g_login_sig=encodeURIComponent\(\"([^\"]+)\"\)").findall(ret)[0];
  39. appid = re.compile("g_appid =encodeURIComponent\(\"(\d+)\"\)").findall(ret)[0];
  40. pt_version = re.compile("g_pt_version=encodeURIComponent\(\"(\d+)\"\)").findall(ret)[0];
  41. mibao = re.compile("mibao_css=encodeURIComponent\(\"(\w+)\"\)").findall(ret)[0];
  42. pt_lang = re.compile("g_lang=\"([^\"]+)\"").findall(ret)[0];
  43. #open("1.txt", "wb").write(ret.encode("utf-8"));
  44. hiddenList = re.compile('<input\s+type="hidden"\s+name="([^\"]*)"\s+value="([^\"]*)"[^/]+/>').findall(ret);
  45. for item in hiddenList:
  46. self.setQuery(item[0], item[1]);
  47. self.setQueryEx({"login_sig":login_sig, "appid":appid, "js_ver":pt_version, "mibao":mibao, "pt_lang":pt_lang});
  48. def _requestVerifyCode(self, param):
  49. headerData = {
  50. "daid":self.queryInfo("daid"),
  51. "target":"self",
  52. "style":"16",
  53. "mibao_css":self.queryInfo("mibao"),
  54. "appid":self.queryInfo("appid"),
  55. "enable_qlogin":"0",
  56. "no_verifyimg":"1",
  57. "s_url":"http://w.qq.com/proxy.html",
  58. "f_url":"loginerroralert",
  59. "strong_login":"1",
  60. "login_state":"10",
  61. "t":"20131024001",
  62. };
  63. header = {
  64. "Host":"Host:ssl.captcha.qq.com",
  65. "Referer":"https://ui.ptlogin2.qq.com/cgi-bin/login?" + urlencode(headerData),
  66. "User-Agent":"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36",
  67. };
  68. data = {
  69. "aid":self.queryInfo("appid"),
  70. "r":"0.1642276826314628",
  71. "uin":self.queryInfo("uin"),
  72. };
  73. request = urllib.request.Request(URL_VERYCODE_IMG + urlencode(data), headers = header);
  74. open("verifyCode.jpg", "wb").write(self._opener.open(request).read());
  75. verifyCode = input("输入验证码:");
  76. return verifyCode;
  77. #虽然这个是获取验证码部分, 但一直都没碰到过验证码, 所以。。
  78. def _getVerycode(self, id):
  79. form = {"login_sig":self.queryInfo("login_sig"), "r":"0.3272944095078856", "js_type":"0", "appid":self.queryInfo("appid"), "js_ver":self.queryInfo("js_ver"), "u1":"http://w.qq.com/proxy.html", "uin":id};
  80. request = urllib.request.Request(URL_VERYCODE + urlencode(form));
  81. ret = self._opener.open(request).read().decode("utf-8");
  82. list = re.compile("ptui_checkVC\('(\d+)','([^\']*)','([^\']+)', '([^\']*)'\);").findall(ret)[0];
  83. if(list[0] == "0"):
  84. return list[1];
  85. else:
  86. return self._requestVerifyCode(list[1]);
  87. print(list);#debug
  88. return None;
  89. #第一次登录
  90. def _firstLogin(self, id, psw):
  91. verifycode = self._getVerycode(id);
  92. #大部分都用到了之前框架里面抓取到的东西, 避免硬编码(虽然还是有很多无法避免地用到了硬编码)
  93. form = {
  94. "u":id,
  95. "p":PSWEncrypt.encrypt(id, psw, verifycode),
  96. "verifycode":verifycode,
  97. "webqq_type":self.queryInfo("webqq_type"),
  98. "remember_uin":self.queryInfo("remember_uin"),
  99. "login2qq":self.queryInfo("login2qq"),
  100. "aid":self.queryInfo("appid"),
  101. "u1":"{0}?login2qq={1}&webqq_type={2}".format(self.queryInfo("u1"), self.queryInfo("login2qq"), self.queryInfo("webqq_type")),
  102. "h":self.queryInfo("h"),
  103. "ptredirect":self.queryInfo("ptredirect"),
  104. "ptlang":self.queryInfo("pt_lang"),
  105. "daid":self.queryInfo("daid"),
  106. "from_ui":self.queryInfo("from_ui"),
  107. "pttype":self.queryInfo("pttype"),
  108. "dumy":self.queryInfo("dumy"),
  109. "fp":self.queryInfo("fp"),
  110. "action":"0-23-34008",
  111. "mibao_css":self.queryInfo("mibao"),
  112. "t":"1",
  113. "g":"1",
  114. "js_type":"0",
  115. "js_ver":self.queryInfo("js_ver"),
  116. "login_sig":self.queryInfo("login_sig"),
  117. };
  118. #在这里用post方法的话。。会出错
  119. request = urllib.request.Request(URL_LOGIN + urlencode(form), headers = webQQHeader);
  120. ret = self._opener.open(request).read().decode("utf-8");
  121. #第一次登录完成, 保存返回的相关参数
  122. tuple = re.compile("ptuiCB\('([^\']*)',\s*'([^\']*)',\s*'([^\']*)',\s*'([^\']*)',\s*'([^\']*)',\s*'([^\']*)'\);").findall(ret)[0];
  123. if(tuple[0] == "0" and tuple[1] == "0"):
  124. self.setQuery("nick", tuple[-1]);
  125. self.setQuery("ptwebqq", re.compile("ptwebqq=([^\s]+)").findall(str(self._cookie))[0]);
  126. return tuple[2]; #这里会返回一个地址, 第二次登录的时候要先访问一次这个地址
  127. else:
  128. print(tuple);#debug
  129. return None;
  130. #第二次登录
  131. def _secLogin(self, url):
  132. #先访问一次第一次登录返回的那个地址
  133. self._opener.open(url);
  134. data = {"r":'{"ptwebqq":"' + self.queryInfo("ptwebqq") + '","clientid":' + self.queryInfo("clientid") + ',"psessionid":"","status":"online"}'};
  135. request = urllib.request.Request(URL_LOGIN2, headers = webQQHeader2);
  136. ret = json.loads(self._opener.open(request, urlencode(data).encode("utf-8")).read().decode("utf-8"));
  137. #retcode为0则第二次登录成功, 保存返回的相关参数
  138. if(ret["retcode"] == 0):
  139. result = ret["result"];
  140. self.setQuery("status", result["status"]);
  141. self.setQuery("vfwebqq", result["vfwebqq"]);
  142. self.setQuery("psessionid", result["psessionid"]);
  143. return True;
  144. else:
  145. print(ret); #debug
  146. return False;
  147. def login(self, id, psw):
  148. self.setQuery("uin", id);
  149. self._readInfo(URL_LOAD_INFO);
  150. secLoginAddr = self._firstLogin(id, psw);
  151. if(secLoginAddr == None):
  152. return None;
  153. if(not self._secLogin(secLoginAddr)):
  154. return None;
  155. self.setQuery("opener", self._opener);
  156. self.setQuery("header", webQQHeader2);
  157. #登录成功后将已经保存的所有参数信息返回
  158. return self.getDict();
  159. def main():
  160. qq = WebQQLogin();
  161. print(qq.login("397828451", "xxxx"));
  162. if(__name__ == "__main__"):
  163. main();




Queryable.py

  1. #coding=utf-8
  2. class Queryable:
  3. def __init__(self, dict):
  4. self.__dict = dict;
  5. def queryInfo(self, key):
  6. if(self.find(key)):
  7. return self.__dict[key];
  8. return None;
  9. def setQuery(self, key, value):
  10. self.__dict[key] = value;
  11. def setQueryEx(self, dict):
  12. self.__dict.update(dict);
  13. def find(self, key):
  14. if(key in self.__dict):
  15. return True;
  16. return False;
  17. def getDict(self):
  18. return self.__dict;

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多