“秒杀”心得

简介:

  本文记录对某网站A的秒杀活动编写秒杀器的经历和技术重点。

 

故事回顾


    某日早上,朋友给我说最近A网站在开展秒杀活动,有IPad、IPhone,让大家一起去秒杀。结果我们四个人一起秒,都没有别人快,没有一个人秒到。然后下午我就开始尝试分析它网站的秒杀流程,并尝试使用自动提交数据的方案来进行秒杀。结果,在晚上的时候,成功做出了第一个版本的秒杀器,然后我们一起秒杀了几个IPad(大家都想要IPad,而对IPhone没兴趣,汗)。

    当时就用网银付了帐,等待它发货。接下来我们每个人一个接一个地接到了A网站打来的电话,确定我们是不是作弊了,哈哈,我们当然打死不会承认了~

    过了半个来月,该网站又发起了新一轮的秒杀活动,但是由于之前发现有许多人作弊,所以这次全面更改了网站的流程,随机出现各种题目让会员回答,回答成功才能继续秒杀。这样,难度就大了些,一开始以为它们是题库,后来发现原来所有的题目都是自动生成的。元旦也没闲着,花了几天时间,改出了第二个版本的秒杀器,智能解题。经测试,目前没有失败过。

 

第一版本


    以下简明扼要地描述所有的分析流程

    分析网站秒杀流程,得出“入口页面”的地址。但是尝试登录此页面失败,返回活动等待页面,并提示:“活动未开始”。

    写了一个简单的控制台程序,在活动开始时立刻运行此程序,快速地打开了20-40个入口页面。此时,发现有一半左右的页面进入成功,到达“提交页面”。提交页面中需要填写一些必要的个人信息,最下面是一个提交按钮。估计这是A网站秒杀的最后一道关。

    把提交页面的客户端源代码全部保存下来,尝试进行分析。发现表单中需要填写的是:一些固定信息、一些隐藏域(HiddenField)、图片验证码。

    隐藏域中需要提交一些如:当时秒杀活动Id、用户Id等的信息。这些信息只要在网站中多分析一下就能得出。

    验证码:这个目前并没有什么好的办法能自动识别验证码,网上虽然有此类程序,不过我懒得去下载了,直接把验证码的图片显示在程序中,人工录入就好了。这样做的原因是,以我的经验,他们的验证码十有八九存储在服务端Session中,也有可能是客户端Cookie中,也就是说,验证码是可以提前获取的,并不一定需要等等活动开始后再获取。所以只要在临近活动开始的前2分钟获取并录入验证码就行了。

    这样,所有的数据都准备好了,接下来就是如何让程序自动填写数据并提交到网站上。这是重点,也是难点。如果纯粹使用后台代码模拟提交的话,就需要保证后台代码拥有已经被网站验证通过后的Cookie。之前我做过类似的提交程序,但是准备假Cookie的工作一直没有成功过,也比较麻烦。由于这次时间比较紧,没法再试验这种纯正的方案。所以静下心来想别的方案。后来灵机一动决定使用控制浏览器的方案来试试:在秒杀程序中嵌入一个浏览器,在浏览器中执行登录操作。这样,登录成功后的Cookie,就由浏览器自己来维护,而我要做的就是控制浏览器中页面的运行,让它以我的方式加载页面、填写数据、提交数据。在提交数据时,浏览器也会自动把Cookie一并提交。这样就可以在登录的状态下,把前面准备好的数据直接自动提交给服务器。

    最后一个问题,让浏览器先访问A网站的页面,登录并拿到登录成功的凭证后,如何让浏览器运行我的代码来提交数据呢?我试了一下在WPF应用程序中直接使用WPF自带的浏览器控件,并研究它的API。在WebBrowser类的API列表中,我发现以下方法:

1
2
public  void NavigateToString(string text);
public  object InvokeScript(string scriptName);

这正是我想要的啊,先构造一个模拟的页面,使用NavigateToString到这个页面上,然后使用InvokeScript方法来调用javascript提交表单到表单上指定的网站的地址就行了!

    OK,至此,全部设计完成。由于验证码已经在活动前就准备好了,所以整个过程基本上是完全自动化的,速度当然比人快多了,IPad自然也就手到擒来!

 

第二版本


    上面已经说过,网站改版后的秒杀活动,已经使用随机出现的题目来防止作弊。所以这次我的主要任务就是如何自动答题!其次,分析网站的提交页面中的表单,发现有很多的隐藏域是一连串随机的数字,没有任何规律,估计这些数据是每次活动都不一样的,所以再使用第一版中静态的模拟页面提交数据的方法不行了,必须使用动态的页面,把这些随机的数据都保留下来,并一起提交,或者直接在A网站发回来的页面中填写数据再提交。

    首先,第一直觉就是获取大量的提交页面,提取出获取到的所有题目,存储在题目库中。答题时,直接在题库中进行匹配,如果找到相同的题目,则直接使用题目库中的答案进行回答。

    当时,简单地画了一个流程的设计:

image

    后来在该次活动的最后一轮秒杀时,程序开发完成,并开始使用。结果,发现没有一题匹配成功,都找不到答案,全部都显示到了右边的窗口中人为回答,结果我还答错了!!!活动结束!!!

    很气人啊,这样的方案根本不行。后来分析了半天,发现原来所有的题目都是程序自动生成的,只是模式固定而已。所以改了设计方案,遵循设计模式写了一些类来自动回答题目,类结构如下:

