Python3 網絡爬蟲(六):618,愛他/她,就清空他/她的購物車!

Python3 網絡爬蟲(六):618,愛他/她,就清空他/她的購物車!

本文 GitHub https://github.com/Jack-Cherish/PythonPark 已收錄,有技術乾貨文章,整理的學習資料,一線大廠面試經驗分享等,歡迎 Star 和 完善。

一、前言

爬蟲系列,已講 5 篇。

文字、圖片、視頻這類常規的內容下載、API 的使用,這些操作對你來說,應該輕而易舉了。

那今天,就講解一下高級一點的技能,「模擬登錄」。

值此 618 之際,幫他/她清空一波購物車!

二、模擬登錄

學爬蟲,總能聽到「模擬登錄」這四個字,究竟什麼是「模擬登錄」?

通俗一點講,「模擬登錄」就是程序用賬號和密碼自動登錄一個網站。

然後,拿到只有登錄後,才能下載的網站數據。

比如,我們只有登錄淘寶賬號之後,才能看到購物車裏有哪些東西。

本文,就以「模擬登錄」淘寶爲例進行講解,並幫他/她清空購物車。

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

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

三、Selenium

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

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

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

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

之前的教程,講解了很多基於 requests 請求包分析的爬蟲思路。

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

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

1、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

2、小試牛刀

使用 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 操作,就可以開始跟我一起「模擬登錄」淘寶。

四、登錄淘寶,掏空錢包

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

  • 模擬登錄淘寶
  • 購物車結算

1、模擬登錄淘寶

用 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 驅動路徑,運行代碼,看看能否如我們所願的登陸成功。

可以看到,賬號密碼,都輸入了,驗證碼也通過。

但是,就是登陸不上!這是爲什麼呢?

2、淘寶反 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 的反爬,就這樣解決了!

3、清空購物車

已經登陸進來了,清空購物車就小菜一碟了!

還是按照之前的步驟,自行分析吧。

這裏很簡單,我就直接貼代碼了。

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

運行效果:

剩下的就是掏錢了。

 

掃碼支付,只要你有錢,你甚至可以不看價格,直接程序寫好支付密碼,完成支付。

五、最後

  • Selenium 用着很方便,但是也會遇到反爬蟲,需要根據情況自行分析。
  • 618 準備開始剁手啦!愛他/她,就幫他清空購物車!

點贊再看,養成習慣,微信公衆號搜索【JackCui-AI】關注一個在互聯網摸爬滾打的潛行者

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章