jd抢购工具_Python爬虫教程,京东自动登录,在线抢购商品

2023-10-31

京东抢购

Python爬虫,自动录京东网站,查询商品库存,价格,显示购物车详情等。
可以指定抢购商品,自动购买下单,然后手动去京东付款就行。

chang log

  • 2017-03-30 实现二维码扫码登陆
  • 2017-06-27 Golang版JD_AutoBuy

运行环境

Python 2.7

第三方库

  • Requests: 简单好用,功能强大的Http请求库
  • beautifulsoup4: HTML文档格式化及便签选择器

环境配置

pip 

使用帮助

> python scraper-jd.py -h
usage: scraper-jd.py [-h] [-u USERNAME] [-p PASSWORD] [-g GOOD] [-c COUNT]
                     [-w WAIT] [-f] [-s]

Simulate to login Jing Dong, and buy sepecified good

optional arguments:
  -h, --help            show this help message and exit
  -u USERNAME, --username USERNAME
                        Jing Dong login user name
  -p PASSWORD, --password PASSWORD
                        Jing Dong login user password
  -g GOOD, --good GOOD  Jing Dong good ID
  -c COUNT, --count COUNT
                        The count to buy
  -w WAIT, --wait WAIT  Flush time interval, unit MS
  -f, --flush           Continue flash if good out of stock
  -s, --submit          Submit the order to Jing Dong

实例输出

+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Thu Mar 30 17:10:01 2017 > 请打开京东手机客户端,准备扫码登陆:
201 : 二维码未扫描 ,请扫描二维码
201 : 二维码未扫描 ,请扫描二维码
201 : 二维码未扫描 ,请扫描二维码
201 : 二维码未扫描 ,请扫描二维码
202 : 请手机客户端确认登录
200 : BADACIFYhf6fakfHvjiYTlwGzSp4EjFATN3Xw1ePR1hITtw0
登陆成功
+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Thu Mar 30 17:10:28 2017 > 商品详情
编号:3133857
库存:现货
价格:6399.00
名称:Apple iPhone 7 Plus (A1661) 128G 黑色 移动联通电信4G手机
链接:http://cart.jd.com/gate.action?pid=3133857&pcount=1&ptype=1
商品已成功加入购物车!
购买数量:3133857 > 1
+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Thu Mar 30 17:10:30 2017 > 购物车明细
购买    数量    价格        总价        商品
 Y      1       6399.00     6399.00     Apple iPhone 7 Plus (A1661) 128G 黑色 移动联通电信4G手机
总数: 1
总额: 6399.00
+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Thu Mar 30 17:10:30 2017 > 订单详情
+++++++++++++++++++++++++++++++++++++++++++++++++++++++
...

使用帮助

> python scraper-jd.py -h
usage: scraper-jd.py [-h] [-u USERNAME] [-p PASSWORD] [-g GOOD] [-c COUNT]
                     [-w WAIT] [-f] [-s]

Simulate to login Jing Dong, and buy sepecified good

optional arguments:
  -h, --help            show this help message and exit
  -u USERNAME, --username USERNAME
                        Jing Dong login user name
  -p PASSWORD, --password PASSWORD
                        Jing Dong login user password
  -g GOOD, --good GOOD  Jing Dong good ID
  -c COUNT, --count COUNT
                        The count to buy
  -w WAIT, --wait WAIT  Flush time interval, unit MS
  -f, --flush           Continue flash if good out of stock
  -s, --submit          Submit the order to Jing Dong

实例输出

+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Thu Mar 30 17:10:01 2017 > 请打开京东手机客户端,准备扫码登陆:
201 : 二维码未扫描 ,请扫描二维码
201 : 二维码未扫描 ,请扫描二维码
201 : 二维码未扫描 ,请扫描二维码
201 : 二维码未扫描 ,请扫描二维码
202 : 请手机客户端确认登录
200 : BADACIFYhf6fakfHvjiYTlwGzSp4EjFATN3Xw1ePR1hITtw0
登陆成功
+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Thu Mar 30 17:10:28 2017 > 商品详情
编号:3133857
库存:现货
价格:6399.00
名称:Apple iPhone 7 Plus (A1661) 128G 黑色 移动联通电信4G手机
链接:http://cart.jd.com/gate.action?pid=3133857&pcount=1&ptype=1
商品已成功加入购物车!
购买数量:3133857 > 1
+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Thu Mar 30 17:10:30 2017 > 购物车明细
购买    数量    价格        总价        商品
 Y      1       6399.00     6399.00     Apple iPhone 7 Plus (A1661) 128G 黑色 移动联通电信4G手机
总数: 1
总额: 6399.00
+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Thu Mar 30 17:10:30 2017 > 订单详情
+++++++++++++++++++++++++++++++++++++++++++++++++++++++
...

代码仅供学习之用,京东网页不断变化,代码并不一定总是能正常运行。

ps:点击链接加小编Python学习秋秋群,群里有免费的视频教程,开发工具、电子书籍分享。专业的老师答疑!学习python web、python爬虫、数据分析、大数据,人工智能等技术有不懂的可以加入一起交流学习,一起进步!

