Python Selenium淘宝自动登录(最新版),无意间发现淘宝登陆漏洞?

一、前言

之前写过一篇爬取淘宝商品信息的博客----<<传送门,当时还是新手,急于完成爬取目标,干脆手动登陆淘宝使浏览器保存我的信息,然后使用本地用户配置控制浏览器,投机取巧地解决了登陆问题。虽然这不失为一种方法,但这却让selenium的“全自动”变成了“半自动”,不配Python之美。

那么如何“全自动”登陆淘宝呢?起初我是在互联网上找一些资源项目,直接拿来分析,但随着淘宝的反爬机制的增强,他们的这些方法都行不通了。于是我决定,自己动手!

二、分析

为了方便使用,把代码进行了封装)文件名为login,类名为Login

(1)相关依赖

from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.common.keys import Keys
from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By
from selenium import webdriver
import time

(2)构造函数

    def __init__(self, username, password):
        """
        初始化浏览器配置和登陆信息
        """
        self.url = 'https://login.taobao.com/member/login.jhtml'
        # 初始化浏览器选项
        options = webdriver.ChromeOptions()
        # 禁止加载图片
        options.add_experimental_option("prefs", {"profile.managed_default_content_settings.images": 2})
        # 设置为开发者模式
        options.add_experimental_option('excludeSwitches', ['enable-automation'])
        # 加载浏览器选项
        self.browser = webdriver.Chrome(options=options)
        # 设置显式等待时间40s
        self.wait = WebDriverWait(self.browser, 40)
        self.username = username  # 用户名
        self.password = password  # 密码

(3)原始登陆,使用淘宝账号或手机号登陆

    def original(self):
        """
        直接使用淘宝账号登陆

        :return: None
        """
        self.browser.get(url=self.url)
        try:
            input_username = self.wait.until(EC.presence_of_element_located((
                By.CSS_SELECTOR, 'div.fm-field > div.input-plain-wrap.input-wrap-loginid > input'
            )))
            input_password = self.wait.until(EC.presence_of_element_located((
                By.CSS_SELECTOR, 'div.fm-field > div.input-plain-wrap.input-wrap-password > input'
            )))
            # 等待滑块按钮加载
            div = self.wait.until(EC.presence_of_element_located((
                By.ID, 'nc_1__bg'
            )))
            input_username.send_keys(self.username)
            input_password.send_keys(self.password)
            # 休眠2s,等待滑块按钮加载
            time.sleep(2)
            # 点击并按住滑块
            ActionChains(self.browser).click_and_hold(div).perform()
            # 移动滑块
            ActionChains(self.browser).move_by_offset(xoffset=300, yoffset=0).perform()
            # 等待验证通过
            self.wait.until(EC.text_to_be_present_in_element((
                By.CSS_SELECTOR, 'div#nc_1__scale_text > span.nc-lang-cnt > b'), '验证通过'
            ))
            # 登陆
            input_password.send_keys(Keys.ENTER)
            print('Successful !')
        except TimeoutException as e:
            print('Error:', e.args)
            self.original()

其它的结点元素的定位我就不多说了,主要说一下滑块的定位
在这里插入图片描述

利用浏览器定位的话,会定位到 span 这个结点,但经过我模仿单击按住,拖拽后滑块一动不动,参数也没有任何改变。于是我尝试了一下它的父节点 div 还是按住后拖拽,这次成功了。所以有时候不要怀疑自己的代码,有可能是其它方面的问题。

还有关于拖拽还要说明一下,淘宝的登陆验证不是极验验证码,不是拖动滑块拼图的操作,而是将滑块拖到最右端。所以,至于这个最右端,只要距离够长,且不超出界面范围,长度随便定!

最后补充一下,偶尔会出现这种情况
在这里插入图片描述得到这张图也是很不容易啊,因为这种情况真的是太少了。经过反复实验,大概是因为滑动的轨迹不是基本水平导致的,就是说朝着斜下方滑动,虽然也能到达最右端,但会给出这个错误。我的程序是让它水平方向滑动300,竖直方向坐标为0。虽然是水平滑动,但是为了提高程序的容错率,还是加上了一个验证通过的等待。

