你好,我是小焦。今天给大家分享的是如何用python来实现京东平台的自动抢单,多线程多账号来增大我们的抢购成功率。我们都知道京东自营经常会出现一些折扣力度大的商品。而我们每次抢的时候老是一秒钟缺货了,为什么呢?很简单,本来货就少,全部被黄牛拿走了。
黄牛能用软件搞,我们做为业余的IT人员也是可以凭本事搞的哈哈。至于其中有什么商机,大家下去自己琢磨呗,就像最近的某台酒,某显卡了,那价格翻的了好几倍。好了下面回归正题。
思路
写代码之前肯定要想好如何实现?整体的思路规划肯定少不了。我们要做到多线程多账号同时抢单,第一肯定要实现多账号的储备了,账号这里下去自己申请哦。其次我们要借用上次讲过的cookie池了,我们总不可能开始抢单了才一个一个的账号去登录,黄花菜都凉了。然后就是用cookies登录网页进行模拟抢单下单操作了。将各个模块实现之后,然后应用python的多线程操作就行,或者用多进程都可以的,调用很简单。
准备工作:
- 自行准备京东账号(京东账号貌似要绑定手机号的,当然是越多越好)
- 安装谷歌浏览器
- 安装Chromdriver(整个根据下载的浏览器版本下载,自行百度)
- 安装redis数据库
- python以及selenium、redis库
一、建立cookie池
第一步就是建立京东的cookie池,方法参照我的上一篇文章cookie池的建立,或者到文章末尾直接去github看我写的代码。由于京东验证这块非常多,验证码,短信验证等待都是非常麻烦,所以我们还是用selnium来获取cookies的。由于短信验证是随机出来的,所以我们要将网页最大等待时间设置的时间长一点。其次就是根据自己家的设备和网速自行设置。
最让人无语的就是京东的cookies有效时间只有一天,所以我们时间超过一天必须要重新生成。下面来看看京东的cookie生成操作吧。
from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
import selenium.common.exceptions as ex
import time
class Cookies():
def __init__(self,username,password):
# 这里我们使用谷歌浏览器
self.url = 'https://www.jd.com/'
self.brower = webdriver.Chrome()
# 设置最长显示等待时间10s
self.wait = WebDriverWait(self.brower,30)
self.username = username
self.password = password
# 这里进行模拟登录操作
def openjd(self):
self.brower.get(self.url)
# 打开京东主页,打击登录按钮
self.wait.until(EC.presence_of_element_located((By.CLASS_NAME,'link-login'))).click()
# 选择账号密码登录
self.wait.until(EC.presence_of_element_located((By.XPATH,'//div[@class="login-tab login-tab-r"]/a'))).click()
# 输入账号
self.wait.until(EC.presence_of_element_located((By.ID,'loginname'))).send_keys(self.username)
# 输入密码
self.wait.until(EC.presence_of_element_located((By.ID,'nloginpwd'))).send_keys(self.password)
# 点击登录按钮
self.wait.until(EC.presence_of_element_located((By.ID,'loginsubmit'))).click()
# 判断账号密码受否错误
def password_error(self):
try:
# 判断是否会出现错误提示,如果出现则出现密码错误提示
print('正在测试账号密码')
return bool(self.wait.until(EC.presence_of_element_located((By.CLASS_NAME,'msg-error'))))
except ex.TimeoutException:
return False
# 获取cookies
def getcookies(self):
return self.brower.get_cookies()
# 判断账号受否登录成功
def login_success(self):
try:
# 判断页面中是否有退出
return bool(self.wait.until(EC.presence_of_element_located((By.CLASS_NAME,'nickname'))))
except ex.TimeoutException:
return False
def main(self):
self.openjd()
# 上面完成打开浏览器填写账号密码操作,验证码这块自己手动操作
time.sleep(5)
if self.password_error():
print('用户名或密码错误')
self.brower.close()
return {
'status':2,
'content':'用户名或者密码错误'
}
elif self.login_success():
print('登录成功')
# 获取cookies
cookies = self.getcookies()
self.brower.close()
print(cookies)
return {
'status':1,
'content':cookies
}
else:
print('登录失败')
self.brower.close()
return {
'status':3,
'content':'登录异常'
}
生成cookie后记得去测试,这块我们就不展开说了,和上次的方法一样。
二、模拟下单
经过第一波的操作,我们将账号的cookie池生成并测试有效保存到了本地redis数据库中了。下面就是登录,选择商品,加入购物车,结算支付了。切记进行下面操作时,先重新生成cookie池,京东的有效期只有一天。这里我主要做了用cookie登录,然后进入到商品详情页,自动选择我们要买的商品属性,进行一系列点击操作,基本上都是CLASS和LINK_TEXT的筛选。每个步骤我都进行了备注。由于我的网速和硬件限制加载网页慢,所以wait等待时间设置的比较长,这块根据自身情况设置。
from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from save import RedisClient
from datetime import datetime
from selenium.webdriver.common.by import By
import selenium.common.exceptions as ex
import json
import time
# 普通商品购买流程,这里由于有的商品有多个属性,所以我们yanse使用字典
class putong():
def __init__(self,url,yanse):
self.url = url
# yanse为为我们下单上面的颜色类目选项
self.yanse = yanse
self.brower = webdriver.Chrome()
self.wait = WebDriverWait(self.brower,30)
self.cookies_db = RedisClient('jdcookies')
#先进行登录
def login(self):
print(datetime.now().strftime('%Y-%m-%d %H:%M:%S '),'开始使用cookies登录账号')
#随机获取一个账号的cookies
if self.cookies_db.count() != 0:
username,cookie = self.cookies_db.random_getall()
cookies = json.loads(cookie)
print(datetime.now().strftime('%Y-%m-%d %H:%M:%S '),'成功获取到账号%s的cookies'%username)
else:
print('没有可用的cookies,请重新获取后再进行登录')
return False
self.brower.get('https://www.jd.com/')
for cookie in cookies:
self.brower.add_cookie(cookie)
self.brower.get(self.url)
try:
# 判断账号是否登录成功
return bool(self.wait.until(EC.presence_of_element_located((By.CLASS_NAME,'nickname'))))
except ex.TimeoutException:
return False
# 选择商品加入购物车
def choice(self):
try:
# 遍历yanse中设定的值,也就是我们要选择的商品属性,有的商品有多个属性同时选择,所以我们要添加多个
for i in self.yanse:
print(datetime.now().strftime('%Y-%m-%d %H:%M:%S'),"正在选择属性",i)
self.wait.until(EC.presence_of_element_located((By.LINK_TEXT,i)))
#选择属性后点击加入购物车
self.wait.until(EC.presence_of_element_located((By.XPATH,'//div[@id="choose-btns"]/a[@id="InitCartUrl"]'))).click()
# 商品加入成功后京东会自动跳入到成功页面,我们检测整个CSS就行
if self.wait.until(EC.presence_of_element_located((By.CLASS_NAME,'success-lcol'))):
print(datetime.now().strftime('%Y-%m-%d %H:%M:%S'),'商品已成功加入购物车')
return True
else:
print(datetime.now().strftime('%Y-%m-%d %H:%M:%S'),'商品加入购物车失败')
return False
except ex.TimeoutException:
return False
# 购物车页面进行结算
def pay(self):
try:
# 打开购物车页面
self.brower.get('https://cart.jd.com/cart_index/')
# 点击全选。这块跳转到结算界面京东自动打勾了,这里我们不用自己操作
# self.wait.until(EC.presence_of_element_located((By.NAME,'select-all'))).click()
time.sleep(2)
# 点击结算
self.wait.until(EC.presence_of_element_located((By.LINK_TEXT, '去结算'))).click()
time.sleep(2)
self.wait.until(EC.presence_of_element_located((By.ID, 'order-submit'))).click()
print(datetime.now().strftime('%Y-%m-%d %H:%M:%S'), "已提交订单")
return True
except ex.TimeoutException:
print('页面超时')
return False
#进行登录下单流程
def run(self):
if self.login():
print(datetime.now().strftime('%Y-%m-%d %H:%M:%S'), "登录成功")
# 登录成功后选择商品属性
if self.choice():
print(datetime.now().strftime('%Y-%m-%d %H:%M:%S'), "商品属性选择完毕并成功加入购物车")
if self.pay():
print(datetime.now().strftime('%Y-%m-%d %H:%M:%S'), "成功提交订单,请及时支付")
self.brower.close()
else:
print('订单提交失败')
self.brower.close()
else:
print('商品选择失败')
self.brower.close()
三、多线程下单
经过上面两步,我们已经从京东下单并跳转到支付页面了。输入密码那些抢单成功后自行操作吧。最后我们调用多线程,多账号同时下单。thread_number是我们设置的最大线程数,自己根据情况而定。下面是截图的局部代码片段,具体的去我的github上面下载。最近github上不去,要源码的私聊我
#下单
def xiadan(self):
a = putong(shangping_url,shuxing)
a.run()
# 下单模块,
def run(self):
thread_list = []
# p = Pool(4)
# 根据我们设置的数量添加线程
for i in range(0,thread_number):
print('启动线程',i)
# 这块遇到大坑,多线程调用函数只写函数名,千万不要加括号,切记!切记!切记!坑的要死
a = threading.Thread(target=self.xiadan,args=(),)
print('加入线程',i)
thread_list.append(a)
# thread_list.append(Process(target=putong(url=shangping_url, yanse=shuxing).run(),name=str(i),))
# 启动线程
for m in thread_list:
m.start()
for thread in thread_list:
thread.join()
今天的内容我们就分享到这,整体也是非常简单,内容不多,太多的东西可能花到中途的调试过程中了。整体运行是没有问题,大伙根据自己情况修改。下次我会添加UI界面,并打包成可配置的exe文件给大伙分享出来。
github地址:https://github.com/zhanjiuyou
评论2