Python3 网络爬虫(六):618,爱他/她,就清空他/她的购物车!

Python3 网络爬虫(六):618,爱他/她,就清空他/她的购物车!

本文 GitHub https://github.com/Jack-Cherish/PythonPark 已收录,有技术干货文章,整理的学习资料,一线大厂面试经验分享等,欢迎 Star 和 完善。css

1、前言

爬虫系列,已讲 5 篇。html

文字、图片、视频这类常规的内容下载、API 的使用,这些操做对你来讲,应该垂手可得了。python

那今天,就讲解一下高级一点的技能,「模拟登陆」。git

值此 618 之际,帮他/她清空一波购物车!github

2、模拟登陆

学爬虫,总能听到「模拟登陆」这四个字,究竟什么是「模拟登陆」?web

通俗一点讲,「模拟登陆」就是程序用帐号和密码自动登陆一个网站。面试

而后,拿到只有登陆后,才能下载的网站数据。算法

好比,咱们只有登陆淘宝帐号以后,才能看到购物车里有哪些东西。chrome

本文,就以「模拟登陆」淘宝为例进行讲解,并帮他/她清空购物车。浏览器

你只须要知道他/她的淘宝帐号和密码,而且有个充足的钱包,就能够运行程序,扫码支付一鼓作气。

体验自动结算钱包秒空的快感!

3、Selenium

模拟登陆无非两种方法:请求包分析模拟登陆、自动化测试工具模拟登陆。

前者,须要抓包分析请求,解析各类参数,还可能涉及一些加密算法。

后者,能够绕过一些繁琐的分析过程,直接定位元素进行操做,但也会遇到一些反爬策略。

二者,都有各自的操做技巧。

以前的教程,讲解了不少基于 requests 请求包分析的爬虫思路。

本文讲解一个新思路,使用自动化测试工具 Selenium 模拟登陆。

Selenium 基本的使用方法,以及如何破解淘宝对于 Selenium 的反爬策略,尽在下文。​

一、Selenium 安装

Selenium 是一个自动化测试工具,支持各类主流浏览器,例如 Chrome、Safari、Firefox 等。

不知道什么是自动化测试工具不要紧,我会经过实战操做,慢慢讲解。

无论怎样,先安装 Selenium 再说。

pip install selenium

使用 pip 直接安装 selenium

除了安装 Python 的 Selenium 第三方库,还须要根据浏览器配置相应的浏览器驱动。

以 Chrome 为例,下载浏览器驱动。

驱动下载地址(需翻墙):点击查看

须要根据浏览器的版本,选择驱动下载。

Python3 网络爬虫(六):618,爱他/她,就清空他/她的购物车!

没法翻墙下载不要紧,我已经将这三个版本的驱动下载并上传到百度云了。

百度云连接:https://pan.baidu.com/s/1-AfONQGkK8xPwLaW5P-9Bw

提取码:cbsu

二、小试牛刀

使用 Selenium 登陆百度看一下。

from selenium import webdriver

if __name__ == "__main__":
    browser = webdriver.Chrome('path\to\your\chromedriver.exe')
    browser.get('https://www.baidu.com/')

上面的 path\to\your\chromedriver.exe 是刚刚下载的 Chrome 驱动文件位置,根据本身的状况修改,建议使用绝对路径。结果以下图所示:

程序会自动打开 Chrome 浏览器,并打开 www.baidu.com。

再来个复杂一些的例子。

from selenium import webdriver
from selenium.webdriver.common.keys import Keys

if __name__ == "__main__":
    driver = webdriver.Chrome("path\to\your\chromedriver.exe")
    driver.get("https://www.python.org")
    assert "Python" in driver.title
    elem = driver.find_element_by_name("q")
    elem.send_keys("pycon")
    elem.send_keys(Keys.RETURN)
    print(driver.page_source)

打开 www.python.org 官网,并根据 name 属性为 q 找到搜索框,并输入 pycon 并点击搜索。

运行结果:

写好程序,浏览器自动操做,是否是很简单,很酷炫?

这就是自动化测试工具,程序写好,浏览器自动执行你的写的操做。

find_element_by_* 是一种定位网页元素的方法,有不少方式:

find_element_by_id
find_element_by_name
find_element_by_xpath
find_element_by_link_text
find_element_by_partial_link_text
find_element_by_tag_name
find_element_by_class_name
find_element_by_css_selector

能够经过,标签的 id 属性、name 属性、class_name 属性查找元素,也能够经过 xpath 等。

这里面,其实用到最多的就是 xpath,由于好用。

不用动脑思考怎么写 xpath,就能操做,方便好用。举个例子,好比我想找到 baidu.com 的搜索框的元素:

 

在搜索框位置,点击右键,选择 copy 下的 copy xpath,直接复制 xpath 。