image image

这里,只贴一个子类的代码,展示一下解答的模式。这个子类的逻辑也是所有题目中最复杂的一个:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class TallerAlgorithm : SelectionQuestionAlgorithm
{
     internal override void TryComplete(SelectionQuestion question)
     {
         var match = Regex.Match(question.Content, @ "小(?<a>.)比小(?<b>.)(?<abUnit>.),小(?<c>.)比小(?<d>.)(?<cdUnit>.),请问他们当中谁最(?<finalUnit>.)?" );
         if (match.Success)
         {
             var a = match.Groups[ "a" ].Value;
             var b = match.Groups[ "b" ].Value;
             var c = match.Groups[ "c" ].Value;
             var d = match.Groups[ "d" ].Value;
 
             var abUnit = match.Groups[ "abUnit" ].Value;
             var cdUnit = match.Groups[ "cdUnit" ].Value;
             var finalUnit = match.Groups[ "finalUnit" ].Value;
 
             var winner1 = abUnit == finalUnit ? a : b;
             var loster1 = abUnit == finalUnit ? b : a;
             var winner2 = cdUnit == finalUnit ? c : d;
             var loster2 = abUnit == finalUnit ? d : c;
 
             string champion = null ;
 
             if (winner1 == winner2) champion = winner1;
             else  if (winner1 == loster2) champion = winner2;
             else  if (winner2 == loster1) champion = winner1;
 
             if (!string.IsNullOrWhiteSpace(champion))
             {
                 question.RightAnswer = question.Answers
                     .SingleOrDefault(an => an.Text. Contains (champion));
             }
         }
     }
}

 

    其次,是动态的页面的整理:把里面的题目都提取出来,自动答题之后,填写答案,插入一些提交的Javascript代码。然后继续使用NavigateToString、InvokeScript来提交数据。过程中,有两点心得:

1. 在一开始控制浏览器导向提交页面后,发现无法获取Html源代码,花了些时间研究,没搞出来。查了半天网页,最后使用WinForm中的WebBrowser来解决了这个问题。WinForm中WebBrowser不象WPF中的WebBrowser,它拥有着强大的API,DocumentText属性就取到了源代码。

2. 这次我使用了LinqToXml来维护Html Dom中的所有内容,发现XLinq的API实在是太方便了,查找某个元素,更改某个属性。如果没有XLinq,相同的功能,我可能需要3-5倍的时间来完成。

 

总结


    这次秒杀器编写的过程,让我的一个心结给解了。一直以来,就想完全控制网页客户端程序的运行:大四在电信的时候,老总让我给领导刷票;再后来有要人给我给论坛自动提交数据。这些需求都需要持有客户端的用户凭证,然后用这个身份给服务端自动发送一些请求。一直使用纯后台代码的方式提交,没有成功过。这次,使用控制浏览器的方案,使得真正做到了一直想做到的:“完全控制客户端”。

目录
相关文章
|
8月前
|
存储 NoSQL 安全
Redis解决秒杀下单
Redis解决秒杀下单
32 0
|
8月前
|
数据库
.商品秒杀-超卖
.商品秒杀-超卖问题
53 0
|
10月前
|
Java
记录一次简单的秒杀场景
记录一次简单的秒杀场景
52 0
|
12月前
|
缓存 NoSQL JavaScript
面试官:电商库存扣减如何设计?如何防止超卖?
面试官:电商库存扣减如何设计?如何防止超卖?
|
缓存 监控 NoSQL
秒杀系统
秒杀能够以极小的经费撬动巨大的流量,虽然会带来一定的口碑损失,但因为极具性价比,所以经常被运营同学使用。本文介绍如何设计一款能够支撑60W QPS的秒杀系统,希望能够帮助到大家。
|
存储 缓存 NoSQL
京东一面:Redis 如何实现库存扣减操作?如何防止商品被超卖?
京东一面:Redis 如何实现库存扣减操作?如何防止商品被超卖?
384 0
京东一面:Redis 如何实现库存扣减操作?如何防止商品被超卖?
|
数据采集 Web App开发 IDE
Python爬虫抢购某宝秒杀商品
某宝秒杀,用毫秒级的精准度来抢购! 你还在为各种活动秒杀 抢不过别人而烦恼吗? 应粉丝要求 今天出一期 利用Python爬虫 抢购秒杀商品的文章 目录 ​ 1,项目环境 ​ 2,某宝抢购流程分析 ​ 3,程序实现思路 ​ 4,代码实践与梳理
525 0
|
SQL 缓存 NoSQL
高并发下秒杀商品,你必须知道的9个细节
高并发下秒杀商品,你必须知道的9个细节
高并发下秒杀商品,你必须知道的9个细节
|
存储 消息中间件 缓存
【高并发】高并发秒杀系统架构解密,不是所有的秒杀都是秒杀!
在电商领域,存在着典型的秒杀业务场景,那何谓秒杀场景呢。简单的来说就是一件商品的购买人数远远大于这件商品的库存,而且这件商品在很短的时间内就会被抢购一空。 比如每年的618、双11大促,小米新品促销等业务场景,就是典型的秒杀业务场景。
677 1
【高并发】高并发秒杀系统架构解密,不是所有的秒杀都是秒杀!
|
双11 数据库 黑灰产治理
高并发秒杀系统如何实现正确的扣减库存?
高并发秒杀系统如何实现正确的扣减库存?
383 1
高并发秒杀系统如何实现正确的扣减库存?