Taobaosnap

HSCSEC

某宝抢购脚本

Taobaosnap

Taobaosnap is a completely open tool, which is used to buy goods in seconds on Taobao. This is a project created with python, using selenium and requests module to achieve login and snap-up. The project integrates network script ideas and improves them, using selenium to realize remote login and login verification problems. Use requests for snapping without rendering, reducing the time required for access and snapping. Use the countdown idea to realize automatic snapping when the time is up. The number of times of use is set, which is convenient for reading and analyzing the program log after the snap-up is over.(This description is for versions higher than 3.1.5)

关于Taobaosnap的介绍描述已经在项目的readme.md写的非常详细了,大家可自行访问开源项目查看。(代码已于git托管并开源)

项目开发经历

基于笔者对于手动抢购一周仍一墩无购的情况,我们在网络上找到了两位开发者写的抢购脚本。

requests方案

1.来自’Charles的比卡丘‘的程序使用python开发,使用requests模块,以requests的方式获取登录二维码进行扫码登陆后直接进行购物车信息获取,选择并抢购。该代码使用了request请求的方式直接进行抢购.

优点:访问速度快,无需渲染。

缺点:容易触发反爬虫(经大量数据测试,极大多数情况下前四次正常,第五次无法获取购物车信息),登录遇到二次校验或三次校验(二次校验概率非常高,三次校验概率较低。该情况会导致部分账号无法登录),抢购第四五次会触发校验。

selenium+webdriver方案

2.来自‘SWHL’师傅的程序同样使用python开发,使用selenium模块,以webdriver的形式自动打开浏览器,使用浏览器自动操做。该项目使用了读秒的方式计算抢购开始时间,抢购以自动化可视化操做提交订单。

优点:解决了登录校验的问题,能够完成或多次登的录校验。读秒抢购,减少请求次数。 缺点:访问速度慢,页面访问需要渲染,对于网络速度的要求相对较高。

下面我们来分析一下某宝的反爬虫策略

selenium抓取一个网站的时候,容易被识别为爬虫。我们来分析一下识别点:

  1. 账号密码或手机号登录容易触发反爬虫机制。

  2. 某宝官方提取浏览器驱动的指纹特征,比如chromedriver,firefox的webdriver,edge的msedgedriver。

  3. 重复提交登录申请而未完成登录校验。

  4. 多次提交订单而未完成校验。

反爬虫与应对策略

  1. 使用扫码登录并完成多次校验,避免登录过程被反爬。

  2. 经过测试发现,chrome的selenium疑似规避了反爬虫策略了。linux系统下使用geckodriver不会触发反爬虫。

  3. 由于此处使用webdriver会导致抢购速度慢,需要等待页面渲染。requests不便实现 再次使用webdriver弹出校验。该问题目前暂无良好解决方案。

此处可以参考使用 mitmproxy 蔽掉识别 webdriver 标识符的 js 文件。

  1. 设置抢购开始时间,读秒并与系统时间比对。同时设置抢购次数(测试建议五次)。

理论与思路

  1. 使用selenium模块与webdriver调用chromedriver完成登录与登录校验。

  2. 将selenium登陆完后获取列表形式的cookie转换为requests请求字典形式cookie,并使用requests方案获取购物车信息。

  3. 使用读秒思路比对抢购时间,设置抢购次数限制,减少反爬虫触犯几率。

优点:解决登录校验的问题,完成或多次登的录校验。读秒抢购,减少请求次数。访问速度快,无需渲染。不易触发反爬虫机制。 缺点:requests不便实现 再次使用webdriver弹出校验。

项目思路

登录

使用selenium库与webdriver实现图形化登录,以解决requests登录方式无法完成登录验证的问题。

def cookie_info():
    chrome_options = webdriver.ChromeOptions()
    chrome_options.add_argument("start-maximized")

    login_url = 'https://login.taobao.com/member/login.jhtml?spm=a21bo.jianhua.201864-2.d1.5af911d9lhGWni&f=top&redirectURL=http%3A%2F%2Fwww.taobao.com%2F'
    driver = webdriver.Chrome(options=chrome_options)
    print("请尽快扫码!")
    driver.get(login_url)
    time.sleep(15)  # 预留了安全验证的时间
    driver.refresh()    # 刷新页面
    c = driver.get_cookies()
    sessions = dict()
    for cookie in c:
        sessions[cookie['name']] = cookie['value']
    #driver.quit()
    return sessions

经多次测试,安全验证时间采用15s停留,以应对二次校验。

命令参数解析

def parseArgs():
    parser = argparse.ArgumentParser(description='抢购脚本')
    parser.add_argument('--time', dest='time', help='秒杀时间', type=str, required=True)
    parser.add_argument('--interval', dest='interval', help='抢购商品的时间间隔(单位秒)', type=float, required=True)
    parser.add_argument('--l', dest='number', help='抢购商品的次数', type=int, required=True)
    args = parser.parse_args()
    return args