项目源码

# -*- coding: utf-8 -*-

"""
JD online shopping helper tool
-----------------------------------------------------
only support to login by QR code, 
username / password is not working now.
"""


import bs4
import requests, requests.utils, pickle
import requests.packages.urllib3
requests.packages.urllib3.disable_warnings()

import os
import time
import json
import random


import argparse
#from selenium import webdriver


import sys
reload(sys)
sys.setdefaultencoding('utf-8')

# get function name
FuncName = lambda n=0: sys._getframe(n + 1).f_code.co_name


def tags_val(tag, key='', index=0):
    '''
    return html tag list attribute @key @index
    if @key is empty, return tag content
    '''
    if len(tag) == 0 or len(tag) <= index:
        return ''
    elif key:
        txt = tag[index].get(key)
        return txt.strip(' trn') if txt else ''
    else:
        txt = tag[index].text
        return txt.strip(' trn') if txt else ''


def tag_val(tag, key=''):
    '''
    return html tag attribute @key
    if @key is empty, return tag content
    '''
    if tag is None: 
        return ''
    elif key:
        txt = tag.get(key)
        return txt.strip(' trn') if txt else ''
    else:
        txt = tag.text
        return txt.strip(' trn') if txt else ''


class JDWrapper(object):
    '''
    This class used to simulate login JD
    '''
    
    def __init__(self, usr_name=None, usr_pwd=None):
        # cookie info
        self.trackid = ''
        self.uuid = ''
        self.eid = ''
        self.fp = ''

        self.usr_name = usr_name
        self.usr_pwd = usr_pwd

        self.interval = 0

        # init url related
        self.home = 'https://passport.jd.com/new/login.aspx'
        self.login = 'https://passport.jd.com/uc/loginService'
        self.imag = 'https://authcode.jd.com/verify/image'
        self.auth = 'https://passport.jd.com/uc/showAuthCode'
        
        self.sess = requests.Session()

        self.headers = {
            'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36',
            'ContentType': 'text/html; charset=utf-8',
            'Accept-Encoding':'gzip, deflate, sdch',
            'Accept-Language':'zh-CN,zh;q=0.8',
            'Connection' : 'keep-alive',
        }
        
        self.cookies = {

        }

        '''
        try:
            self.browser = webdriver.PhantomJS('phantomjs.exe')
        except Exception, e:
            print 'Phantomjs initialize failed :', e
            exit(1)
        '''
        
    @staticmethod
    def print_json(resp_text):
        '''
        format the response content
        '''
        if resp_text[0] == '(':
            resp_text = resp_text[1:-1]
        
        for k,v in json.loads(resp_text).items():
            print u'%s : %s' % (k, v)

    @staticmethod
    def response_status(resp):
        if resp.status_code != requests.codes.OK:
            print 'Status: %u, Url: %s' % (resp.status_code, resp.url)
            return False
        return True

    def _need_auth_code(self, usr_name):
        # check if need auth code
        # 
        auth_dat = {
            'loginName': usr_name,
        }
        payload = {
            'r' : random.random(),
            'version' : 2015
        }
        
        resp = self.sess.post(self.auth, data=auth_dat, params=payload)
        if self.response_status(resp) : 
            js = json.loads(resp.text[1:-1])
            return js['verifycode']

        print u'获取是否需要验证码失败'
        return False

    def _get_auth_code(self, uuid):
        # image save path
        image_file = os.path.join(os.getcwd(), 'authcode.jfif')
            
        payload = {
            'a' : 1,
            'acid' : uuid,
            'uid' : uuid,
            'yys' : str(int(time.time() * 1000)),
        }
            
        # get auth code
        r = self.sess.get(self.imag, params=payload)
        if not self.response_status(r):
            print u'获取验证码失败'
            return False

        with open (image_file, 'wb') as f:
            for chunk in r.iter_content(chunk_size=1024):
                f.write(chunk)
                        
            f.close()
        
        os.system('start ' + image_file)
        return str(raw_input('Auth Code: '))

    def _login_once(self, login_data):
        # url parameter
        payload = {
            'r': random.random(),
            'uuid' : login_data['uuid'],
            'version' : 2015,
        }
        
        resp = self.sess.post(self.login, data=login_data, params=payload)
        if self.response_status(resp):
            js = json.loads(resp.text[1:-1])
            #self.print_json(resp.text)
            
            if not js.get('success') :
                print  js.get('emptyAuthcode')
                return False
            else:
                return True

        return False

    def _login_try(self):
        """ login by username and password, but not working now.
        
        .. deprecated::
            Use `login_by_QR`
        """
        # get login page
        #resp = self.sess.get(self.home)
        print '+++++++++++++++++++++++++++++++++++++++++++++++++++++++'
        print u'{0} > 登陆'.format(time.ctime())

        try:
            # 2016/09/17 PhantomJS can't login anymore
            self.browser.get(self.home)
            soup = bs4.BeautifulSoup(self.browser.page_source, "html.parser")
            
            # set cookies from PhantomJS
            for cookie in self.browser.get_cookies():
                self.sess.cookies[cookie['name']] = str(cookie['value'])

            #for (k, v) in self.sess.cookies.items():
            #    print '%s: %s' % (k, v)
                
            # response data hidden input == 9 ??. Changed 
            inputs = soup.select('form#formlogin input[type=hidden]')
            rand_name = inputs[-1]['name']
            rand_data = inputs[-1]['value']
            token = ''

            for idx in range(len(inputs) - 1):
                id = inputs[idx]['id']
                va = inputs[idx]['value']
                if   id == 'token':
                    token = va
                elif id == 'uuid':
                    self.uuid = va
                elif id == 'eid':
                    self.eid = va
                elif id == 'sessionId':
                    self.fp = va
            
            auth_code = ''
            if self.need_auth_code(self.usr_name):
                auth_code = self.get_auth_code(self.uuid)    
            else:
                print u'无验证码登陆'
            
            login_data = {
                '_t': token,
                'authcode': auth_code,
                'chkRememberMe': 'on',
                'loginType': 'f',
                'uuid': self.uuid,
                'eid': self.eid,
                'fp': self.fp,
                'nloginpwd': self.usr_pwd,
                'loginname': self.usr_name,
                'loginpwd': self.usr_pwd,
                rand_name : rand_data,
            }
            
            login_succeed = self.login_once(login_data)
            if login_succeed:
                self.trackid = self.sess.cookies['TrackID']
                print u'登陆成功 %s' % self.usr_name
            else:        
                print u'登陆失败 %s' % self.usr_name    

            return login_succeed

        except Exception, e:
            print 'Exception:', e.message
            raise
        finally:
            self.browser.quit()

        return False
    
    def checkLogin(self):
        checkUrl = 'https://passport.jd.com/uc/qrCodeTicketValidation'

        try:
            print '+++++++++++++++++++++++++++++++++++++++++++++++++++++++'
            print u'{0} > 自动登录中... '.format(time.ctime())
            with open('cookie', 'rb') as f:
                cookies = requests.utils.cookiejar_from_dict(pickle.load(f))
                resp = requests.get(checkUrl, cookies=cookies)

                if resp.status_code != requests.codes.OK:
                    print u'登录过期, 请重新登录!'
                    return False
                else:
                    return True

            return False
        except Exception as e:
            return False
        else:
            pass
        finally:
            pass

        return False
    
    def login_by_QR(self):
        # jd login by QR code
        try:
            print '+++++++++++++++++++++++++++++++++++++++++++++++++++++++'
            print u'{0} > 请打开京东手机客户端,准备扫码登陆:'.format(time.ctime())

            urls = (
                'https://passport.jd.com/new/login.aspx',
                'https://qr.m.jd.com/show',
                'https://qr.m.jd.com/check',
                'https://passport.jd.com/uc/qrCodeTicketValidation'
            )

            # step 1: open login page
            resp = self.sess.get(
                urls[0], 
                headers = self.headers
            )
            if resp.status_code != requests.codes.OK:
                print u'获取登录页失败: %u' % resp.status_code
                return False

            ## save cookies
            for k, v in resp.cookies.items():
                self.cookies[k] = v
            

            # step 2: get QR image
            resp = self.sess.get(
                urls[1], 
                headers = self.headers,
                cookies = self.cookies,
                params = {
                    'appid': 133,
                    'size': 147,
                    't': (long)(time.time() * 1000)
                }
            )
            if resp.status_code != requests.codes.OK:
                print u'获取二维码失败: %u' % resp.status_code
                return False

            ## save cookies
            for k, v in resp.cookies.items():
                self.cookies[k] = v

            ## save QR code
            image_file = 'qr.png'
            with open (image_file, 'wb') as f:
                for chunk in resp.iter_content(chunk_size=1024):
                    f.write(chunk)
            
            ## scan QR code with phone
            if os.name == "nt": 
                # for windows
                os.system('start ' + image_file)
            else:
                if os.uname()[0] == "Linux":
                    # for linux platform
                    os.system("eog " + image_file)
                else:
                    # for Mac platform
                    os.system("open " + image_file)

            # step 3: check scan result
            ## mush have
            self.headers['Host'] = 'qr.m.jd.com' 
            self.headers['Referer'] = 'https://passport.jd.com/new/login.aspx'

            # check if QR code scanned
            qr_ticket = None
            retry_times = 100
            while retry_times:
                retry_times -= 1
                resp = self.sess.get(
                    urls[2],
                    headers = self.headers,
                    cookies = self.cookies,
                    params = {
                        'callback': 'jQuery%u' % random.randint(100000, 999999),
                        'appid': 133,
                        'token': self.cookies['wlfstk_smdl'],
                        '_': (long)(time.time() * 1000)
                    }
                )

                if resp.status_code != requests.codes.OK:
                    continue

                n1 = resp.text.find('(')
                n2 = resp.text.find(')')
                rs = json.loads(resp.text[n1+1:n2])

                if rs['code'] == 200:
                    print u'{} : {}'.format(rs['code'], rs['ticket'])
                    qr_ticket = rs['ticket']
                    break
                else:
                    print u'{} : {}'.format(rs['code'], rs['msg'])
                    time.sleep(3)
            
            if not qr_ticket:
                print u'二维码登陆失败'
                return False
            
            # step 4: validate scan result
            ## must have
            self.headers['Host'] = 'passport.jd.com'
            self.headers['Referer'] = 'https://passport.jd.com/uc/login?ltype=logout'
            resp = self.sess.get(
                urls[3], 
                headers = self.headers,
                cookies = self.cookies,
                params = {'t' : qr_ticket },
            )
            if resp.status_code != requests.codes.OK:
                print u'二维码登陆校验失败: %u' % resp.status_code
                return False
            
            ## 京东有时候会认为当前登录有危险,需要手动验证
            ## url: https://safe.jd.com/dangerousVerify/index.action?username=...
            res = json.loads(resp.text)
            if not resp.headers.get('P3P'):
                if res.has_key('url'):
                    print u'需要手动安全验证: {0}'.format(res['url'])
                    return False
                else:
                    print_json(res)
                    print u'登陆失败!!'
                    return False
            
            ## login succeed
            self.headers['P3P'] = resp.headers.get('P3P')
            for k, v in resp.cookies.items():
                self.cookies[k] = v

            with open('cookie', 'wb') as f:
                pickle.dump(self.cookies, f)

            print u'登陆成功'
            return True
        
        except Exception as e:
            print 'Exp:', e
            raise

        return False

    
    def good_stock(self, stock_id, good_count=1, area_id=None):
        '''
        33 : on sale, 
        34 : out of stock
        '''
        # http://ss.jd.com/ss/areaStockState/mget?app=cart_pc&ch=1&skuNum=3180350,1&area=1,72,2799,0
        #   response: {"3180350":{"a":"34","b":"1","c":"-1"}}
        #stock_url = 'http://ss.jd.com/ss/areaStockState/mget' 

        # http://c0.3.cn/stocks?callback=jQuery2289454&type=getstocks&skuIds=3133811&area=1_72_2799_0&_=1490694504044
        #   jQuery2289454({"3133811":{"StockState":33,"freshEdi":null,"skuState":1,"PopType":0,"sidDely":"40","channel":1,"StockStateName":"现货","rid":null,"rfg":0,"ArrivalDate":"","IsPurchase":true,"rn":-1}})
        # jsonp or json both work
        stock_url = 'https://c0.3.cn/stocks' 

        payload = {
            'type' : 'getstocks',
            'skuIds' : str(stock_id),
            'area' : area_id or '1_72_2799_0', # area change as needed
        }
        
        try:
            # get stock state
            resp = self.sess.get(stock_url, params=payload)
            if not self.response_status(resp):
                print u'获取商品库存失败'
                return (0, '')
            
            # return json
            resp.encoding = 'gbk' 
            stock_info = json.loads(resp.text)
            stock_stat = int(stock_info[stock_id]['StockState'])
            stock_stat_name = stock_info[stock_id]['StockStateName']
            
            # 33 : on sale, 34 : out of stock, 36: presell
            return stock_stat, stock_stat_name

        except Exception as e:
            print 'Stocks Exception:', e
            time.sleep(5)

        return (0, '')

    
    def good_detail(self, stock_id, area_id=None):
        # return good detail
        good_data = {
            'id' : stock_id,
            'name' : '',
            'link' : '',
            'price' : '',
            'stock' : '',
            'stockName': '',
        }
        
        try:
            # shop page
            stock_link = 'http://item.jd.com/{0}.html'.format(stock_id)
            resp = self.sess.get(stock_link)

            # good page
            soup = bs4.BeautifulSoup(resp.text, "html.parser")
            
            # good name
            tags = soup.select('div#name h1')
            if len(tags) == 0:
                tags = soup.select('div.sku-name')
            good_data['name'] = tags_val(tags).strip(' trn')

            # cart link
            tags = soup.select('a#InitCartUrl')
            link = tags_val(tags, key='href')
            
            if link[:2] == '//': link = 'http:' + link
            good_data['link'] = link
        
        except Exception, e:
            print 'Exp {0} : {1}'.format(FuncName(), e)

        # good price
        good_data['price'] = self.good_price(stock_id)
        
        # good stock
        good_data['stock'], good_data['stockName'] = self.good_stock(stock_id=stock_id, area_id=area_id)
        #stock_str = u'有货' if good_data['stock'] == 33 else u'无货'
        
        print '+++++++++++++++++++++++++++++++++++++++++++++++++++++++'
        print u'{0} > 商品详情'.format(time.ctime())
        print u'编号:{0}'.format(good_data['id'])
        print u'库存:{0}'.format(good_data['stockName'])
        print u'价格:{0}'.format(good_data['price'])
        print u'名称:{0}'.format(good_data['name'])
        #print u'链接:{0}'.format(good_data['link'])
        
        return good_data
        

    def good_price(self, stock_id):
        # get good price
        url = 'http://p.3.cn/prices/mgets'
        payload = {
            'type'   : 1,
            'pduid'  : int(time.time() * 1000),
            'skuIds' : 'J_' + stock_id,
        }
        
        price = '?'
        try:
            resp = self.sess.get(url, params=payload)
            resp_txt = resp.text.strip()
            #print resp_txt

            js = json.loads(resp_txt[1:-1])
            #print u'价格', 'P: {0}, M: {1}'.format(js['p'], js['m'])
            price = js.get('p')

        except Exception, e:
            print 'Exp {0} : {1}'.format(FuncName(), e)

        return price
    

    def buy(self, options):
        # stock detail
        good_data = self.good_detail(options.good)

        # retry until stock not empty
        if good_data['stock'] != 33:
            # flush stock state
            while good_data['stock'] != 33 and options.flush:
                print u'<%s> <%s>' % (good_data['stockName'], good_data['name'])
                time.sleep(options.wait / 1000.0)
                good_data['stock'], good_data['stockName'] = self.good_stock(stock_id=options.good, area_id=options.area)
                
            # retry detail
            #good_data = self.good_detail(options.good)
            

        # failed 
        link = good_data['link']
        if good_data['stock'] != 33 or link == '':
            #print u'stock {0}, link {1}'.format(good_data['stock'], link)
            return False

        try:
            # change buy count
            if options.count != 1:
                link = link.replace('pcount=1', 'pcount={0}'.format(options.count))

            # add to cart
            resp = self.sess.get(link, cookies = self.cookies)
            soup = bs4.BeautifulSoup(resp.text, "html.parser")

            # tag if add to cart succeed
            tag = soup.select('h3.ftx-02')
            if tag is None:
                tag = soup.select('div.p-name a')

            if tag is None or len(tag) == 0:
                print u'添加到购物车失败'
                return False
            
            print '+++++++++++++++++++++++++++++++++++++++++++++++++++++++'
            print u'{0} > 购买详情'.format(time.ctime())
            print u'链接:{0}'.format(link)
            print u'结果:{0}'.format(tags_val(tag))

            # change count after add to shopping cart
            #self.buy_good_count(options.good, options.count)
            
        except Exception, e:
            print 'Exp {0} : {1}'.format(FuncName(), e)
        else:
            self.cart_detail()
            return self.order_info(options.submit)

        return False

    def buy_good_count(self, good_id, count):
        url = 'http://cart.jd.com/changeNum.action'

        payload = {
            'venderId': '8888',
            'pid': good_id,
            'pcount': count,
            'ptype': '1',
            'targetId': '0',
            'promoID':'0',
            'outSkus': '',
            'random': random.random(),
            'locationId':'1-72-2799-0',  # need changed to your area location id
        }

        try:
            rs = self.sess.post(url, params = payload, cookies = self.cookies)
            if rs.status_code == 200:
                js = json.loads(rs.text)
                if js.get('pcount'):
                    print u'数量:%s @ %s' % (js['pcount'], js['pid'])
                    return True
            else:
                print u'购买 %d 失败' % count
                
        except Exception, e:
            print 'Exp {0} : {1}'.format(FuncName(), e)

        return False

        
    def cart_detail(self):
        # list all goods detail in cart
        cart_url = 'https://cart.jd.com/cart.action'
        cart_header = u'购买    数量    价格        总价        商品'
        cart_format = u'{0:8}{1:8}{2:12}{3:12}{4}'
        
        try:    
            resp = self.sess.get(cart_url, cookies = self.cookies)
            resp.encoding = 'utf-8'
            soup = bs4.BeautifulSoup(resp.text, "html.parser")
            
            print '+++++++++++++++++++++++++++++++++++++++++++++++++++++++'
            print u'{0} > 购物车明细'.format(time.ctime())
            print cart_header
            
            for item in soup.select('div.item-form'):
                check = tags_val(item.select('div.cart-checkbox input'), key='checked')
                check = ' + ' if check else ' - '
                count = tags_val(item.select('div.quantity-form input'), key='value')
                price = tags_val(item.select('div.p-price strong'))        
                sums  = tags_val(item.select('div.p-sum strong'))
                gname = tags_val(item.select('div.p-name a'))
                #: ¥字符解析出错, 输出忽略¥
                print cart_format.format(check, count, price[1:], sums[1:], gname)

            t_count = tags_val(soup.select('div.amount-sum em'))
            t_value = tags_val(soup.select('span.sumPrice em'))
            print u'总数: {0}'.format(t_count)
            print u'总额: {0}'.format(t_value[1:])

        except Exception, e:
            print 'Exp {0} : {1}'.format(FuncName(), e)


    def order_info(self, submit=False):
        # get order info detail, and submit order
        print '+++++++++++++++++++++++++++++++++++++++++++++++++++++++'
        print u'{0} > 订单详情'.format(time.ctime())

        try:
            order_url = 'http://trade.jd.com/shopping/order/getOrderInfo.action'
            payload = {
                'rid' : str(int(time.time() * 1000)), 
            }

            # get preorder page
            rs = self.sess.get(order_url, params=payload, cookies = self.cookies)
            soup = bs4.BeautifulSoup(rs.text, "html.parser")

            # order summary
            payment = tag_val(soup.find(id='sumPayPriceId'))
            detail = soup.find(class_='fc-consignee-info')

            if detail:
                snd_usr = tag_val(detail.find(id='sendMobile'))
                snd_add = tag_val(detail.find(id='sendAddr'))

                print u'应付款:{0}'.format(payment)
                print snd_usr
                print snd_add

            # just test, not real order
            if not submit:
                return False

            # order info
            payload = {
                'overseaPurchaseCookies': '',
                'submitOrderParam.btSupport': '1',
                'submitOrderParam.ignorePriceChange': '0',
                'submitOrderParam.sopNotPutInvoice': 'false',
                'submitOrderParam.trackID': self.trackid,
                'submitOrderParam.eid': self.eid,
                'submitOrderParam.fp': self.fp,
            }
            
            order_url = 'http://trade.jd.com/shopping/order/submitOrder.action'
            rp = self.sess.post(order_url, params=payload, cookies = self.cookies)

            if rp.status_code == 200:
                js = json.loads(rp.text)
                if js['success'] == True:
                    print u'下单成功!订单号:{0}'.format(js['orderId'])
                    print u'请前往东京官方商城付款'
                    return True
                else:
                    print u'下单失败!<{0}: {1}>'.format(js['resultCode'], js['message'])
                    if js['resultCode'] == '60017':
                        # 60017: 您多次提交过快,请稍后再试
                        time.sleep(1)
            else:
                print u'请求失败. StatusCode:', rp.status_code
        
        except Exception, e:
            print 'Exp {0} : {1}'.format(FuncName(), e)

        return False


