周日. 8月 1st, 2021

淘宝抢号那些坑

懂的玩家都知道,淘宝抢号其实是一家,所谓的竞争都是假象,恶意竞价的比比皆是,玩家想抢的号如果特别超值,人家就自己抢到手倒号了。五十块起步价,博主当年被坑过,就是不想干活不想累那个人(不是故意黑),剩30分钟到交易区的时候,告诉我有人竞价,我心里MMP,当时还不懂,就加到了一百块,其实号就十几个关注,完全不是超值的号。官方一直声称打击代人秒号行为,我觉得没有什么实际的行动,到现在那几家淘宝店仍然风生水起,您倒是起诉一下,或者想点办法优化程序(摊手)。

必备知识

  1. 天龙八部畅易阁商品在公示期内无法下单,公示期结束的时间不固定,刷新网页会有2秒左右的随机偏移
  2. 商品进入交易区后需要正确输入验证码,才能够成功下单(验证码难度非常大,人眼也经常识别错误)
  3. 所有网页限制刷新频率,大概不允许连续10秒内的30次刷新,否则会报服务器维护的错误
  4. 商品信息的页面非常大,一般网速下刷新网页的速度在0.2秒左右
  5. 同一账号下单再取消,次数过多后,会暂时不允许下单,一天后解封

制作谷歌插件抢号

为什么用谷歌插件?
因为懒,可以免去登录session,cookie等等麻烦的东西,只要有js基础就很容易上手
现在开始(敲黑板)


首先比较一下手动抢号和程序抢号
手动抢号的过程:

  1. 登录天龙账号,打开要购买的商品页面
  2. 在公示时间马上结束时,疯狂刷新页面,直至出现立刻购买的按钮
  3. 点击立刻购买,输入验证码,点击下单,如果成功,则直接跳转到付款界面

程序抢号的过程:

  1. 用谷歌浏览器登录天龙账号,打开要购买的商品页面
  2. 插件获取商品id,循环发送购买请求(以及验证码数字)

下面介绍抢号插件的思路

首先,“必备知识3”告诉我们,不能通过无脑刷新网页来找到商品进入交易区的时间点,那么应该怎么办呢?
商品信息页面有一个重要的信息:剩余时间。那么我可以在第一次进入商品信息页面的时候获取到剩余的时间,然后设置一个定时器,检查时间过去了多久,当剩余时间为0的时候,开始进行抢号活动。

var restTime = parseInt($(".less-than-day").attr("data-second"));  // 获取公示剩余秒数
var running = false;

let itv_run = setInterval(() => {   // 检测剩余时间是否到达规定
    if (restTime < -1) {
        running = true;
        clearInterval(itv_run);
        // 抢号代码
    }
}, 10);

let time_count = setInterval(() => {  //每隔0.1秒更新一次剩余时间
    restTime = restTime - 0.1;
}, 100);

然后分析下单按钮会触发什么事件, 下面的代码是向服务器发送post请求,验证下单信息和验证码

// 这里的BASE_PATH = "http://tl.cyg.changyou.com"
$.ajax({
    url: BASE_PATH + "/transaction/buy",
    type: "post",
    async: !1,
    data: {
        goods_serial_num: t,  //商品id
        captcha_code: o   //验证码数字
    },
    success: function(t) {  //购买成功,进入付款界面
        if (0 == t.indexOf("success_")) {
            var o = t.substring("success_".length);
            return n.find(".span").html("\u6210\u529f\u8df3\u8f6c\u4e2d"),
            window.location.href = BASE_PATH + "/transaction/check?orders_num=" + o,
            !1
        }
    }
});

所以用插件实现的话很简单:

id = window.location.href.split("=")[1];  // 获取商品id
$.ajax({
    url: "http://tl.cyg.changyou.com/transaction/buy",
    type: "post",
    async: !1,
    data: {
        goods_serial_num: id,
        captcha_code: data //验证码后续介绍
    },
    success: function (t) {
        console.log(t);
    }
});

那么问题来了,如何得到正确的验证码呢,首先我们需要拿到验证码的图片,你可以尝试点击立即购买,然后右键验证码图片,点击检查(或者审查元素),你会看到这样一串(截取)代码:

src=”http://tl.cyg.changyou.com/transaction/captcha-image?goods_serial_num=201909091549420642&t=1569149359054″