粘贴出来你会看到以下内容:

//*[@id="kw"]

其实意思就是从根目录开始找,找到 id 属性为 kw 的标签。

定位到搜索框,就能够经过百度输入 Jack Cui,搜索个人相关内容。

from selenium import webdriver
from selenium.webdriver.common.keys import Keys

if __name__ == "__main__":
    driver = webdriver.Chrome("path\to\your\chromedriver.exe")
    driver.get("https://www.baidu.com")
    elem = driver.find_element_by_xpath('//*[@id="kw"]')
    elem.send_keys("Jack Cui")
    elem.send_keys(Keys.RETURN)

运行结果:

能够看到,运行程序,搜索 Jack Cui,能搜到个人我的网站、CSDN 和知乎等。

Selenium 就是这么简单省事。

若是想学习更多,关于 Selenuim 其余的基本方法和 Xpath 的基础知识,能够看下我 3 年前写的文章。

文章地址:点击查看

详细的,关于 Selenium 的 API 文档,能够看官方手册。

官方手册:点击查看

好了,基础知识准备完毕。

只要你会使用 copy xpath,基本的 Selenium 操做,就能够开始跟我一块儿「模拟登陆」淘宝。

4、登陆淘宝,掏空钱包

这场为了爱情的清空购物车大做战,须要分两步完成:

  • 模拟登陆淘宝
  • 购物车结算

一、模拟登陆淘宝

用 Selenium 模拟登陆,就边看边写,按照人的操做步骤写代码便可。

打开淘宝,上来第一步确定是点击登陆按钮,不会写 XPath,那就复制这个标签的 XPath。

所以点击登陆的代码就是:

browser.find_element_by_xpath('//*[@id="J_SiteNavLogin"]/div[1]/div[1]/a[1]').click()

找到登陆元素位置,而后 click() 点击。

点击登陆后,进入登录页面,找到帐号框和密码框位置,并输入帐号和密码。

仍是简单粗暴的复制粘贴 XPath 便可。

browser.find_element_by_xpath('//*[@id="fm-login-id"]').send_keys(username)
browser.find_element_by_xpath('//*[@id="fm-login-password"]').send_keys(password)

username 和 password 就是你要输入的帐号和密码。

输入完密码以后,可能会出现一个验证码滑动窗口。

这种滑动窗口也好解决,仍是复制 XPath 匹配元素,而后使用 Selenium 的 ActionChains 方法,拖动滑块。

最后点击登录按钮

登录后,再读取下用户名,看下是否登录成功便可。

分析完毕,直接上代码。

from selenium import webdriver
import logging
import time
from selenium.common.exceptions import NoSuchElementException, WebDriverException
from retrying import retry
from selenium.webdriver import ActionChains

