Jingdong’s rush to buy failed? Try using python to automatically buy on time (detailed comments)

1. Problem analysis

  • The rush to buy products on JD.com always fails. When submitting the order, it is found that the goods are no longer in stock. The sign that JD.com has confirmed that the product has been purchased is to submit the order. Sometimes it seems that payment is required before the product is successfully purchased. Although pre-sale items can be added to the shopping cart, they are not selectable, so they must be checked first during the automatic snap-up process.
  • The general process of JD.com rush buying is: log in to your account → enter the shopping cart → select the rush buying product → click to go to checkout → click to submit the order → select the payment method and make the payment. Based on this situation, python code is used to automatically log in to the JD account, automatically slide the verification code for verification, automatically check the shopping cart items and submit the order, and the remaining payment operations are performed manually.

Insert image description here

2. Basic situation

One of the following environments is sufficient:

  • The python interpreter and Pycharm software have been installed, and the image source has been switched and bound.
  • Anaconda software and Pycharm software have been installed and bound to Anaconda's own python interpreter. The mirror source has been switched and bound.

It is not limited to the above two development environment configuration methods.

3. Install selenium

Selenium is a python automated testing tool. Using the selenium toolkit, you can perform operations such as clicking and downloading content on browser web pages. It is simple and practical.

3.1 For the case of using a separate python interpreter, use the command line cd to enter the Scripts path under the interpreter installation path and run the code pip install seleniumto install.

Insert image description here
3.2 For the case of using Anaconda's own python interpreter, open Anaconda Prompt, run the code activate rootto enter the basic environment (some versions are already in the basic environment when opening, so basethere is no need to perform this step), and then run the code pip install seleniumto install.

Insert image description here
3.3 After the installation is completed, run python to enter the interactive environment. import seleniumIf no error is reported when running the code, the installation is successful.

Insert image description here

4. Download Edge browser driver

You are not limited to using the Edge browser. You can use Chrome, FireFox, etc., but you need to download the corresponding driver. Click the link https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/ to enter the edge driver download interface, check the stable version x64 to start downloading, select here according to your computer system.

Insert image description here
Download a compressed package, right-click to extract it to the current folder, and copy msedgedriver.exe in it to the root path of your current project.

Insert image description here

5. Log in to JD.com website

5.1 First open the edge browser and maximize the window to enter the JD login interface.

driver = webdriver.Edge(executable_path='./msedgedriver.exe')  # 打开 Edge 浏览器
driver.maximize_window()  # 最大化 Edge 浏览器窗口
driver.get('https://passport.jd.com/new/login.aspx')  # 京东登录界面链接

5.2 Select the account login option, automatically enter the username and password, and finally click Login.

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. Sliding verification login

Due to JD.com's security restrictions, after clicking to log in, sliding verification is required to complete the login. The sliding verification code itself consists of two images, one as a small slider that can be slid, and the other as a background with missing slider structure.

6.1 First obtain two images of the sliding verification code, grayscale them and save them locally.

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 Then use the template matching function in opencv matchTemplateto obtain the similarity matrix of the slider image on the background.

result = cv2.matchTemplate(background, slideblock, cv2.TM_CCOEFF_NORMED)  # 模板匹配,获得滑块在背景上的相似度矩阵

6.3 Use the element index function in numpy unravel_indexto obtain the index of the maximum matching degree in the original similarity matrix.

_, distance = np.unravel_index(result.argmax(), result.shape)  # 获得要移动的距离

Note that the index coordinate system in this function is slightly different from the general understanding.

Insert image description here

6.4 The simulator moves the slider to the specified position faster and faster. Due to JD.com's security control, a certain slider movement strategy must be adopted to avoid being detected as much as possible. In actual experiments, the correct number of steps for sliding verification is also uncertain, about 1 to 10 steps.

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. Automatically purchase goods

7.1 After successful login, click My Shopping Cart to open another browser page.

driver.implicitly_wait(2)  # 隐式等待 2 秒
driver.find_element_by_link_text("我的购物车").click()  # 找到我的购物车并点击

7.2 Select all the products in the shopping cart, click checkout and submit the order.

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. Complete implementation of source code

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')  # 定时购买

Conclusion

Automated operations on web pages can indeed help you snap up products, which is faster than manual operations, but the above code alone is still far from being able to compare with some professional snap-up servers. If necessary, you can give it a try and treat it as a python practical project study.

Insert image description here

Reference blog

  1. https://blog.csdn.net/netuser1937/article/details/111594315
  2. https://blog.csdn.net/jolly10/article/details/109516130

Guess you like

Origin blog.csdn.net/Wenyuanbo/article/details/119603768