def main(options):
    # 
    jd = JDWrapper()
    if not jd.checkLogin():
        if not jd.login_by_QR():
            return

    while not jd.buy(options) and options.flush:
        time.sleep(options.wait / 1000.0)


if __name__ == '__main__':
    # help message
    parser = argparse.ArgumentParser(description='Simulate to login Jing Dong, and buy sepecified good')
    #parser.add_argument('-u', '--username', 
    #                    help='Jing Dong login user name', default='')
    #parser.add_argument('-p', '--password', 
    #                    help='Jing Dong login user password', default='')
    parser.add_argument('-a', '--area', 
                        help='Area string, like: 1_72_2799_0 for Beijing', default='1_72_2799_0')    
    parser.add_argument('-g', '--good', 
                        help='Jing Dong good ID', default='')
    parser.add_argument('-c', '--count', type=int, 
                        help='The count to buy', default=1)
    parser.add_argument('-w', '--wait', 
                        type=int, default=500,
                        help='Flush time interval, unit MS')
    parser.add_argument('-f', '--flush', 
                        action='store_true', 
                        help='Continue flash if good out of stock')
    parser.add_argument('-s', '--submit', 
                        action='store_true',
                        help='Submit the order to Jing Dong')
                
    # example goods
    hw_watch = '2567304'
    iphone_7 = '3133851'
    
    options = parser.parse_args()
    print options
  
    # for test
    if options.good == '':
        options.good = iphone_7
    
    '''
    if options.password == '' or options.username == '':
        print u'请输入用户名密码'
        exit(1)
    '''
    main(options)
    
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

