1. 程式人生 > 實用技巧 >利用Python模擬登陸淘寶,實現購物秒殺!

利用Python模擬登陸淘寶,實現購物秒殺!

模擬登入

學爬蟲,總能聽到模擬登入這四個字,究竟什麼是模擬登入?通俗一點講,模擬登入就是程式用賬號和密碼自動登入一個網站。然後,拿到只有登入後,才能下載的網站資料。

比如,我們只有登入淘寶賬號之後,才能看到購物車裡有哪些東西。本文,就以模擬登入淘寶為例進行講解,並幫他/她清空購物車。

很多人學習python,不知道從何學起。
很多人學習python,掌握了基本語法過後,不知道在哪裡尋找案例上手。
很多已經做案例的人,卻不知道如何去學習更加高深的知識。
那麼針對這三類人,我給大家提供一個好的學習平臺,免費領取視訊教程,電子書籍,以及課程的原始碼!
QQ群:101677771

你只需要知道他/她的淘寶賬號和密碼,並且有個充足的錢包,就可以執行程式,掃碼支付一氣呵成。

體驗自動結算,錢包秒空的快感!

Selenium

模擬登入無非兩種方法:請求包分析模擬登入、自動化測試工具模擬登入。

前者,需要抓包分析請求,解析各種引數,還可能涉及一些加密演算法。

後者,可以繞過一些繁瑣的分析過程,直接定位元素進行操作,但也會遇到一些反爬策略。

兩者,都有各自的操作技巧。

本文講解一個新思路,使用自動化測試工具 Selenium 模擬登入。

Selenium 基本的使用方法,以及如何破解淘寶對於 Selenium 的反爬策略,盡在下文。

Selenium 安裝

Selenium 是一個自動化測試工具,支援各種主流瀏覽器,例如 Chrome、Safari、Firefox 等。

不知道什麼是自動化測試工具沒關係,我會通過實戰操作,慢慢講解。

不管怎樣,先安裝 Selenium 再說。

pip install selenium

使用 pip 直接安裝 selenium。

除了安裝 Python 的 Selenium 第三方庫,還需要根據瀏覽器配置相應的瀏覽器驅動。

以 Chrome 為例,下載瀏覽器驅動。

https://sites.google.com/a/chromium.org/chromedriver/downloads

需要根據瀏覽器的版本,選擇驅動下載。

小試牛刀

使用 Selenium 登入百度看一下。

from selenium import webdriver

if __name__ == "__main__":
    browser = webdriver.Chrome()
    browser.get('https://www.baidu.com/')

結果如下圖所示:

程式會自動開啟 Chrome 瀏覽器,並開啟 www.baidu.com。

再來個複雜一些的例子。

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

if __name__ == "__main__":
    driver = webdriver.Chrome()
    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 的標籤。

詳細的,關於 Selenium 的 API 文件,可以看官方手冊。

官方手冊:

https://selenium-python.readthedocs.io/index.html

好了,基礎知識準備完畢。

只要你會使用 copy xpath,基本的 Selenium 操作,就可以開始跟我一起「模擬登入」淘寶。

登陸淘寶,掏空錢包

這場為了愛情的清空購物車大作戰,需要分兩步完成:

  • 模擬登入淘寶

  • 購物車結算

模擬登入淘寶

用 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()

剩下的就是掏錢了。