获取购物车

def buycartinfo(self):
        url = 'https://cart.taobao.com/cart.htm'
        headers = {
            'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36',
            'sec-fetch-dest': 'document', 'sec-fetch-mode': 'navigate', 'sec-fetch-site': 'none', 'sec-fetch-user': '?1',
            'upgrade-insecure-requests': '1',
            'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
            'accept-encoding': 'gzip, deflate, br', 'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8',
            'cache-control': 'max-age=0'
        }
        response = self.session.get(url, headers=headers)
        # print(response.text)
        response_json = re.search('try{var firstData = (.*?);}catch', response.text).group(1)
        response_json = json.loads(response_json)
        user_id = re.search('\|\^taoMainUser:(.*?):\^', response.headers['s_tag']).group(1)
        return response_json, user_id

抢购时间比对与次数限制

时间比对与自动抢购。列出实时时间并比对抢购时间。此处若有因反爬虫检测导致提交订单失败将给出提示。

        print(f'[{time.strftime("%H:%M:%S", time.localtime())} INFO]: 正在尝试抢购商品***{good_infos[good_id]["title"]}***')
        # 对比时间,时间到的话就点击结算
        while True:
            now = datetime.datetime.now().strftime('%H:%M:%S.%f')
            print(now)
            if now > self.Seconds_kill_time:
                for i in range(self.number):
                    try:
                        is_success = self.buygood(good_infos[good_id], user_id)
                    except Exception as err:
                        crawler = re.findall("'NoneType' object has no attribute 'group'",str(err))
                        if "'NoneType' object has no attribute 'group'" in crawler:
                            print("已触发反爬虫机制,请稍后尝试! 错误信息如下:\n{0}\n".format(err))
                            # is_success = False
                            break
                        else:
                            print(f'[{time.strftime("%H:%M:%S", time.localtime())} INFO]: 抢购失败, 错误信息如下: \n{err}\n将在{self.trybuy_interval}秒后重新尝试.')
                            is_success = False
                    if i == self.number-1 and is_success == False:
                        print("抢购失败")
                        break
                    elif is_success:
                        print(f'[{time.strftime("%H:%M:%S", time.localtime())} INFO]: 抢购***{good_infos[good_id]["title"]}***成功, 已为您自动提交订单, 请尽快完成付款.')
                        # 电脑语音提示
                        for _ in range(5):
                            pyttsx3.speak('已经为您抢购到你所需的商品, 请尽快完成付款.')
                            time.sleep(self.trybuy_interval)
                        break
                break

结算请求

抢购数据使用requests提交,该方案优于自动抢购webdriver方案,无需渲染,自动提交抢购请求,提高抢购速度。

        url = 'https://buy.taobao.com/auction/order/confirm_order.htm?spm=a1z0d.6639537.0.0.undefined'
        headers = {
            'cache-control': 'max-age=0', 'upgrade-insecure-requests': '1',
            'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36',
            'origin': 'https://cart.taobao.com', 'content-type': 'application/x-www-form-urlencoded',
            'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
            'sec-fetch-site': 'same-site', 'sec-fetch-mode': 'navigate', 'sec-fetch-user': '?1',
            'sec-fetch-dest': 'document', 'referer': 'https://cart.taobao.com/',
            'accept-encoding': 'gzip, deflate, br', 'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8'
        }
        cart_id, item_id, sku_id, seller_id, cart_params, to_buy_info = info['cart_id'], info['item_id'], info['sku_id'], info['seller_id'], info['cart_params'], info['to_buy_info']
        data = {
            'item': f'{cart_id}_{item_id}_1_{sku_id}_{seller_id}_0_0_0_{cart_params}_{urllib.parse.quote(str(to_buy_info))}__0',
            'buyer_from': 'cart',
            'source_time': ''.join(str(int(time.time() * 1000)))
        }
        disable_warnings()
        response = self.session.post(url = url, data = data, headers = headers, verify = False)
        order_info = re.search('orderData= (.*?);\n</script>', response.text).group(1)
        order_info = json.loads(order_info)
        # 发送提交订单请求
        token = self.session.cookies['_tb_token_']
        endpoint = order_info['endpoint']
        data = order_info['data']
        structure = order_info['hierarchy']['structure']
        hierarchy = order_info['hierarchy']
        linkage = order_info['linkage']
        linkage.pop('url')
        submitref = order_info['data']['submitOrderPC_1']['hidden']['extensionMap']['secretValue']
        sparam1 = order_info['data']['submitOrderPC_1']['hidden']['extensionMap']['sparam1']
        input_charset = order_info['data']['submitOrderPC_1']['hidden']['extensionMap']['input_charset']
        event_submit_do_confirm = order_info['data']['submitOrderPC_1']['hidden']['extensionMap']['event_submit_do_confirm']
        url = f'https://buy.taobao.com/auction/confirm_order.htm?x-itemid={item_id}&x-uid={user_id}&submitref={submitref}&sparam1={sparam1}'
        data_submit = {}
        for key, value in data.items():
            if value.get('submit') == 'true' or value.get('submit'):
                data_submit[key] = value
        data = {
            'action': '/order/multiTerminalSubmitOrderAction',
            '_tb_token_': token,
            'event_submit_do_confirm': '1',
            'praper_alipay_cashier_domain': 'cashierrz54',
            'input_charset': 'utf-8',
            'endpoint': urllib.parse.quote(json.dumps(endpoint)),
            'data': urllib.parse.quote(json.dumps(data_submit)),
            'hierarchy': urllib.parse.quote(json.dumps({"structure": structure})),
            'linkage': urllib.parse.quote(json.dumps(linkage))
        }
        headers = {
            'cache-control': 'max-age=0', 'upgrade-insecure-requests': '1', 'origin': 'https://buy.taobao.com',
            'content-type': 'application/x-www-form-urlencoded',
            'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36',
            'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
            'sec-fetch-site': 'same-origin', 'sec-fetch-mode': 'navigate', 'sec-fetch-user': '?1',
            'sec-fetch-dest': 'document',
            'referer': 'https://buy.taobao.com/auction/order/confirm_order.htm?spm=a1z0d.6639537.0.0.undefined',
            'accept-encoding': 'gzip, deflate, br', 'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8'
        }
        response = self.session.post(url, data=data, headers=headers, verify = False)
        if response.status_code == 200: return True
        return False