jd抢购工具_Python爬虫教程,京东自动登录,在线抢购商品 的相关文章

  • CH06_第一组重构(下)

    封装变量 Encapsulate Variable 132 曾用名 自封装字段 Self Encapsulate Field 曾用名 封装字段 Encapsulate Field let defaultOwner firstName Mar
  • C++的强制类型转换

    关于强制类型转换的问题 很多书都讨论过 写的最详细的是C 之父的 C 的设计和演化 最好的解决方法就是不要使用C风格的强制类型转换 而是使用标准C 的类型转换符 static cast dynamic cast 标准C 中有四个类型转换符
  • 在docker上安装spark

    拉安装好spark的镜像 https hub docker com r bde2020 spark master docker pull bde2020 spark master 安装master节点 docker run name spa
  • SpringBoot 整合shiro框架

    网上有很多整合shiro的博客分享 但是貌似没找到一个完整 并且能够实现的 不是包的问题 就是代码的问题 也可能是自己的问题 或者版本的问题 所以 整理了一版自己已应用的 maven依赖
  • Netty 入门实战

    Netty 入门实战 异步事件驱动的Java开源网络应用程序框架 用于快速开发可维护的高性能协议服务器和客户端 Netty 项目旨在为可维护的高性能和高可伸缩性协议服务器和客户端的快速开发提供一个异步事件驱动的网络应用框架和工具 Netty
  • Kafka概述

    Kafka概述 Kafka 基础架构 生产者消息发送流程 生产者发送消息示例 分区的好处 生产者如何提高吞吐量 可靠性总结 幂等性问题 Kafka 事务 生产者乱序问题 kafka是一个多分区 多副本且基于zookeeper协调的分布式消息
  • wsl连接vscode

    文章目录 1 wsl 安装 2 wsl搭配vscode 3 adb 在wsl上的使用 1 wsl 安装 由于我已经提前安装了 所以这里没办法展示如何安装 大致有两个需要注意的点 在官网或者其它博文有 1 需要在命令行输入安装命令 2 需要下
  • python-循环

    文章目录 循环 是什么 定义 分类 做什么 怎么用 语法 If 语法 If 基本语法 If else if elif else 结构 if 嵌套 while 语法 while 基本语法 while else while else break
  • 费曼学习法简述

    你真的已经对某个知识点足够深入了吗 还是只是停留在一个肤浅的阶段 不妨试试费曼学习法 让自己的思考更加深入 费曼学习法 主要分为四个阶段 下面针对这四个步骤进行详述 选择概念 选择一个你想学习的概念 讲授概念 你对面的是一个10岁孩童 试图
  • 操作系统复习知识点(第四章、第五章)

    存储器管理 1 多层结构的存储器系统 存储器的多层结构 存储层次至少应具有三级 最高层为 CPU 寄存器 中间为主存 最底层是辅存 还可以根据具体的功能分工细划为寄存器 高速缓存 主存储器 磁盘缓存 固定磁盘 可移动存储介质等 6 层 在存
  • Mad Scientist (纯模拟题)

    Mad Scientist 题目描述 Farmer John s cousin Ben happens to be a mad scientist Normally this creates a good bit of friction a
  • QT--3.创建一个简单的图形界面

    创建一个简单的图形界面 1 qt基础 qt的移植性非常强 2 做一个简单的qt界面 1 创建一个工程 2 项目选择Application 然后选择Qt Widgets Application 最后选择choose 注意 创建项目的名称和路径
  • 对象池简单理解

    unity中一些需要频繁创建和销毁的对象 在销毁时会频繁的调用gc 非常占用cpu时 造成性能瓶颈 这时候就需要对象池技术 使用对象池在销毁时并不调用gc 而是仅仅将需要销毁的obj失活 当再次创建同类对象时 在对象池中查找可以使用的对象进
  • C语言练习——输出字符串长度

    输出字符串长度 题目描述 代码实现 方法一 方法二 方法三 方法四 题目描述 写一个函数 求一个字符串的长度 在 main 函数中输入字符串 并输出其长度 代码实现 方法一 include
  • linux oracle 临时空间不足,oracle for linux服务器磁盘空间不足,通过过期的文件释放磁盘空间...

    2013 09 16截取的数据 使用df h命令查看系统磁盘空间 root erpdbs PROD df h Filesystem Size Used Avail Use Mounted on dev sda5 4 9G 241M 4 4G
  • CCPC2019河南省省赛总结:lwh

    之前的邀请赛突然变成省赛 多了次拿牌的机会 还挺开心的 然后旷了2节课和队友去打了网络赛 成绩还不错 应该能够拿个金 然后就是现场赛了 不知道什么原因 现场赛开始前推迟了20分钟 比赛开始 开始一眼望过去 学长选了题 签到题直接敲 样例过了
  • mysql 列名映射_[Mybatis] Mybatis处理列名->字段名映射(二) - AS用法 & ResultMap

    前言 考虑到在Select时使用AS和方案一其实没什么差别 在介绍ResultMap之前 顺便带过一下 方案二 Select AS 当我们的数据库列名和对象字段之间不是驼峰式命名的关系 我们可以在Select时使用AS 使得列名和对象名匹配
  • BTY Ecosystem DNS‘s Ideas of DeSoc

    In May 2022 Ethereum founder Vitalik Buterin economist Glen Weyl and Flashbots researcher Puja Ohlhaver jointly released
  • vue前端上传文件到COS

    1 main js中 COS相关的 Vue prototype loadi https images 1254950508 cos ap guangzhou myqcloud com a 1588390454918 loading gif

