文章目錄
- 1. 問題分析
- 2. 基礎情況
- 3. 安裝 selenium
- 4. 下載 Edge 瀏覽器驅動
- 5. 登錄網頁京東
- 6. 滑動驗證登錄
- 7. 自動購買商品
- 8. 完整實作原始碼
- 結 語
- 參考博客
1. 問題分析
- 在京東上搶購商品老是失敗,在提交訂單時發現已經沒貨,由此確定京東已經搶到的標志是提交訂單,有時好像是付款才算搶到成功,預售商品雖然可以加入購物車,但卻是不可選的,因此在自動搶購程序中必須先勾選,
- 一般京東搶購的程序是:登錄賬號 → 進入購物車 → 選擇搶購商品 → 點擊去結算 → 點擊提交訂單 → 選擇付款方式并付款,基于這種情況利用 python 代碼實作自動登錄京東賬號,自動滑動驗證碼進行驗證,自動勾選購物車商品并提交訂單,剩下的付款操作手動進行,

2. 基礎情況
以下環境滿足其一即可:
- 已安裝 python 解釋器和 Pycharm 軟體,已切換鏡像源并系結,
- 已安裝 Anaconda 軟體和 Pycharm 軟體并系結 Anaconda 自帶的 python 解釋器,已切換鏡像源并系結,
可以不限于以上兩種開發環境配置方式,
3. 安裝 selenium
selenium 是一個 python 自動化測驗工具,利用 selenium 工具包可以對瀏覽器網頁進行諸如點擊和下載內容等操作,簡單實用,
3.1 對于使用單獨 python 解釋器的情況,使用命令列 cd 進入解釋器安裝路徑下的 Scripts 路徑下,運行代碼 pip install selenium 進行安裝,

3.2 對于使用 Anaconda 自帶 python 解釋器的情況,打開 Anaconda Prompt,運行代碼 activate root 進入基礎環境(有些版本打開時就已經在基礎環境 base 下就不用執行這一步),接下來再運行代碼 pip install selenium 進行安裝,

3.3 等待安裝完成之后運行 python 進入互動式環境,運行代碼 import selenium 不報錯則表示安裝成功,

4. 下載 Edge 瀏覽器驅動
可以不限于使用 Edge 瀏覽器,使用 Chrome,FireFox 等都是可以的,但需要下載對應的驅動,點擊鏈接 https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/進入 edge 驅動下載界面,勾選穩定版 x64 開始下載,此處根據自己電腦系統進行選擇,

下載得到一個壓縮包,右鍵點擊解壓到當前檔案夾,將其中的 msedgedriver.exe 復制到自己當前的專案工程根路徑下,

5. 登錄網頁京東
5.1 先打開 edge 瀏覽器并最大化視窗,進入京東登錄界面,
driver = webdriver.Edge(executable_path='./msedgedriver.exe') # 打開 Edge 瀏覽器
driver.maximize_window() # 最大化 Edge 瀏覽器視窗
driver.get('https://passport.jd.com/new/login.aspx') # 京東登錄界面鏈接
5.2 選擇賬戶登錄選項,自動輸入用戶名和密碼,最后點擊登錄,
driver.find_element_by_link_text("賬戶登錄").click() # 選擇賬戶登錄并點擊
driver.implicitly_wait(2) # 隱式等待 2 秒
driver.find_element_by_id("loginname").send_keys(username) # 找到用戶名輸入框并輸入用戶名
driver.implicitly_wait(2) # 隱式等待 2 秒
driver.find_element_by_id("nloginpwd").send_keys(password) # 找到密碼輸入框輸入密碼
driver.implicitly_wait(2) # 隱式等待 2 秒
driver.find_element_by_id("loginsubmit").click() # 找到登錄并點擊
6. 滑動驗證登錄
由于京東的安全限制,點擊登錄之后需要進行滑動驗證才能完成登錄,滑動驗證碼本身由兩幅影像組成,一個作為可滑動的小滑塊,一個是缺失滑塊結構的背景,
6.1 首先獲取滑動驗證碼的兩幅影像,灰度化處理后保存到本地,
image_big_path = r'//div/div[@class="JDJRV-bigimg"]/img' # 滑動驗證碼大圖(大背景)
image_small_path = r'//div/div[@class="JDJRV-smallimg"]/img' # 滑動驗證碼小圖(小滑塊)
image_big = driver.find_element_by_xpath(image_big_path).get_attribute("src") # 驗證碼背景圖的完整路徑
image_small = driver.find_element_by_xpath(image_small_path).get_attribute("src") # 驗證碼滑塊圖的完整路徑
request.urlretrieve(image_big, 'background.jpg') # 下載驗證碼背景圖到本地
request.urlretrieve(image_small, 'slideblock.jpg') # 下載驗證碼滑塊圖到本地
cv2.imwrite('background.jpg', cv2.imread('background.jpg', 0)) # 將驗證碼背景圖讀取為灰度圖并覆寫原圖
slideblock = cv2.imread('slideblock.jpg', 0) # 將驗證碼滑塊圖讀取為灰度圖
slideblock = abs(255 - slideblock) # 對驗證碼滑塊圖反灰化處理
cv2.imwrite('slideblock.jpg', slideblock) # 保存處理后的驗證碼滑塊圖
background = cv2.imread('background.jpg') # 讀取驗證碼背景圖(灰度)
slideblock = cv2.imread('slideblock.jpg') # 讀取驗證碼滑塊圖(灰度)
6.2 再利用 opencv 中的模板匹配函式 matchTemplate 得到滑塊影像在背景上的相似度矩陣,
result = cv2.matchTemplate(background, slideblock, cv2.TM_CCOEFF_NORMED) # 模板匹配,獲得滑塊在背景上的相似度矩陣
6.3 利用 numpy 中的元素索引函式 unravel_index 獲取匹配度最大值在原相似度矩陣中的索引,
_, distance = np.unravel_index(result.argmax(), result.shape) # 獲得要移動的距離
注意在該函式中索引坐標系與一般理解略有不同,