(3)使用新浪微博账号登陆,巧妙利用漏洞

提示:在用新浪微博登陆之前,请在淘宝上绑定你的新浪账号

    def sina(self):
        """
        使用新浪微博账号登陆(提前绑定新浪账号)

        :return: None
        """
        self.browser.get(url=self.url)
        try:
            # 等待新浪登陆链接加载
            weibo_login = self.wait.until(EC.element_to_be_clickable((
                By.CSS_SELECTOR, '#login-form a.weibo-login'
            )))
            weibo_login.click()
            input_username = self.wait.until(EC.presence_of_element_located((
                By.CSS_SELECTOR, 'div.info_list > div.inp.username > input.W_input'
            )))
            input_password = self.wait.until(EC.presence_of_element_located((
                By.CSS_SELECTOR, 'div.info_list > div.inp.password > input.W_input'
            )))
            input_username.send_keys(self.username)
            input_password.send_keys(self.password)
            input_password.send_keys(Keys.ENTER)
            # 等待浏览器保存我方信息,网速不好可以设置长一点
            time.sleep(5)
            # 刷新页面
            self.browser.refresh()
            # 等待快速登陆按钮加载
            quick_login = self.wait.until(EC.element_to_be_clickable((
                By.CSS_SELECTOR, 'div.info_list > div.btn_tip > a.W_btn_g'
            )))
            quick_login.click()
            print('login successful !')
        except TimeoutException as e:
            print('Error:', e.args)
            self.sina()

关于结点元素的定位我就不多说了,主要说一下这个漏洞

正常情况下,输入完信息后点击登录,就该进入淘宝页面了,但是这个登陆按钮不管怎么点,页面都是无动于衷。

定位一下发现
在这里插入图片描述这个按钮的链接是javascript:void(0),假链接!!!

由于我的前端基础不好,不知道这啥意思。我疯狂的在互联网上查找如何使用selenium点击这种链接,可依旧没找到解决的办法,有没有人知道如何处理这种,请留言!

然而就在我快放弃的时候,按了下F5刷新,奇迹的事情出现了!
在这里插入图片描述检测到已登录的微博账号,快速登陆???原来虽然我没有进入淘宝,但是浏览器左下角一直在显示如:等待**相应,正在解析主机等信息。所以淘宝还是保存了我的账号信息,只要下次自动登录的勾打上(默认打勾),它就会保存账号信息。

这就是为什么上面的代码,在输入好信息并回车登陆后,要等待5秒,就是让它保存我的账号信息。

最后刷新页面,点击快速登陆,大功告成!

三、完整代码及使用方法

完整代码

# -*- coding: utf-8 -*-
"""
@author:Pineapple

@contact:[email protected]

@time:2020/7/28 9:09

@file:login.py

@desc: login taobao .
"""

from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.common.keys import Keys
from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By
from selenium import webdriver
import time