logging.basicConfig(level = logging.INFO,format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

class taobao():
    def __init__(self):
        self.browser = webdriver.Chrome("path\to\your\chromedriver.exe")
        # 最大化窗口
        self.browser.maximize_window()
        self.browser.implicitly_wait(5)
        self.domain = 'http://www.taobao.com'
        self.action_chains = ActionChains(self.browser)

    def login(self, username, password):
        while True:
            self.browser.get(self.domain)
            time.sleep(1)
            
            #会xpath能够简化这几步
            #self.browser.find_element_by_class_name('h').click()
            #self.browser.find_element_by_id('fm-login-id').send_keys(username)
            #self.browser.find_element_by_id('fm-login-password').send_keys(password)
            self.browser.find_element_by_xpath('//*[@id="J_SiteNavLogin"]/div[1]/div[1]/a[1]').click()
            self.browser.find_element_by_xpath('//*[@id="fm-login-id"]').send_keys(username)
            self.browser.find_element_by_xpath('//*[@id="fm-login-password"]').send_keys(password)
            time.sleep(1)

            try:
                # 出现验证码,滑动验证
                slider = self.browser.find_element_by_xpath("//span[contains(@class, 'btn_slide')]")
                if slider.is_displayed():
                    # 拖拽滑块
                    self.action_chains.drag_and_drop_by_offset(slider, 258, 0).perform()
                    time.sleep(0.5)
                    # 释放滑块,至关于点击拖拽以后的释放鼠标
                    self.action_chains.release().perform()
            except (NoSuchElementException, WebDriverException):
                logger.info('未出现登陆验证码')
            
            #会xpath能够简化点击登录按钮
            #self.browser.find_element_by_class_name('password-login').click()
            self.browser.find_element_by_xpath('//*[@id="login-form"]/div[4]/button').click()
            
            nickname = self.get_nickname()
            if nickname:
                logger.info('登陆成功,呢称为:' + nickname)
                break
            logger.debug('登陆出错,5s后继续登陆')
            time.sleep(5)

    def get_nickname(self):
        self.browser.get(self.domain)
        time.sleep(0.5)
        try:
            return self.browser.find_element_by_class_name('site-nav-user').text
        except NoSuchElementException:
            return ''


if __name__ == '__main__':
    # 填入本身的用户名,密码
    username = 'username'
    password = 'password'
    tb = taobao()
    tb.login(username, password)

代码加了一些异常处理,以及 log 信息的打印。这里须要注意的是,滑块不是每次都出,因此要加个判断。

输入你的帐号和密码,指定 Chrome 驱动路径,运行代码,看看可否如咱们所愿的登录成功。

能够看到,帐号密码,都输入了,验证码也经过。

可是,就是登录不上!这是为何呢?

二、淘宝反 Selenium 登录破解

很简单,淘宝有反爬虫,并且是专门针对 Selenium 的。

这么操做,永远登录不进去。

遇到这种反爬的时候,不要慌,慢慢思考

一般,遇到这种反爬虫,第一反应就是:验证码滑块滑地太快了。

被检测出来了。

我刚开始也是这么想,因此我本身写了一个滑动方法。

匀速、加速、减速,甚至颤颤巍巍滑动,都不行!

显然,跟验证码滑块无关。

这时候,就得学会测试,分析出它的放爬虫策略。

分步测试,你就会发现,帐号密码程序输入,滑块程序滑动,而后暂停程序,咱们手动鼠标点击登陆,就能登录成功。

神奇吧?

这是为啥?

我猜想,应该是淘宝,有针对 Selenium 的 find_element_by_* 方法的 click 事件监听。

只要是使用 Selenium 完成的点击事件,淘宝就不让你登陆。

具体怎么实现的我不清楚,可是我知道怎么破解。

很简单,Selenium 这个点击方法不行,那就换个第三方库呗!

Python 最不缺的就是各类各样的第三方库。

pyautogui 了解一下。

pyautogui 功能强大,能够操控电脑的鼠标,有相似「按键精灵」的功能。

pyautogui 的有些方法,甚至比「按键精灵」更强大。

安装方法也很简单,使用 pip 便可。

python -m pip install pyautogui

用法很简单,截取登陆按钮那里的图片,像这样:

而后 pyautogui 就能够根据这张图片,找到按钮的坐标,而后操控电脑的鼠标进行点击。

coords = pyautogui.locateOnScreen('1.png')
x, y = pyautogui.center(coords)
pyautogui.leftClick(x, y)

就问你强大不?

直接修改代码,开搞!

from selenium import webdriver
import logging
import time
from selenium.common.exceptions import NoSuchElementException, WebDriverException
from retrying import retry
from selenium.webdriver import ActionChains

import pyautogui
pyautogui.PAUSE = 0.5 

logging.basicConfig(level = logging.INFO,format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

class taobao():
    def __init__(self):
        self.browser = webdriver.Chrome("path\to\your\chromedriver.exe")
        # 最大化窗口
        self.browser.maximize_window()
        self.browser.implicitly_wait(5)
        self.domain = 'http://www.taobao.com'
        self.action_chains = ActionChains(self.browser)

    def login(self, username, password):
        while True:
            self.browser.get(self.domain)
            time.sleep(1)
            
            #会xpath能够简化这几步
            #self.browser.find_element_by_class_name('h').click()
            #self.browser.find_element_by_id('fm-login-id').send_keys(username)
            #self.browser.find_element_by_id('fm-login-password').send_keys(password)
            self.browser.find_element_by_xpath('//*[@id="J_SiteNavLogin"]/div[1]/div[1]/a[1]').click()
            self.browser.find_element_by_xpath('//*[@id="fm-login-id"]').send_keys(username)
            self.browser.find_element_by_xpath('//*[@id="fm-login-password"]').send_keys(password)
            time.sleep(1)

            try:
                # 出现验证码,滑动验证
                slider = self.browser.find_element_by_xpath("//span[contains(@class, 'btn_slide')]")
                if slider.is_displayed():
                    # 拖拽滑块
                    self.action_chains.drag_and_drop_by_offset(slider, 258, 0).perform()
                    time.sleep(0.5)
                    # 释放滑块,至关于点击拖拽以后的释放鼠标
                    self.action_chains.release().perform()
            except (NoSuchElementException, WebDriverException):
                logger.info('未出现登陆验证码')
            
            # 会xpath能够简化点击登录按钮,但都没法登陆,须要使用 pyautogui 完成点击事件
            #self.browser.find_element_by_class_name('password-login').click()
            #self.browser.find_element_by_xpath('//*[@id="login-form"]/div[4]/button').click()
            # 图片地址
            coords = pyautogui.locateOnScreen('1.png')
            x, y = pyautogui.center(coords)
            pyautogui.leftClick(x, y)
            
            nickname = self.get_nickname()
            if nickname:
                logger.info('登陆成功,呢称为:' + nickname)
                break
            logger.debug('登陆出错,5s后继续登陆')
            time.sleep(5)

    def get_nickname(self):
        self.browser.get(self.domain)
        time.sleep(0.5)
        try:
            return self.browser.find_element_by_class_name('site-nav-user').text
        except NoSuchElementException:
            return ''


if __name__ == '__main__':
    # 填入本身的用户名,密码
    username = 'username'
    password = 'password'
    tb = taobao()
    tb.login(username, password)

淘宝针对 Selenium 的反爬,就这样解决了!

三、清空购物车

已经登录进来了,清空购物车就小菜一碟了!

仍是按照以前的步骤,自行分析吧。

这里很简单,我就直接贴代码了。

from selenium import webdriver
import logging
import time
from selenium.common.exceptions import NoSuchElementException, WebDriverException
from retrying import retry
from selenium.webdriver import ActionChains

import pyautogui
pyautogui.PAUSE = 0.5 

logging.basicConfig(level = logging.INFO,format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

class taobao():
    def __init__(self):
        self.browser = webdriver.Chrome("path\to\your\chromedriver.exe")
        # 最大化窗口
        self.browser.maximize_window()
        self.browser.implicitly_wait(5)
        self.domain = 'http://www.taobao.com'
        self.action_chains = ActionChains(self.browser)

    def login(self, username, password):
        while True:
            self.browser.get(self.domain)
            time.sleep(1)
            
            #会xpath能够简化这几步
            #self.browser.find_element_by_class_name('h').click()
            #self.browser.find_element_by_id('fm-login-id').send_keys(username)
            #self.browser.find_element_by_id('fm-login-password').send_keys(password)
            self.browser.find_element_by_xpath('//*[@id="J_SiteNavLogin"]/div[1]/div[1]/a[1]').click()
            self.browser.find_element_by_xpath('//*[@id="fm-login-id"]').send_keys(username)
            self.browser.find_element_by_xpath('//*[@id="fm-login-password"]').send_keys(password)
            time.sleep(1)

            try:
                # 出现验证码,滑动验证
                slider = self.browser.find_element_by_xpath("//span[contains(@class, 'btn_slide')]")
                if slider.is_displayed():
                    # 拖拽滑块
                    self.action_chains.drag_and_drop_by_offset(slider, 258, 0).perform()
                    time.sleep(0.5)
                    # 释放滑块,至关于点击拖拽以后的释放鼠标
                    self.action_chains.release().perform()
            except (NoSuchElementException, WebDriverException):
                logger.info('未出现登陆验证码')
            
            # 会xpath能够简化点击登录按钮,但都没法登陆,须要使用 pyautogui 完成点击事件
            #self.browser.find_element_by_class_name('password-login').click()
            #self.browser.find_element_by_xpath('//*[@id="login-form"]/div[4]/button').click()
            # 图片地址
            coords = pyautogui.locateOnScreen('1.png')
            x, y = pyautogui.center(coords)
            pyautogui.leftClick(x, y)
            
            nickname = self.get_nickname()
            if nickname:
                logger.info('登陆成功,呢称为:' + nickname)
                break
            logger.debug('登陆出错,5s后继续登陆')
            time.sleep(5)

    def get_nickname(self):
        self.browser.get(self.domain)
        time.sleep(0.5)
        try:
            return self.browser.find_element_by_class_name('site-nav-user').text
        except NoSuchElementException:
            return ''
            
    def clear_cart(self):
        cart = self.browser.find_element_by_xpath('//*[@id="J_MiniCart"]')
        if cart.is_displayed():
            cart.click()
        select = self.browser.find_element_by_xpath('//*[@id="J_SelectAll1"]/div/label')
        if select.is_displayed():
            select.click()
        time.sleep(0.5)
        go = self.browser.find_element_by_xpath('//*[@id="J_Go"]')
        if go.is_displayed():
            go.click()
        submit = self.browser.find_element_by_xpath('//*[@id="submitOrderPC_1"]/div/a[2]')
        if submit.is_displayed():
            submit.click()


if __name__ == '__main__':
    # 填入本身的用户名,密码
    username = 'username'
    password = 'password'
    tb = taobao()
    tb.login(username, password)
    tb.clear_cart()

运行效果:

剩下的就是掏钱了。

 

扫码支付,只要你有钱,你甚至能够不看价格,直接程序写好支付密码,完成支付。

5、最后

  • Selenium 用着很方便,可是也会遇到反爬虫,须要根据状况自行分析。
  • 618 准备开始剁手啦!爱他/她,就帮他清空购物车!

点赞再看,养成习惯,微信公众号搜索【JackCui-AI】关注一个在互联网摸爬滚打的潜行者