6.4 模擬人越來越快地移動滑塊到指定位置,由于京東的安全管制,必須采取一定的滑塊移動策略才能盡量不被檢測出來非手動,實際實驗中滑動驗證正確的步數也是不確定的,大概 1~10 步左右,
dist_finished = 0 # 已經移動的距離
dist_remaining = distance # 剩余的距離
dist_move = 5 # 每次移動的距離
element = driver.find_element_by_xpath(button_slide) # 選取滑動驗證碼滑塊
ActionChains(driver).click_and_hold(element).perform() # 模擬滑鼠在滑塊上點擊并保持
# 模擬滑動開始和滑動結束時比較慢,中間階段比較快
while dist_remaining > 0:
dist_move += dist_move # 不斷加速地移動滑塊
# 每次移動滑塊都帶有正負偏差來模擬手動移動時的滑動不穩定
ActionChains(driver).move_by_offset(dist_move, random.randint(-3, 3)).perform() # 模擬滑鼠水平向右拖動滑塊
dist_remaining -= dist_move # 剩余距離減去已移動的距離
dist_finished += dist_move # 已完成距離加上已移動的距離
ActionChains(driver).move_by_offset(dist_remaining, random.randint(-3, 3)).perform() # 模擬滑鼠水平回移拖動滑塊修正
ActionChains(driver).release(on_element=element).perform() # 模擬松開滑鼠
7. 自動購買商品
7.1 登錄成功后點擊我的購物車打開另一個瀏覽器頁面,
driver.implicitly_wait(2) # 隱式等待 2 秒
driver.find_element_by_link_text("我的購物車").click() # 找到我的購物車并點擊
7.2 全選購物車中的商品,點擊結算并提交訂單,
driver.implicitly_wait(2) # 隱式等待 2 秒
driver.find_element_by_name('select-all').click() # 購物車全選
time.sleep(0.5) # 等待 0.5 秒
driver.find_element_by_link_text("去結算").click() # 找到去結算并點擊
driver.implicitly_wait(2) # 隱式等待 2 秒
driver.find_element_by_id("order-submit").click() # 找到提交訂單并點擊
8. 完整實作原始碼
import cv2
import time
import random
import datetime
import numpy as np
from urllib import request
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
# 移動滑動驗證碼中的滑塊
def checkMove(button_slide, distance):
dist_finished = 0 # 已經移動的距離
dist_remaining = distance # 剩余的距離
dist_move = 5 # 每次移動的距離
element = driver.find_element_by_xpath(button_slide) # 選取滑動驗證碼滑塊
ActionChains(driver).click_and_hold(element).perform() # 模擬滑鼠在滑塊上點擊并保持
# 模擬滑動開始和滑動結束時比較慢,中間階段比較快
while dist_remaining > 0:
dist_move += dist_move # 不斷 加速移動滑塊
# 每次移動滑塊都帶有正負偏差來模擬手動移動時的滑動不穩定
ActionChains(driver).move_by_offset(dist_move, random.randint(-3, 3)).perform() # 模擬滑鼠水平向右拖動滑塊
dist_remaining -= dist_move # 剩余距離減去已移動的距離
dist_finished += dist_move # 已完成距離加上已移動的距離
ActionChains(driver).move_by_offset(dist_remaining, random.randint(-3, 3)).perform() # 模擬滑鼠水平回移拖動滑塊修正
ActionChains(driver).release(on_element=element).perform() # 模擬松開滑鼠
# 獲取滑動驗證碼構成的兩張圖片并計算應移動的距離
def getCheckImage():
image_big_path = r'//div/div[@class="JDJRV-bigimg"]/img' # 滑動驗證碼大圖(大背景)
image_small_path = r'//div/div[@class="JDJRV-smallimg"]/img' # 滑動驗證碼小圖(小滑塊)
button_slide = '//div[@class="JDJRV-slide-inner JDJRV-slide-btn"]' # 滑動驗證碼滑塊按鈕
image_big = driver.find_element_by_xpath(image_big_path).get_attribute("src") # 驗證碼背景圖的完整路徑
image_small = driver.find_element_by_xpath(image_small_path).get_attribute("src") # 驗證碼滑塊圖的完整路徑
request.urlretrieve(image_big, 'background.jpg') # 下載驗證碼背景圖到本地
request.urlretrieve(image_small, 'slideblock.jpg') # 下載驗證碼滑塊圖到本地
cv2.imwrite('background.jpg', cv2.imread('background.jpg', 0)) # 將驗證碼背景圖讀取為灰度圖并覆寫原圖
slideblock = cv2.imread('slideblock.jpg', 0) # 將驗證碼滑塊圖讀取為灰度圖
slideblock = abs(255 - slideblock) # 對驗證碼滑塊圖反灰化處理
cv2.imwrite('slideblock.jpg', slideblock) # 保存處理后的驗證碼滑塊圖
background = cv2.imread('background.jpg') # 讀取驗證碼背景圖(灰度)
slideblock = cv2.imread('slideblock.jpg') # 讀取驗證碼滑塊圖(灰度)
result = cv2.matchTemplate(background, slideblock, cv2.TM_CCOEFF_NORMED) # 模板匹配,獲得滑塊在背景上的相似度矩陣
_, distance = np.unravel_index(result.argmax(), result.shape) # 獲得要移動的距離
return button_slide, distance
# 滑動驗證
def slideIdentify():
slideButton, distance = getCheckImage() # 獲取滑塊和滑塊需要移動的距離
print(f'本次滑塊需要移動的距離為: {distance}') # 列印滑塊需要移動的距離
checkMove(slideButton, distance / 1.3) # 移動滑塊,1.3 是一個實驗修正值
# 登錄京東網頁版
def login(username, password):
driver.get('https://passport.jd.com/new/login.aspx') # 京東登錄界面鏈接
driver.implicitly_wait(2) # 隱式等待 2 秒
driver.find_element_by_link_text("賬戶登錄").click() # 找到賬戶登錄并點擊
driver.implicitly_wait(2) # 隱式等待 2 秒
driver.find_element_by_id("loginname").send_keys(username) # 找到用戶名輸入框并輸入用戶名
driver.implicitly_wait(2) # 隱式等待 2 秒
driver.find_element_by_id("nloginpwd").send_keys(password) # 找到密碼輸入框輸入密碼
driver.implicitly_wait(2) # 隱式等待 2 秒
driver.find_element_by_id("loginsubmit").click() # 找到登錄并點擊
while True:
try:
slideIdentify() # 進行滑動驗證
time.sleep(2) # 等待 3 秒
except:
print("登錄成功")
break
# 定時購買東西
def buy(buy_time):
driver.implicitly_wait(2) # 隱式等待 2 秒
driver.find_element_by_link_text("我的購物車").click() # 找到我的購物車并點擊
total_windows = driver.window_handles # 所有打開的視窗
driver.switch_to.window(total_windows[1]) # 句柄遷移到第二個視窗
while True:
current_time = datetime.datetime.now() # 獲取當前日期時間
if current_time.strftime('%Y-%m-%d %H:%M:%S') == buy_time: # 如果當前時間等于指定購買時間
driver.implicitly_wait(2) # 隱式等待 2 秒
driver.find_element_by_name('select-all').click() # 購物車全選
time.sleep(0.5) # 等待 0.5 秒
driver.find_element_by_link_text("去結算").click() # 找到去結算并點擊
driver.implicitly_wait(2) # 隱式等待 2 秒
driver.find_element_by_id("order-submit").click() # 找到提交訂單并點擊
driver.implicitly_wait(2) # 隱式等待 2 秒
print('current time : ' + current_time.strftime('%Y-%m-%d %H:%M:%S')) # 列印當前時間
print('購買成功 !') # 購買成功
if __name__ == '__main__':
driver = webdriver.Edge(executable_path='./msedgedriver.exe') # 打開 Edge 瀏覽器
driver.maximize_window() # 最大化 Edge 瀏覽器視窗
login('你的用戶名', '你的密碼') # 登錄京東
buy('2021-08-14 12:00:00') # 定時購買
結 語
網頁自動化操作確實可以實作搶購商品,相比手動操作會更快,但僅靠上述代碼想與某些專業搶購的服務器進行比較還是相去甚遠,如果有需要可以嘗試一下,就當是一個 python 實戰專案學習,

參考博客
- https://blog.csdn.net/netuser1937/article/details/111594315
- https://blog.csdn.net/jolly10/article/details/109516130
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/293617.html
標籤:python