随机推荐

  • 计算机网络重点知识解析(1)

    总结一下计算机网络知识 文章目录 OSI七层网络协议 TCP IP协议模型 TCP协议 UDP协议 TCP和UDP协议的区别 RTT和RTO TCP的滑动窗口 TCP 拥塞控制 OSI七层网络协议 先来一张网络协议图 简单解释一下各个协议
  • 64位和32位相比优势是什么(一)

    前置知识 程序是如何执行的 一道常规的面试题 相比 32 位 64 位的优势是什么 面试官考察这种类型的问题 主要是想看求职者是否有扎实的计算机基础 同时想知道求职者在工作中是否充满好奇 会主动学习 寻根问底 毕竟 32 64 位是经常出现
  • [MATLAB]学习笔记

    目录 第一章 Matlab基础 1 1 Matlab介绍 1 2 界面使用 1 3 运算基础 1 4 数据基础 1 5 矩阵基础 第一章 Matlab基础 1 1 Matlab介绍 一 最新版本 MathWorks MATLAB R2021
  • Python和Java二选一该学啥?

    Java这种跨平台 可面向对象的编程语言完美解释了它不仅仅只是一种语言 而且自身很强大是一种开发平台 第一 学习过的大家可能都知道它的优势和特性有哪些 比如说它简单性 面向对象 分布式 解释型 可靠 安全 平台无关 可移植 高性能 多线程
  • 分享Visual Studio 2019专业版、企业版密匙

    官网下载地址 https visualstudio microsoft com zh hans downloads 点击进入 Professional产品密钥 NYWVH HT4XC R2WYW 9Y3CM X4V3Y Enterprise
  • 零基础初学前端—新建项目

    对于一个没有基础的新手来说 如何使用 vscode 新建一个前端项目 写一些html页面 并能进行运行 需要吐下几个步骤 新建一个文件夹 在文件夹里新建一个文件 命名为 xxx html 例如 index html 打开 vscode Fi
  • 【Windows】Windows下载使用wget命令

    文章目录 一 前言 介绍 二 安装步骤 2 1 下载 wget 压缩包 2 2 解压到指定的位置 2 3 检查是否安装成功 2 4 是否可以正常下载 一 前言 介绍 wget 是 linux 一个下载文件的工具 可以下载一些软件或从远程服务
  • centos7常用工具包安装

    1 nano yum install y nano 2 wget yum install y wget
  • MySQL的“插入”/“删除+插入”操作——REPLACE

    问题及背景 有一个数据表Table 主键为YYYY MM DD 年 月 日 形式的字符串 存储着本日某事件的信息 该信息每隔若干小时 会根据最新数据重新计算该信息 如果Table中已存在本日记录 需要对其进行 UPDATE 或 DELATE
  • 模型化公务员能力

    1 搜集信息 现象 在较大的行政管理对象中 信息失真是普遍现象 误区 地方统计上报的数据 只要各级管理人员认真负责 严格核实 怎么会有错误 对策 建立及时 真实 全面 立体的信息搜集和分析机制 2 办理公文 现象 领导的批示和交办的事项 往
  • Java System.arraycopy()方法示例

    Java System arraycopy is a native static method to copy elements from the source array to the destination array Java Sys
  • SQLserver 2008数据库迁移 - 导出 方法二 备份法

    前言 由于更换服务器 所以需要对数据库进行备份 到新服务器还原 收到数据库迁移的命令 登上服务器一看 一脸懵B SQLServer 2008完全没用过 于是开始查资料 各种百度 CSDN一顿查 方法一 保存脚本法 点此链接了解详情 方法二
  • keil报错:Symbol set_value multiply define和 incomplete type is not allowed和error:  #65: expected a “;“

    一个是重复定义 一个是不完整类型 一个是缺一个 第一个 重复定义 一般最多的就是两个文件中的变量定义重复而报错 一般这种改一下名就差不多了 而另一种就比较难看出来了 比如 定义一个结构体在sys h的文件中 并在文件中进行了定义和初始化 然
  • Formality流程

    Formality流程 前言 一 formality是什么 二 使用步骤 0 打开formality的gui界面 1 导入svf文件 2 读入verilog文件 3 读入网表文件 4 setup 5 match and verify 6 注
  • 安装 Media Player 11验证最简单的解决方案

    MS说打补丁 我就让它打 结果给我升到了11 还要验证 不爽 搞了半天 最后找到解决方案 好简单将C Program Files Windows Media Player LegitLibM dll改名为legitlib dll 打开Med
  • python网络爬虫模块

    re模块 想在python中使用正则表达式 可以使用re模块来辅助筛选 1 findall 查找数据中所有符合条件的数值 最后的结果以列表形式输出 贪婪匹配 import re res re findall l hello l l 2 fi
  • JavaEE学习 day09

    今天 继续学习了JavaEE 继续做SSM图书管理系统项目 SSM图书管理系统 修改用户 显示修改数据 SSM图书管理系统 修改用户 userid隐藏域 SSM图书管理系统 修改用户 与新增共用一个方法 SSM图书管理系统 删除用户 总结一
  • Python 批量处理PNG、JPG图片 去白边

    每次写论文用seaborn画出来的图白边都很大并且没法调 每次都用PS软件去白边很麻烦 索性写了个脚本 在不改变图片像素密度 尺寸变了 相当于切割 的情况下 批量去掉图片白边 参考了部分网上的程序 自己写了个简单的脚本 放到一个Python
  • python中isalpha的用法_Python string isalpha()用法及代码示例

    在Python中 isalpha 是用于字符串处理的内置方法 如果字符串中的所有字符都是字母 则isalpha 方法返回 True 否则 返回 False 此函数用于检查参数是否包含任何字母字符 例如 ABCDEFGHIJKLMNOPQRS
  • jd抢购工具_Python爬虫教程,京东自动登录,在线抢购商品

    京东抢购 Python爬虫 自动录京东网站 查询商品库存 价格 显示购物车详情等 可以指定抢购商品 自动购买下单 然后手动去京东付款就行 chang log 2017 03 30 实现二维码扫码登陆 2017 06 27 Golang版JD