class Login:
    def __init__(self, username, password):
        """
        初始化浏览器配置和登陆信息
        """
        self.url = 'https://login.taobao.com/member/login.jhtml'
        # 初始化浏览器选项
        options = webdriver.ChromeOptions()
        # 禁止加载图片
        options.add_experimental_option("prefs", {"profile.managed_default_content_settings.images": 2})
        # 设置为开发者模式
        options.add_experimental_option('excludeSwitches', ['enable-automation'])
        # 加载浏览器选项
        self.browser = webdriver.Chrome(options=options)
        # 设置显式等待时间40s
        self.wait = WebDriverWait(self.browser, 40)
        self.username = username  # 用户名
        self.password = password  # 密码

    def original(self):
        """
        直接使用淘宝账号登陆

        :return: None
        """
        self.browser.get(url=self.url)
        try:
            input_username = self.wait.until(EC.presence_of_element_located((
                By.CSS_SELECTOR, 'div.fm-field > div.input-plain-wrap.input-wrap-loginid > input'
            )))
            input_password = self.wait.until(EC.presence_of_element_located((
                By.CSS_SELECTOR, 'div.fm-field > div.input-plain-wrap.input-wrap-password > input'
            )))
            # 等待滑块按钮加载
            div = self.wait.until(EC.presence_of_element_located((
                By.ID, 'nc_1__bg'
            )))
            input_username.send_keys(self.username)
            input_password.send_keys(self.password)
            # 休眠2s,等待滑块按钮加载
            time.sleep(2)
            # 点击并按住滑块
            ActionChains(self.browser).click_and_hold(div).perform()
            # 移动滑块
            ActionChains(self.browser).move_by_offset(xoffset=300, yoffset=0).perform()
            # 等待验证通过
            self.wait.until(EC.text_to_be_present_in_element((
                By.CSS_SELECTOR, 'div#nc_1__scale_text > span.nc-lang-cnt > b'), '验证通过'
            ))
            # 登陆
            input_password.send_keys(Keys.ENTER)
            print('Successful !')
        except TimeoutException as e:
            print('Error:', e.args)
            self.original()

    def sina(self):
        """
        使用新浪微博账号登陆(提前绑定新浪账号)

        :return: None
        """
        self.browser.get(url=self.url)
        try:
            # 等待新浪登陆链接加载
            weibo_login = self.wait.until(EC.element_to_be_clickable((
                By.CSS_SELECTOR, '#login-form a.weibo-login'
            )))
            weibo_login.click()
            input_username = self.wait.until(EC.presence_of_element_located((
                By.CSS_SELECTOR, 'div.info_list > div.inp.username > input.W_input'
            )))
            input_password = self.wait.until(EC.presence_of_element_located((
                By.CSS_SELECTOR, 'div.info_list > div.inp.password > input.W_input'
            )))
            input_username.send_keys(self.username)
            input_password.send_keys(self.password)
            input_password.send_keys(Keys.ENTER)
            # 等待浏览器保存我方信息,网速不好可以设置长一点
            time.sleep(5)
            # 刷新页面
            self.browser.refresh()
            # 等待快速登陆按钮加载
            quick_login = self.wait.until(EC.element_to_be_clickable((
                By.CSS_SELECTOR, 'div.info_list > div.btn_tip > a.W_btn_g'
            )))
            quick_login.click()
            print('login successful !')
        except TimeoutException as e:
            print('Error:', e.args)
            self.sina()

如何使用

在使用的时候要导入这个Login类,然后初始化这个类,最后登陆方法使用相应的函数,比如:
文件名为login,类名为Login

from login import Login

username = '******'  # 账号
password = '******.'  # 密码
# 初始化Login类
login = Login(username, password)
# 使用淘宝账号或手机号登陆
login.original()
# 使用新浪微博账号登陆
# login.sina()

小插曲:

如果你用的是PyCarm,可能会出现如下问题:

在这里插入图片描述虽然不妨碍运行,但是身为强迫症患者,怎么可能容忍波浪线的存在!

解决方法:右击文件夹,点击Sources Root,将文件夹设置为根目录。
在这里插入图片描述

如果用的是VS code,在导入的时候并不会出现上面的问题,但是你会发现突然多了一个文件夹,并且里面还有一个.pyc文件:

在这里插入图片描述不要慌,有这个才是正常的现象!

文件名:login.cpython-38.pyc。login代表导入的文件名,cpython指的是我们使用的python解释器,38代表python版本,pyc是python字节码文件的后缀。

python文件在运行的时候,Python解释器将源码转换为字节码,然后再由解释器来执行这些字节码。

在导入模块的时候,python将该模块的字节码文件保存在当前文件夹下,后续再次运行直接,若模块没有被改动,就直接执行字节码文件,这样就缩短了程序运行的时间。

四、结语

本篇说的是淘宝自动登陆,其实还是用了很多投机取巧的方法,比如:拖动滑块的位置没有确定,没有解决javascript:void(0)假链接的问题。若是淘宝加强了反爬机制,使用极验验证码等,这个标题里的“最新版”,可能也要被淘汰了,所以还是要接着解决极验验证码啊,以备后续跟新!

如有错误,欢迎私信纠正!
技术永无止境,谢谢支持!

代码修改记录1


  1. line:89,107。方法不严谨。
    将等待条件presence_of_element_located替换为element_to_be_clickable ↩︎

猜你喜欢

转载自blog.csdn.net/pineapple_C/article/details/107641799