利用Python模擬登陸淘寶,實現購物秒殺!
模擬登入
學爬蟲,總能聽到模擬登入這四個字,究竟什麼是模擬登入?通俗一點講,模擬登入就是程式用賬號和密碼自動登入一個網站。然後,拿到只有登入後,才能下載的網站資料。
比如,我們只有登入淘寶賬號之後,才能看到購物車裡有哪些東西。本文,就以模擬登入淘寶為例進行講解,並幫他/她清空購物車。
很多人學習python,不知道從何學起。
很多人學習python,掌握了基本語法過後,不知道在哪裡尋找案例上手。
很多已經做案例的人,卻不知道如何去學習更加高深的知識。
那麼針對這三類人,我給大家提供一個好的學習平臺,免費領取視訊教程,電子書籍,以及課程的原始碼!
QQ群:101677771
你只需要知道他/她的淘寶賬號和密碼,並且有個充足的錢包,就可以執行程式,掃碼支付一氣呵成。
模擬登入無非兩種方法:請求包分析模擬登入、自動化測試工具模擬登入。
前者,需要抓包分析請求,解析各種引數,還可能涉及一些加密演算法。
後者,可以繞過一些繁瑣的分析過程,直接定位元素進行操作,但也會遇到一些反爬策略。
兩者,都有各自的操作技巧。
本文講解一個新思路,使用自動化測試工具 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() 點選。
點選登入後,進入登陸頁面,找到賬號框和密碼框位置,並輸入賬號和密碼。
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 的 find_element_by_* 方法的 click 事件監聽。
只要是使用 Selenium 完成的點選事件,淘寶就不讓你登入。
具體怎麼實現的我不清楚,但是我知道怎麼破解。
很簡單,Selenium 這個點選方法不行,那就換個第三方庫唄!
Python 最不缺的就是各種各樣的第三方庫。
pyautogui 瞭解一下。
pyautogui 功能強大,可以操控電腦的滑鼠,有類似「按鍵精靈」的功能。
pyautogui 的有些方法,甚至比「按鍵精靈」更強大。
安裝方法也很簡單,使用 pip 即可。
python -m pip install 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()
剩下的就是掏錢了。