Python模拟登录淘宝 详解怎样用Python模拟登录淘宝
猪哥66 人气:0看了下网上有很多关于模拟登录淘宝,但是基本都是使用scrapy、pyppeteer、selenium等库来模拟登录,但是目前我们还没有讲到这些库,只讲了requests库,那我们今天就来使用requests库模拟登录淘宝!
讲模拟登录淘宝之前,我们来回顾一下之前用requests库模拟登录豆瓣和新浪微博的过程:这一类模拟登录是比较简单的登录,只需要在请求登录时将用户名和密码上传验证通过就成功了,也就是说一步到位!
而淘宝登录就比较复杂,为什么说复杂呢?因为淘宝登录涉及参数多且请求不止一次!我们就先来讲讲淘宝登录的流程,先把流程原理搞懂,再去敲代码,这样大家就容易理解!
一、淘宝登录流程
淘宝ua参数:ua(User-Agent)故名用户代理,淘宝的ua参数加入了浏览器、ip、电脑、时间等信息,然后加密生成,在很多地方使用,不仅仅是登录!
上图是比较详细的流程图,从代码层面考虑将模拟登录淘宝分为以下四个步骤:
输入用户名后,浏览器会向淘宝(taobao.com)发起一个post的请求,判断是否出现滑块验证!
用户输入密码后,浏览器向淘宝(taobao.com)又发起一个post请求,验证用户名密码是否正确,如果正确则返回一个token。
浏览器拿着token去阿里巴巴(alibaba.com)交换st码!
浏览器获取st码之后,拿着st码获取cookies,登录成功
这里也许有同学会提出疑问:为什么淘宝(taobao.com)验证通过之后还要拿着 token去阿里巴巴(alibaba.com)交换st码呢? 这个我们放后面讲!
二、模拟登录实现
上面我们只讲了大概的登录流程,这里猪哥会先详细讲解下每一步的操作,然后再贴出实现代码!
1.判断是否需要验证码
目前我们在登录淘宝的时候,大多数情况下是不会出现滑块验证码,猪哥尝试了很多次的登录退出也只是在中间出现过一次,那究竟是什么在控制是否需要滑块验证码的呢?
从上图可以看出,当猪哥输入用户名(必须是手机号)后,浏览器就会发起一个post请求,来验证是否需要出现滑块验证码,如果返回true,滑块验证码则出现!否则不出现,一般是不会出现!
图中我们可以看到这次post请求上传了两个参数:username、ua!
前面猪哥说过ua为浏览器、ip、设备信息等多信息加密参数,所以猪哥猜想淘宝的验证码是否出现不仅仅从账号角度,还有ip、设备等角度!
举个例子:某台设备可能出现登录过大量的账号,这时候淘宝就可以从ua参数中获取设备号,然后对该设备进行限制!
2.验证用户名密码
这里一步也就是上面时序图图中的第5步:请求登录,这里会将用户名、ua参数、加密密码等30十几个参数post到淘宝(taobao.com)去验证。我们来用代码实现一下,大家别被这么多参数吓到,都是从浏览器复制过来的!
可以看到申请st码链接后面带了一个token,具体token是干什么用的后面我们再分析!
3.申请st码
上面我们已经申请到了淘宝(taobao.com)的token,这一步就是用token来换取st码。
到这里很多人可能会有疑问:为什么淘宝登录需要这么麻烦呢?直接在 taobao.com 登录不就可以吗?为什么要先在taobao验证用户名密码,通过之后再去 alibaba.com 换取st码登录呢?
任何公司的框架都是慢慢演变的结果,我想最开始的淘宝登录肯定没这么复杂。但是随着阿里巴巴的慢慢壮大,很多事业线都划分开来,但是这些事业线之间又有关联性,比如用户登录了淘宝账号之后天猫就不需要再登录了呢?(注意淘宝和天猫的顶级域名不同,所以不能共享cookis)为了解决这个问题,单点登录就出现了。
单点登录(Single Sign On),简称为 SSO,是目前比较流行的企业业务整合的解决方案之一。SSO的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。 ——百度百科
很多大企业几乎都有做单点登录,那阿里的单点登录系统肯定是由母公司阿里巴巴(alibaba.com)来做啦,所有子公司去调用母公司接口!
我们再回来分析淘宝登录为何要如此复杂就很好理解了:用户数据在淘宝这里,所以需要现在淘宝(taobao.com)验证用户名和密码,验证通过生成一个token,浏览器拿着token去和阿里巴巴(alibaba.com)申请单点登录码(st码),阿里巴巴收到请求验证token通过则返回st码,所以用token换st码的原因就在于单点登录!
理解了设计原理之后,代码实现起来就很清晰了!
4.使用st码登录
成功获取st码之后我们就可以来登录了,这一步是通过st码获取登录的cookies。
到这里我们就已经模拟登录淘宝成功了!
5.获取淘宝昵称
其实上面我们就已经登录淘宝成功并返回用户主页的链接,我们为了进一步验证登录成功,就请求一下淘宝用户主页,顺便把淘宝昵称提取出来吧!
三、总结
整体讲完之后我们来稍微总结一下吧,主要从代码结构和存在的问题两个方面说下:
1.代码结构
来放出一张代码结构图,让大家直观了解
这就是我们前面说过的模拟登录淘宝的四个步骤,不过这里我们是用代码实现了!
2.存在问题
在写这篇教程之前也是先在网上了解,然后自己用浏览器和抓包工具(Charles)一步一步实践,最重要的是你先要了解淘宝登录的大概流程,不然你实际操作起来会一头雾水,下面就要讲讲目前遇到的问题和存在的问题吧
首先第一个问题便是淘宝的滑块解锁,目前requests还没有很好的破解办法,后面介绍了一些爬虫框架之后我们再来破解吧!
猪哥尝试了很多次(50次以上)登录退出都没出现过滑块验证码。
网上有人使用代理ip,这里猪哥也没用,只要你不是超级超级超级频繁且大量爬取数据,一般大厂都不太会去封ip,因为有误伤率和影响用户面太广,也许一封就是整个小区。
在第二步验证用户名和密码时,上传了近30个参数,如果你把username、ua、加密密码复制进去验证还是不通过可尝试把那30个参数换成你浏览器中的!
在第三步和第四步偶尔会出现一次错误,重试一下就可以!
看到这里是不是感觉淘宝模拟登录就清晰明了很多了,感兴趣的同学可以收藏转发,周末有空自己尝试一下。征服淘宝登录,其他登录也就相对简单了!
下面是源码
# -*- coding:utf-8 -*- import re import os import json import requests s = requests.Session() # cookies序列化文件 COOKIES_FILE_PATH = 'taobao_login_cookies.txt' class UsernameLogin: def __init__(self, username, ua, TPL_password2): """ 账号登录对象 :param username: 用户名 :param ua: 淘宝的ua参数 :param TPL_password2: 加密后的密码 """ # 检测是否需要验证码的URL self.user_check_url = 'https://login.taobao.com/member/request_nick_check.do?_input_charset=utf-8' # 验证淘宝用户名密码URL self.verify_password_url = "https://login.taobao.com/member/login.jhtml" # 访问st码URL self.vst_url = 'https://login.taobao.com/member/vst.htm?st={}' # 淘宝个人 主页 self.my_taobao_url = 'https://i.taobao.com/my_taobao.htm' # 淘宝用户名 self.username = "手机号" # 淘宝关键参数,包含用户浏览器等一些信息,很多地方会使用,从浏览器或抓包工具中复制,可重复使用 self.ua = "" # 加密后的密码,从浏览器或抓包工具中复制,可重复使用 self.TPL_password2 = "" # 请求超时时间 self.timeout = 3 def _user_check(self): """ 检测账号是否需要验证码 :return: """ data = { 'username': self.username, 'ua': self.ua } try: response = s.post(self.user_check_url, data=data, timeout=self.timeout) response.raise_for_status() except Exception as e: print('检测是否需要验证码请求失败,原因:') raise e needcode = response.json()['needcode'] print('是否需要滑块验证:{}'.format(needcode)) return needcode def _verify_password(self): """ 验证用户名密码,并获取st码申请URL :return: 验证成功返回st码申请地址 """ verify_password_headers = { redirectURL=https%3A%2F%2Fi.taobao.com%2Fmy_taobao.htm%3Fspm%3Da2d00.7723416.754894437.1.61531fc917M0p9%26ad_id%3D%26am_id%3D%26cm_id%3D%26pm_id%3D1501036000a02c5c3739', # ':scheme': 'https', 'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3', 'accept-encoding': 'gzip, deflate, br', 'accept-language': 'zh-CN,zh;q=0.9', 'cache-control': 'max-age=0', 'content-length': '2858', 'content-type': 'application/x-www-form-urlencoded', 'sec-fetch-mode': 'navigate', 'sec-fetch-site': 'same-origin', 'sec-fetch-user': '?1', 'Cache-Control': 'max-age=0', 'Origin': 'https://login.taobao.com', 'Upgrade-Insecure-Requests': '1', 'User-Agent': '5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.70 Safari/537.36', 'Content-Type': 'application/x-www-form-urlencoded', 'Referer': 'https://login.taobao.com/member/login.jhtml?redirectURL=https%3A%2F%2Fi.taobao.com%2Fmy_taobao.htm%3Fspm%3Da2d00.7723416.754894437.1.61531fc917M0p9%26ad_id%3D%26am_id%3D%26cm_id%3D%26pm_id%3D1501036000a02c5c3739', } # 登录toabao.com提交的数据,如果登录失败,可以从浏览器复制你的form data verify_password_data = { 'TPL_username': self.username, 'ncoToken': '1f1389fac2a670101d8a09de4c99795e8023b341', 'slideCodeShow': 'false', 'useMobile': 'false', 'lang': 'zh_CN', 'loginsite': 0, 'newlogin': 0, 'TPL_redirect_url': 'https://i.taobao.com/my_taobao.htm?spm=a2d00.7723416.754894437.1.61531fc917M0p9&ad_id=&am_id=&cm_id=&pm_id=1501036000a02c5c3739', 'from': 'tb', 'fc': 'default', 'style': 'default', 'keyLogin': 'false', 'qrLogin': 'true', 'newMini': 'false', 'newMini2': 'false', 'loginType': '3', 'gvfdcname': '10', # 'gvfdcre': '68747470733A2F2F6C6F67696E2E74616F62616F2E636F6D2F6D656D6265722F6C6F676F75742E6A68746D6C3F73706D3D613231626F2E323031372E3735343839343433372E372E356166393131643970714B52693126663D746F70266F75743D7472756526726564697265637455524C3D68747470732533412532462532467777772E74616F62616F2E636F6D253246', 'TPL_password_2': self.TPL_password2, 'loginASR': '1', 'loginASRSuc': '1', 'oslanguage': 'zh-CN', 'sr': '1920*1080', # 'osVer': 'macos|10.145', 'naviVer': 'chrome|78.039047', 'osACN': 'Mozilla', 'osAV': '5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.70 Safari/537.36', 'osPF': 'Win32', 'appkey': '00000000', 'mobileLoginLink': 'https://login.taobao.com/member/login.jhtml?redirectURL=https://i.taobao.com/my_taobao.htm?spm=a2d00.7723416.754894437.1.61531fc917M0p9&ad_id=&am_id=&cm_id=&pm_id=1501036000a02c5c3739&useMobile=true', 'showAssistantLink': 'false', 'um_token': 'T274D86E0BEB4F2F2F527C889BADD92868CE10177BeFF895DE627CFE2D52A', 'ua': self.ua } try: response = s.post(self.verify_password_url, headers=verify_password_headers, data=verify_password_data, timeout=self.timeout) response.raise_for_status() # 从返回的页面中提取申请st码地址 except Exception as e: print('验证用户名和密码请求失败,原因:') raise e # 提取申请st码url apply_st_url_match = re.search(r'<script src="(.*?)"></script>', response.text) # 存在则返回 if apply_st_url_match: print('验证用户名密码成功,st码申请地址:{}'.format(apply_st_url_match.group(1))) return apply_st_url_match.group(1) else: raise RuntimeError('用户名密码验证失败!response:{}'.format(response.text)) def _apply_st(self): """ 申请st码 :return: st码 """ apply_st_url = self._verify_password() try: response = s.get(apply_st_url) # response.raise_for_status() except Exception as e: print('申请st码请求失败,原因:') raise e st_match = re.search(r'"data":{"st":"(.*?)"}', response.text) if st_match: print('获取st码成功,st码:{}'.format(st_match.group(1))) return st_match.group(1) else: raise RuntimeError('获取st码失败!response:{}'.format(response.text)) # raise RuntimeError('获取st码失败!') def login(self): """ 使用st码登录 :return: """ # 加载cookies文件 if self._load_cookies(): return True # 判断是否需要滑块验证 self._user_check() st = self._apply_st() headers = { 'Host': 'login.taobao.com', 'Connection': 'Keep-Alive', 'User-Agent': '5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.70 Safari/537.36' } try: response = s.get(self.vst_url.format(st), headers=headers) response.raise_for_status() except Exception as e: print('st码登录请求,原因:') raise e # 登录成功,提取跳转淘宝用户主页url my_taobao_match = re.search(r'top.location.href = "(.*?)"', response.text) if my_taobao_match: print('登录淘宝成功,跳转链接:{}'.format(my_taobao_match.group(1))) self._serialization_cookies() return True else: raise RuntimeError('登录失败!response:{}'.format(response.text)) def _load_cookies(self): # 1、判断cookies序列化文件是否存在 if not os.path.exists(COOKIES_FILE_PATH): return False # 2、加载cookies s.cookies = self._deserialization_cookies() # 3、判断cookies是否过期 try: self.get_taobao_nick_name() except Exception as e: os.remove(COOKIES_FILE_PATH) print('cookies过期,删除cookies文件!') return False print('加载淘宝登录cookies成功!!!') return True def _serialization_cookies(self): """ 序列化cookies :return: """ cookies_dict = requests.utils.dict_from_cookiejar(s.cookies) with open(COOKIES_FILE_PATH, 'w+', encoding='utf-8') as file: json.dump(cookies_dict, file) print('保存cookies文件成功!') def _deserialization_cookies(self): """ 反序列化cookies :return: """ with open(COOKIES_FILE_PATH, 'r+', encoding='utf-8') as file: cookies_dict = json.load(file) cookies = requests.utils.cookiejar_from_dict(cookies_dict) return cookies def get_taobao_nick_name(self): """ 获取淘宝昵称 :return: 淘宝昵称 """ headers = { 'User-Agent': '5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.70 Safari/537.36' } try: response = s.get(self.my_taobao_url, headers=headers) response.raise_for_status() except Exception as e: print('获取淘宝主页请求失败!原因:') raise e # 提取淘宝昵称 nick_name_match = re.search(r'<input id="mtb-nickname" type="hidden" value="(.*?)"/>', response.text) if nick_name_match: print('登录淘宝成功,你的用户名是:{}'.format(nick_name_match.group(1))) return nick_name_match.group(1) else: raise RuntimeError('获取淘宝昵称失败!response:{}'.format(response.text)) if __name__ == '__main__': # 淘宝用户名 username = '手机号' # 淘宝重要参数,从浏览器或抓包工具中复制,可重复使用 ua = '' # 加密后的密码,从浏览器或抓包工具中复制,可重复使用 TPL_password2 = '' ul = UsernameLogin(username, ua, TPL_password2) ul.login()
加载全部内容