你可以试着把引号里的链接输入到浏览器中,刷新几次,然而每一次都会出现不同的验证码,这说明验证码是动态的,当你刷新的时候,畅游后台也告诉服务器你的验证码变了。仔细看上面的链接,goods_serial_num=后面是商品id号,t=后面是你刷新的时刻的date()秒数

有趣的实验:随意打开一个商品页面,点击立即购买,新开一个页面,将上面的代码拷贝到浏览器搜索框,把goods_serial_num=后面的数字改成你打开的商品id,刷新几次,回到你的商品页面,输入商品页面的验证码,你会发现,系统会告诉你验证码错误——如果你把新打开的验证码页面的验证码输进去,就会成功。
这样一来,就可以直接通过网址获取到验证码。

var image_url = "http://tl.cyg.changyou.com/transaction/captcha-image?goods_serial_num=" + id + "&t=" + (new Date).getTime();

优化程序

优化什么呢?
前面介绍的程序是基于谷歌插件实现的,过分依赖chrome,而且由于需要开启本地服务,又增加了时间消耗。为了节省识别时间,加快post频率,我又在想新的方法。

绕过登录的大坑

前两天仔细研究了一下畅易阁的登录代码,太难了,很多cookie还是本地脚本生成的,实在超出我能力范围,所以换了一个笨方法,用浏览器登录,把cookie复制出来直接使用。

首先登录天龙畅易阁的账号,随便点进去一个商品页或者首页,右键检察元素,点击网络,再刷新一次网页,找到网页文稿对应的名称,在它的请求中找到Cookie,将冒号后面的内容复制下来

然后用下面的代码:

id = 201909261745566152 # 要抢的商品id
cookie_str = "" # 输入你刚才复制的cookie字符串
header = {
    'cookie': cookie_str,
    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36'
}
goodUrl = "http://tl.cyg.changyou.com/goods/char_detail?serial_num=" + str(id)
goodReq = urllib.request.Request(goodUrl, None, header)
raw = request.urlopen(goodReq)
html = raw.read().decode('utf-8')

得到的html变量已经是登录后的样子了
同样的,验证码也可以直接获取到

# 这里换了一种方式
req = request.Request(url)
#设置cookie
req.add_header('cookie', cookie_str)
#设置请求头
req.add_header('User-Agent', 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36')
resp = request.urlopen(req)
# 获取验证码图片数据
byteImg = io.BytesIO(resp.read())
im = Image.open(byteImg)


整体代码架构

# 获取精确的抢号开始时间
def getRestTime():
    return time

# 开始抢号
def start():
    getCaptchaImage() # 获取验证码
    postBuy()  # 发送下单请求
    if success:
        return True
    else:
        return False

startTime = getRestTime()
while startTime > time.time():
    time.sleep(0.05)
print("start post---")
# 开始循环抢号
for i in range(20):
    print(i, '-----')
    flag = start()
    if flag == True:
        break


效果简述

原来的谷歌插件程序,抢号每轮识别和请求的总时间在200毫秒以上,现在能在150毫秒左右。

> 最须提升的部分:判断进入交易区的时间点,精准打击,很多次都输在了这个时间点的把控上,最后给我返回服务器错误,就是说已经有人比我先post下单请求,服务器正在处理,就像卵子那样(哈哈~)

前面的一切都是铺垫,最重要的部分是如何识别验证码,尤其是如此困难的验证码,我相信手动也经常错的不是我一个人。
网上有很多提供验证码识别接口的平台,比如超级鹰,聚合数据这些(已经踩过坑),但是论速度,多花费了向人家的服务器请求的时间,会比较慢;论准确率,这些接口的训练样本是各种各样的验证码,不具有针对性,识别格子的验证码正确率能达到50%左右已经是难得了。
验证码大概都是这样婶的:

堡主采集10000多条格子真实验证码,训练了神经网络,识别率88%,识别速度平均0.08秒,需要电脑配备英伟达显卡

将验证码识别做成了网络本地服务端口,在浏览器插件脚本里发送识别验证码的请求,完成一次抢号操作。如果有兴趣的话,还可以试试tensorflow.js,直接用js做验证码识别,速度会更快。

代码在这里:github链接

最后附上格子搜号网址,以便找到性价比高的号:天龙搜号

   
 摸鱼堡版权所有丨如未注明,均为原创丨本网站采用BY-NC-SA协议进行授权
转载请注明转自:http://moyubao.net/coder/689/
《手把手教你编写畅易阁抢号程序》有4条评论

发表评论

邮箱地址不会被公开。