使用方式

  1. 从https://kaydenlsr.coding.net/public/taobaosnap/taobaosnap/git/files解压最新版taobaosnap

  2. 安装相关依赖 pip install [modules]

  3. 下载chrome浏览器和对应的chromedriver,放到python.exe目录下。项目提供chromedriver version = 99.0.4844.51

  4. 运行cmd并运行'python taobaosnap.py --interval [时间间隔] --time [开始时间] --l [频率]'

例子

$ python taobaosnap.py --interval 0.1 --time 15:59:59:90000000 --l 5

帮助

usage : python taobaosnap.py
--time Buying time and format: 00:00:00:00000000.
--interval Buying time interval. 
--l Buying frequency.

测试截图

(以下非抢购时间测试截图,已测试其他商品可成功提交订单)

3.13,笔者使用本程序成功抢购十三个,明天试试抢茅台吧。


如何获取

Taobaosnap 发行版可从以下位置获得

https://kaydenlsr.coding.net/public/taobaosnap/taobaosnap/git/files

Taobaosnap 应该在任何支持python的平台上运行

Python (http://www.python.org)

注意:有关注意事项,请参阅以下链接中的指南

https://kaydenlsr.coding.net/public/taobaosnap/taobaosnap/git/files/master/readme.md

注意:此方案目前不兼容linux系统和mac系统(目前已开发version=3.2.5支持linux系统,大家可自行git上项目查看)

依赖

必要的驱动

chromedriver

python依赖库

-requests
-urllib
-pyttsx3
-prettytable
-argparse
-selenium

获取

github

https://github.com/kaydenlsr/taobaosnap

coding

https://kaydenlsr.coding.net/public/taobaosnap/taobaosnap/git/files

项目各版本使用方法均于readme.md作描述。可以在项目中查看描述文件,或于往期推文阅读使用方法.

其他因素

  1. 代码运行速度

  2. 网络延时

  3. 网络发包速度

  4. 越点路由数量

使用建议

  1. 将抢购开始时间设置为开始前约0.1秒,抢购时间间隔设置为0.1秒,抢购次数设置为五次。

  2. 系统时间与标准网络时间校对。

  3. 使用前约十分钟登录账号,设置好后等待读秒即可。

关于项目

开源项目已发行数个版本。

version=1.0.5使用requests的方式完成抢购。

version=2.0.3 使用selenium模块与webdriver调用完成抢购。

version=3.1.5 使用selenium模块与webdriver调用完成登录,使用requests的方式完成抢购。

version=3.2.5 简化了3.1.5版本的的操作。

version=3.2.5 适用于linux的方案。

version=1.0.6(windows) 解决了DecryptLogin模块更新后适应问题

version=3.2.6(windows) 合并login文件,优化代码,删除语音播报模块

version=3.2.6(linux) 同3.2.6(windows)

version=3.3.6(windows) 使用某宝服务器时间接口读秒,放弃使用本地时间读秒。

项目作者

spmonkey

K龙

特别鸣谢

Charles

版本(Version)

Last update 2022.3.12 by K龙 version=3.2.5

免责声明

本项目为开源项目旨在互相学习。禁止违反法律法规使用本程序。因使用本程序造成的任何后果或相关规定,作者概不负责。

Last updated