内容简介:本文涉及到的技术点有(多图预警!):行吧,别做梦了,暴富了,我还这里码字?标题党的感觉就是舒服,还是踏踏实实搬砖吧!关于赚大钱的捷径都写在刑法里,想具体了解的可以到逼乎自行查阅:在真正开始本文之前,要严肃的强调几点:
本文涉及到的技术点有(多图预警!):
- 1. Packet Capture和Charles抓包 ;
- 2. 安卓AccessibilityService无障碍服务实现自动下注 ;
- 3. Python爬虫模拟下注 ;
- 4. Python Flask编写简单接口 ;
行吧,别做梦了,暴富了,我还这里码字?标题党的感觉就是舒服,还是踏踏实实搬砖吧!关于赚大钱的捷径都写在刑法里,想具体了解的可以到逼乎自行查阅: 都说最赚钱的方法都在刑法里面,那么宪法里面到底禁止了哪些暴利的赚钱方法?这些方法到底有多赚钱呢? 我只能帮你们到这里了。投机倒把暴富的念想是挺美好的,但我投机倒把的真实的结果是: 国庆短短几天,因为投机倒把我亏了7755块 (截止目前亏了 9073块 )...
编写本文的出于下面几个初衷:
- 1.记录自己在投机倒把过程中运用到的一些 开发技术 ;
- 2.记录这次投机倒把的经历,以此警示自己以后要踏踏实实做事;
- 3.奉劝各位有这种念想的伙计 引以为戒 , 远离投机倒把 , 保持身心健康 。
在真正开始本文之前,要严肃的强调几点:
- 投机倒把 ,十有九 输 ,或者十 输 , 输 !投机倒把中赚钱的永远是极少数的幸运儿。如果只为 娱乐 , 不为赢钱 可以,参考过年家里常有的小赌怡情,玩个几百块,赢了和输了都收手。
- 本文不是让你去投机倒把,所以不会提供任何APP下载外链或文件!
本文的讲解流程:
先讲解一波投机倒把相关的概念,然后通过和两个好基友的沙雕聊天记录,引出一些开发相关的东西,分析一波投机倒把过程里的一些猫腻,希望各位看官会喜欢这个有( 悲 )趣( 伤 )的真实故事~
第零章:名词碎碎念
先来了解一波和投机倒把有关的名词吧~
0.1 赌徒心理(贪欲和侥幸心理)
赢了还想赢更多的钱,输了又想回本,反复告诉自己赢一把就收手,回本就收手,事实上,只有当自己的前输得精光的时候才会收手。
举个例子:
- 1.下注,输了10块,想着把10块赚回来,又压了10块,然后又输,又压20,再输压30...本没有回,钱却越输越多。
- 2.输了10块,下把下注奖为5块, 赢了 , 患得患失 ,如果刚刚那把压多一点就赢好多了, 输了 , 暗自庆幸 ,幸好把下注少了,不然就亏大了。
赢钱的时候也不会见好就收,毕竟对于赌徒来说,收手是最难的。
0.2 大数法则
大数不是 大叔 ,又称“ 平均法则 ”,即: 在随机事件的大量重复中往往出现几乎必然的规律 。在实验条件不变的情况下,重复实验多次,随机事件的频率近似于它的概率。举个例子,我们都知道的常识: 抛硬币 ,正反面的概率各占50%。但是,现在让你去抛两次硬币,却很难出现刚好一正一反的情况。只在你重复了上千上万次后,正和反出现的次数接近持平。
看到这里,读者可能有这样的疑问:
既然最后是五五开,那我一直玩,为什么 最后还是亏了 ,难道是有 中间商 赚差价了?
讲真,真的有 中间商 ,尽管从概率上来说,是五五开的,但是有两点根本不平等。
首先,概率是建立在 大量重复实验 的基础上的,庄家有“用不完的钱”,可以进行无限次投机倒把,且没有赌徒心理,而反观赌徒的资金一般是有限的。然后呢,又有一个名词,概率波动论。
0.3 概率波动论
具备两面性的规律从概率来讲是对半的,但在一段时间内有可能多数呈一面性表现。举个简单的三个骰子买大小的例子(1-9小,10-18大),10次的结果是这样的(连续3次大):
概率波动是概率发生的必然,因此投机倒把过程中可能出现连续输好几把的情况。
0.4 倍投法
接着是中间商赚差价的第二点,比如有一些买大小单双的赌局,胜率并不是 1:2 ,比如 1:1.96 ,或者 1:1.82 等,比如你一把玩1块,第一把输了,第二把也投1块,你中了,只赢 1.96 块,但是,其实你已经花了 2块钱 ,亏4分钱。如果是1.86的,亏1毛4,看上去数额很少是吧,但是基本都不会只玩几把吧,一天下来可能玩了上千把,一个赌客就贡献了好几百,赌客肯定不止你一个,而且下注也肯定不会1块1块的来,所以说说为什么那么多投机倒把类的APP。而扭转这种亏损的一种简单而且赚钱的做法,就是倍投法。举个简单的例子,假如赔率是1:2的话,下注的金额是这样一个列表: [10,20,40,80,160,320,640,1280,2560...] ,第一把投10块,输了,第2把投20,赢了40,减去本金30,赚10,没中,第3把投40,赢了80,减去本金70,赚10块,就是保证每一轮赢10块。我们写个简单的Python代码来生成一个倍投收益的表格。代码如下( prettytable 库用于生成表格):
from prettytable import PrettyTable purchase_base = 10 # 购买基数 ratio = 2 # 中奖倍率 price_list = [] # 投入金额 def init_purchase_list(): x = PrettyTable(['投入', '投入总额', '获利', '净利润']) cost = 0 price_list.append(purchase_base) # 其他进行动态计算 print("初始化投入金额表格...") for i in range(0, 10): cost += purchase_base * (2 ** i) # 花费 bonus = purchase_base * (2 ** i) * ratio # 奖金 x.add_row([purchase_base * (2 ** i), cost, bonus, bonus - cost]) print(x) if __name__ == '__main__': init_purchase_list() 复制代码
运行下程序,可以得出一个倍投的结果列表:
初始化投入金额表格... +------+----------+-------+--------+ | 投入 | 投入总额 | 获利 | 净利润 | +------+----------+-------+--------+ | 10 | 10 | 20 | 10 | | 20 | 30 | 40 | 10 | | 40 | 70 | 80 | 10 | | 80 | 150 | 160 | 10 | | 160 | 310 | 320 | 10 | | 320 | 630 | 640 | 10 | | 640 | 1270 | 1280 | 10 | | 1280 | 2550 | 2560 | 10 | | 2560 | 5110 | 5120 | 10 | | 5120 | 10230 | 10240 | 10 | +------+----------+-------+--------+ 复制代码
每一轮才挣10块,有点少是吧,你可以试试赚更多的3倍投,把上面的代码改一下:
for i in range(0, 10): cost += purchase_base * (3 ** i) # 花费 bonus = purchase_base * (3 ** i) * ratio # 奖金 x.add_row([purchase_base * (3 ** i), cost, bonus, bonus - cost]) 复制代码
输出结果如下:
初始化投入金额表格... +--------+----------+--------+--------+ | 投入 | 投入总额 | 获利 | 净利润 | +--------+----------+--------+--------+ | 10 | 10 | 20 | 10 | | 30 | 40 | 60 | 20 | | 90 | 130 | 180 | 50 | | 270 | 400 | 540 | 140 | | 810 | 1210 | 1620 | 410 | | 2430 | 3640 | 4860 | 1220 | | 7290 | 10930 | 14580 | 3650 | | 21870 | 32800 | 43740 | 10940 | | 65610 | 98410 | 131220 | 32810 | | 196830 | 295240 | 393660 | 98420 | +--------+----------+--------+--------+ 复制代码
卧槽,刺激是吧,如果有30W的本金,三倍投,不中的次数越多,你赚的钱越多。如果连续不中到10次,中了,一轮1将近10W,这种是敢死队倍投法,很难很难挂一次,但是一旦出现一次直接跌入18层地狱永不超生!(笔者试过好几次...等下细讲)。这种是平台比例1:2的情况,有些中间商赚差价的平台的赔率是1.96这样,上面的代码生成的结果就变成了(2倍投,ratio改为1.96):
初始化投入金额表格... +------+----------+---------+---------------------+ | 投入 | 投入总额 | 获利 | 净利润 | +------+----------+---------+---------------------+ | 10 | 10 | 19.6 | 9.600000000000001 | | 20 | 30 | 39.2 | 9.200000000000003 | | 40 | 70 | 78.4 | 8.400000000000006 | | 80 | 150 | 156.8 | 6.800000000000011 | | 160 | 310 | 313.6 | 3.6000000000000227 | | 320 | 630 | 627.2 | -2.7999999999999545 | | 640 | 1270 | 1254.4 | -15.599999999999909 | | 1280 | 2550 | 2508.8 | -41.19999999999982 | | 2560 | 5110 | 5017.6 | -92.39999999999964 | | 5120 | 10230 | 10035.2 | -194.79999999999927 | +------+----------+---------+---------------------+ 复制代码
是的,普通的二倍投法越到后面反而越亏,而三倍投依旧是赚钱的,在本金不够充裕无法三倍投的情况下,要在二倍投的基础上加点,而且少于三倍投,保证我们每把赚的钱>购买基数,而且投入的金额最少,我们改下下我们的代码:
from prettytable import PrettyTable purchase_base = 10 # 购买基数 ratio = 1.96 # 中奖倍率 price_list = [] # 投入金额 def init_purchase_list(): x = PrettyTable(['投入', '投入总额', '获利', '净利润']) x.add_row([purchase_base, purchase_base, round(purchase_base * ratio, 2), round(purchase_base * ratio - purchase_base, 2)]) cost = purchase_base price_list.append(purchase_base) # 其他进行动态计算 print("初始化投入金额表格...") for i in range(10): purchase = 0 # 购买价格其实区间(2倍) start_price = purchase_base * (2 ** i) # 购买价格极限区间(3倍) end_price = purchase_base * (3 ** i) # 保证没把不亏就行 for j in range(start_price, end_price + 1): if j * ratio - cost - j > purchase_base: x.add_row([j, cost + j, round(j * ratio, 2), round(j * ratio - cost - j, 2)]) cost += j price_list.append(j) break print(x) if __name__ == '__main__': init_purchase_list() 复制代码
输出下注金额列表如下:
初始化投入金额表格... +------+----------+----------+--------+ | 投入 | 投入总额 | 获利 | 净利润 | +------+----------+----------+--------+ | 10 | 10 | 19.6 | 9.6 | | 21 | 31 | 41.16 | 10.16 | | 43 | 74 | 84.28 | 10.28 | | 88 | 162 | 172.48 | 10.48 | | 180 | 342 | 352.8 | 10.8 | | 367 | 709 | 719.32 | 10.32 | | 749 | 1458 | 1468.04 | 10.04 | | 1530 | 2988 | 2998.8 | 10.8 | | 3123 | 6111 | 6121.08 | 10.08 | | 6377 | 12488 | 12498.92 | 10.92 | +------+----------+----------+--------+ 复制代码
以上就是通过Python计算倍投下注金额,关于更多的倍投方法可自行查阅: 倍投的方案全面讲解如何倍投 ,关于投机倒把的名词就科普那么多,正式开始这个令人悲伤的故事吧~
第一章:引子
和往常一样,下午等电梯去吃饭,好基友小A又掏出他的小锤子在那里把玩,抱着好奇心的 我用眼角的余光瞄了一下他在看什么,em...竟然不是那种不堪入目的东西?
在我的威逼利诱(Y威)下全盘托出:别人介绍玩的一款赚钱APP(买彩票)。但是,我记得错网络售彩不是从15年就开始命令禁止了吗。行吧,看了下,私庄(私人庄家)。然后大概看了看APP:
页面非常简单,四个部分:
- 1.顶部最新一期下注倒计时+用户余额
- 2.每期开奖结果
- 3.房间里赌客的投注记录
- 4.下注面板
规则就是下注结果和出的结果一样就中,根据买的种类有不同的倍率,三分钟开一把,下注最小金额 10元宝 (10块),数据来源 加拿大28 彩票的出奖结果。这种算是 公彩 吧,不是 私彩 。区分的最简单依据就是 有这个项目的多个平台 是不是开奖的结果都是一样的,相比起私彩,公彩稍微稍微公平一点。 私彩 的话, 后台是可以调的 !!!好吧,一向对于投机倒把不怎么感冒的我就没有过多的关注了。不过,他貌似从别人那里搞了个下注的投法,慢慢从20奋斗到102,成功引起了我的注意。
这个所谓靠谱的投法就是:
- 1.历史记录里,单跟双,多就买谁。
- 2.历史记录里面,大跟小,少就买谁。
- 3.每一次亏了下一把就把下注金额在上一把基础上翻倍,每一次赚了下一把下注金额就还原到最低值。 4.循环上面三步骤。如果遇到异常流:当前步骤应该买大小或者单双时,出现历史记录里他们数量相同,则停止一局。
后面果然给他撸到200了:
啧啧,竟然真的从20撸到200,不心动是假的...
但是作为一个从不相信天上掉馅饼的开发仔有着自己的矜持,不模拟一下,打死我也不信,于是我盘算着,自己写个脚本按照这个投法去模拟,模拟一段时间后,看看最后是不是真的赚了。先来抓一波APP的包看看吧,这里用到的是手机抓包工具: Packet Capture
行吧,token和sign,后面另外抓了下注的接口,一大串,加密,所以基本可以放弃了。然后想逆向找下APP的代码,直接apktool反编译后看到qihoo的包名,擦,360加固,这就触及到我的知识盲区了,我还不会脱壳...
幸运的是,这是公彩,有很多网站会直接公布每一期的结果,比如: www.kandandan.com/yuce/jnd.ht… ,接着打开Chrome抓下包,先看下页面节点:
可以,看下Network也可以找到这些节点,不是JS加载的,nice,所有要做的就是写一个定时器,每隔3分40秒左右(延时问题)访问一下这个站点,提取一波数据。行吧,直接用Python请求库Requests模拟一波请求就行了,定时任务用 apscheduler 库,最后加上投注相关的算法就可以了,直接给代码,就不解释那么多了。
import requests as r from bs4 import BeautifulSoup from apscheduler.schedulers.blocking import BlockingScheduler current_buy = '单双' # 当前买的类型 current_buy_type = '单' # 当前下注类型 current_buy_money = 10 # 当前投注金额 is_buy_flag = False # 此轮是否购买 first_buy = True # 是否第一次下注 balance = 300 # 剩余金额 sched = BlockingScheduler() def fetch_result(): global first_buy resp = r.get('https://m.99yuce.com/yuce/jnd.html').text bs = BeautifulSoup(resp, 'lxml') tr_s = bs.find("table", attrs={'id': 'tbe'}).find_all('tr') # 获取数字列表 num_list = [] for tr in tr_s[2:12]: num_list.append(int(tr.find('td', attrs={'class': 'tbe_3'}).text)) print(num_list) # 构建数字文字列表 num_str_list = [] for num in num_list: if num % 2 == 0: num_str_list.append('双') else: num_str_list.append('单') if num > 13: num_str_list.append('大') else: num_str_list.append('小') if first_buy: first_buy = False print("当前余额:", balance, " 当前投注金额:", current_buy_money, "当前买的类型:", current_buy) else: calculate(num_list[0]) predict(num_str_list) # 预判 def predict(num_str_list): global balance global current_buy_money global current_buy global current_buy_type global is_buy_flag single_count = 0 # 单出现的次数 big_count = 0 # 大出现的次数 for num_str in num_str_list: if num_str == '单': single_count += 1 if num_str == '大': big_count += 1 print('单:', single_count, ' 大:', big_count) # 如果当前这把应该买单双 if current_buy == '单双': if single_count > 5: current_buy_type = "单" balance -= current_buy_money is_buy_flag = True print("押单") elif single_count < 5: current_buy_type = "双" balance -= current_buy_money is_buy_flag = True print("押双") else: # 相等则跳过 print("单双相等,跳过这一局,不买") is_buy_flag = False # 如果当前这把应该买大小 elif current_buy == '大小': if big_count < 5: current_buy_type = "大" balance -= current_buy_money is_buy_flag = True print("押大") elif big_count > 5: current_buy_type = "小" balance -= current_buy_money is_buy_flag = True print("押小 ") else: # 相等则跳过 print("大小相等,跳过这一局,不买") is_buy_flag = False # 结算,传入最新的数字 def calculate(latest_num): global balance global current_buy_money global current_buy global current_buy_type global is_buy_flag # 如果没有买直接跳过结算 if is_buy_flag: result_list = [] if latest_num % 2 == 0: result_list.append('双') else: result_list.append('单') if latest_num > 13: result_list.append('大') else: result_list.append('小') print('开奖结果:', result_list) # 中了(加余额,重置下注金额) if current_buy_type in result_list: balance += current_buy_money * 2 current_buy_money = 10 print("中了!") # 没中(下注金额加倍) else: current_buy_money *= 2 print("没中~") # 无论中没中,切换下一把的下注类型 if current_buy == '单双': current_buy = '大小' else: current_buy = '单双' else: print("没有下注,跳过当前轮") print("当前余额:", balance, " 当前投注金额:", current_buy_money, "当前买的类型:", current_buy) if __name__ == '__main__': sched.add_job(fetch_result, 'interval', minutes=3, seconds=40) fetch_result() sched.start() 复制代码
接着把脚本挂着模拟下注就可以,而且小A玩的时候不用自己去统计,看着投就好了。
经过两个小时的艰辛等待,300跑到390了,卧槽,稳得不行,什么都不干,每小时多50块左右,一天跑个10小时,500进口袋,搞十个号,一天不得5000?,5000*30 = 150000,卧槽,一个月什么都不干15W,有本金了买一堆手机,挂着跑100个号,卧槽,深圳买房不是梦。我还盘算着公司附近哪租个小地方来做机房,就一个架子然后放一堆手机就好了。 在不知不觉中我已经着道了 ,但还保留着一丝理智,无本生利的事情怎么别人想不到,庄家都是傻逼吗?万一卷款跑路了,于是我谷歌搜了一波是不是骗局,在逼乎看到了这篇文章: 腾讯彩票游戏幸运28是不是个骗局? ,现在提是能提现,最怕是做了什么限制,比如次数,或者限额,钱根本搞不出来,抱着先试试,300而已,赚够本金就提出来,后面的就真的是无本生利了(事实是, 我们想多了 ,这么点钱,对人家平台来说真的不算什么,而且本金就没提出来过,最后都是血本无归...)
第二章:如火如荼
贫穷使人勤劳,一想到可以暴富,我比任何时候都勤快,真·撸起袖子加油干。所谓的自动化就是不用自己点点点,方法也很简单,使用的Android的 无障碍服务——AccessibilityService 实现,原生的Android页面都可以用这个点点点,如果是内嵌网页的就无能为力了。如果你想了解AccessibilityService可以查阅我以前写的两篇文章:
简单点说就是利用工具, 根据ID或者TEXT文本 , 找到对应的控件 , 进行一些操作 , 比如最常见的点击 , 传入文本等 。而这个找ID的 工具 可以使用 android-sdk 里自带的 monitor 来查找,如果你的手机有root还可以下载使用 开发者助手 ,如图所示,可以直接拿到控件ID。
模拟点,进入到这个页面,然后把Python写的算法搬运到Android上,用Okhttp模拟下请求。代码比较多,而且本节主要是将Python,就只贴下大概的样子。
花了一早上的的时间撸出了这个自动点点点,自动下注演示:
行吧,自动下注的点点点弄好了,接着就是挂机测试了,因为觉得稳赚的,于是我注册了两个账号,分别充了300,挂着运行:
在一段小测后发现挺稳定的,于是乎把脚本打成APK,让基友也用起来,然后开始说各种幻想暴富的骚话。
接着就是挂机,BUG修复,和不断的程序优化了,短短几天迭代了十几个版本。接着把基友小B也忽悠进来。
为了早日实现完全自动化,在狗东买了本逆向的书,打算利用国庆破解一波接口,把脚本挂到服务器上,暴富似乎指日可待了,实际上却是一步一步在将自己推向深渊...
第三章:噩耗
2018.9.30号晚上,看着挂了一整天的脚本余额1380元宝,不禁心中窃喜,毕竟有什么比得上看着钱一点点变多令人愉悦么,一想到把脚本挂一晚上,第二天起来就可以2000+了,梦里都会笑醒吧。
2018.10.1号的早上,没有像往常那样睡懒觉到十一二点,八点多就醒了,第一件事迫不及待的去看余额,但是等待我的,却不是如期的2000多,而是340。怎么会这样???不是很稳的吗。立马去翻历史下注记录:
排查后是下注操作有问题,大概的原因可能是: APP开奖延迟,时间并不准确,爬取开奖站点存在一定的延时,有时获到的前十期的结果并不是最新的。 一想到:挂了好几天,钱一下子就没了:
本金用了900,减去剩下的340,我 亏了560 啊,怎么行,必须得回本,昨晚是因为自动挂着才会这样,手动就可以,但是340可以 抗的波数不多,需要更多的本金,我犹豫着要不要充多940进去,凑够1280,在支付的页面停顿了一会儿,后面脑子一热手指一按, 就支付了。不得不说,越来越便捷的支付方式,让人对钱的感觉越来越没感觉,以前没钱了,还要跑银行ATM排队取,钱取出来拿在 手上还会掂量掂量,钱是有分量的。而快捷支付让人感觉钱就是一堆数字而已,越加容易冲动消费,在不知不觉中已经负债累累。 钱充之后,依旧挂着脚本,而基友小A则去问别人拿新策略了。一边继续挂着,一边开始排查程序错误,一开始还是挺稳健的,然而 就一下午的事情,我刚充的钱又败完了,而小A充1000用的新策略也输光了。
小A败光了就放弃了,而我像魔怔了一样,觉得是本金还是不够,而且抗的波数不够,既然害怕这种连续出现的情况, 为何我不直接跟连续呢,比如出现3次连续,我才开始继续买连续,我又充了2560进去,能够抗十三波一直不中。 同样,测试初期都是好的,又挂了一晚上,事实证明,我还是太naive了,早上六点多起来还是赚的,睡了个 回笼觉,八点多起,发现钱又输光了...心情一下跌落到谷底,唉,不知不觉就输了四千多,四千多啊!!! 难过得饭都吃不下,狗东给我打电话让我到楼下拿书都没接,我到底在干嘛啊?并立下各种Flag,再碰投机 倒把的东西,是狗。
第四章:真香
正当我想着算了,花4000多买个教训吧,以后别相信这种投机倒把的东西就好,剩下几天好好写书,别再折腾这些东西。 然而世间万物都离不开『 真香定律 』。
晚上小A又给我案例了一个新的APP
相比起之前的APP,这个是可以 1块起投 的(之前的10块)。
行吧,我又冲了 2426 进去,只是想回本...因为还没有出策略,所以我还是用的之前那个平台的策略买, 下注的基数小了,能抗的波数多了,就稳了,然而结果依旧是输得一干二净。
小A开始疯狂炫富:
在我的再三催促下下,小A终于把下注的策略画出了如下这个下注流程图。
行吧,流程图看上去很复杂,其实捋一捋就是下述这样的策略(只买单双):
- 1.最新两条记录结果不一样,连续三次一样,连续八次一样,买相反。
- 2.最新两条记录结果一样,连续四次一样,连续少于七次,买相同。
行吧,策略搞到手了,接着就是抓包和用Python编写爬虫来模拟下注了。
第五章:神兵加持
打开APP,开发者工具打开布局边界,内容面板没有出现边界,行吧不是原生Android,基本就是H5了。 打开 Charlse抓包工具 抓下包(抓包教程可自行百度),可以看到APP陆陆续续发出的请求。
点开其中一个 lotteryOpenCache 可以看到对应的响应的结果如下( 浏览器插件JSON-Handle ):
行吧,大概可以确定是每一把的开奖结果的接口了,接下来是看下传递的参数:
行吧,就是传递JSON数据,但是这个开奖结果要登录后才能访问,肯定是存在cookies或者token这里机制的, 果不其然,点击Cookies选项可以看到:
最后看下请求头如下:
行吧,参数啥的,都有了,我们用Python requests库 来模拟一波请求吧,看是否能得到对应的结果。
import requests as r headers = { 'origin': 'https://m.sfcappwz4.com', 'user-agent': 'Mozilla/5.0 (Linux; Android 8.1.0; OE106 Build/OPM1.171019.026; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/62.0.3202.84 Mobile Safari/537.36', 'content-type': 'application/json', 'cookie':'JSESSIONID=BDCD384F2DAD64E83BC1A6EBFCADB479', 'referer':'https://m.sfcappwz4.com/lottery/K3/OG1K3', 'x-requested-with':'com.bright.aiwprtuon' } def get_result(): resp = r.post('https://m.sfcappwz4.com/tools/_ajax/cache/lotteryOpenCache', headers=headers, json={"requirement": ["OG1K3"]}) print(resp.json()) if __name__ == '__main__': get_result() 复制代码
运行后输出结果如下:
行吧,可以正确拿到数据,接着我们就该考虑如何获得这个Cookie了,这里后台比较顽皮,它不是在登录成功后 分配Cookies,而是在进去APP的时候就分配了,后续如果登录成功才会一直使用这个Cookie。
后续的所有请求都是带着这个cookie。
行吧,就是先访问这个 getSiteInitData 接口,拿到响应头里的 set-cookie ,保存,然后去执行登录, 接着我们来看下登录接口,也是传递的JSON字符串:
一看参数大概就能猜出什么了,依次是:账号,密码,有效码,时间,是否默认登录,除了密码,其他参数 都比较简单,固定字符串,时间戳,密码的话,猜测是MD5,复制下字符串往网上在线MD5解密网站一丢:www.cmd5.com/,果不其然:
行吧,接着就是模拟登录了,这里用到 hashlib库 进行md5加密:
import hashlib hl = hashlib.md5() def auto_login(): global accountId hl.update(account_pawd.encode(encoding='utf-8')) json_params = { 'loginName': account_name, 'loginPwd': hl.hexdigest(), 'validCode': '', 'validateDate': str(int(round(time.time() * 1000))), 'isdefaultLogin': 'true' } headers['referer'] = 'https://m.sfcappwz3.com/login' headers['x-requested-with'] = 'com.bright.aiwprtuon' resp = r.post('https://m.sfcappwz3.com/tools/_ajax/login', json=json_params, headers=headers) # 获取accountId accountId = resp.json()['data']['user']['userDetail']['accountId'] 复制代码
模拟登录成功后,带着Cookie就可以去访问所有的接口了,其他的接口也是如法炮制,设置请求头,传对应 的数据,这里就不重复复述了,都是些繁琐的操作,加上策略直接给完整脚本。
""" 自动投脚本 """ import hashlib import time import requests as r from apscheduler.schedulers.blocking import BlockingScheduler cookies = '' accountId = '' # 用户id playIds = ['K3002001010', 'K3002001011'] # 玩的种类,依次是大小和单双 is_first_open = True # 是否刚打开 result_list = [] # 存储所有结果的数组 purchase_base = 100 # 购买基数 ratio = 1.96 # 中奖倍率 price_list = [] # 投入金额 cur_price_pos = 0 # 当前投入金额游标 cur_purchase_type = '' # 当前下注的类别 account_name = '' # 账号 account_pawd = '' # 密码 cur_money = 0 # 当前余额 hl = hashlib.md5() headers = { 'origin': 'https://m.sfcappwz4.com', 'user-agent': 'Mozilla/5.0 (Linux; Android 8.1.0; OE106 Build/OPM1.171019.026; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/62.0.3202.84 Mobile Safari/537.36', 'content-type': 'application/json', 'accept': '*/*', 'accept-language': 'zh-CN,en-US;q=0.9' } # 1.模拟访问拿到Cookies def fetch_cookies(): global cookies resp = r.post('https://m.sfcappwz4.com/tools/_ajax/getSiteInitData', headers=headers, json={"requirement": ["footerConfig", "helpConfig", "h5BannerList", "gradeList", "noticeData", "rankingList", "activityConfig", "defaultPhotoList", "lotteryConfig", "lotteryList", "rewardData", "config"], "cacheData": {}}) cookies = resp.headers['set-cookie'].split(';')[0] headers['cookie'] = cookies # 2.模拟登陆 def auto_login(): global accountId hl.update(account_pawd.encode(encoding='utf-8')) json_params = { 'loginName': account_name, 'loginPwd': hl.hexdigest(), 'validCode': '', 'validateDate': str(int(round(time.time() * 1000))), 'isdefaultLogin': 'true' } headers['referer'] = 'https://m.sfcappwz3.com/login' headers['x-requested-with'] = 'com.bright.aiwprtuon' resp = r.post('https://m.sfcappwz3.com/tools/_ajax/login', json=json_params, headers=headers) # 获取accountId accountId = resp.json()['data']['user']['userDetail']['accountId'] # 3.获得开奖结果 def get_result(): global is_first_open global result_list headers['origin'] = 'https://m.sfcappwz4.com' headers['cookie'] = cookies headers['referer'] = 'https://m.sfcappwz4.com/lottery/K3/OG1K3' headers['x-requested-with'] = 'com.bright.aiwprtuon' resp = r.post('https://m.sfcappwz4.com/tools/_ajax/cache/lotteryOpenCache', headers=headers, json={"requirement": ["OG1K3"]}) num_list = [] # 获取最新期数 curissueNo = int(resp.json()['data']['backData']['lotteryOpen'][0]['issueNo']) + 1 curissueNo_str = str(curissueNo) # 判断是不是最后一期,是的话更新为第二天的第一期 if curissueNo_str[8:len(curissueNo_str)] == '1441': curissueNo = time.strftime('%Y%m%d') + '001' print("最新期数:", curissueNo) for n in resp.json()['data']['backData']['lotteryOpen']: num_list.append(n['count']) if len(result_list) == 0: result_list.extend(num_list) elif len(result_list) == 10: result_list.insert(0, num_list[0]) result_list.pop() return curissueNo # 4.获取当前余额的方法 def get_money(): global cur_money headers['origin'] = 'https://m.sfcappwz4.com' headers['cookie'] = cookies headers['referer'] = 'https://m.sfcappwz4.com/userCenter/userCenterMenu' headers['x-requested-with'] = 'com.bright.aiwprtuon' resp = r.post('https://m.sfcappwz4.com/tools/_ajax//getUserBanlance', headers=headers, json={"userName": account_name}) cur_money = float(resp.json()['data']['money']) print("当前余额:", resp.json()['data']['money']) init_purchase_list() # 5.自动下注的方法 def auto_buy(choose, curissueNo): global cur_purchase_type cur_purchase_type = choose playId = playIds[1] # 下注类别id buy_price = purchase_base # 如果游标到达危险阀值,只投10块 if cur_price_pos >= len(price_list) - 1: if len(price_list) == 1: buy_price = 1 else: buy_price = 10 else: buy_price = price_list[cur_price_pos] json_params = { 'accountId': accountId, 'clientTime': str(int(round(time.time() * 1000))), 'gameId': 'OG1K3', 'issue': str(curissueNo), 'item': [str({ 'methodid': 'K3002001001', 'nums': 1, 'rebate': '0.00', 'times': buy_price, 'money': buy_price, 'playId': [playId], 'mode': '1', 'issueNo': str(curissueNo), 'codes': choose })] } headers['origin'] = 'https://m.sfcappwz3.com' headers['cookie'] = cookies headers['referer'] = 'https://m.sfcappwz3.com/lottery/K3/OG1K3' headers['x-requested-with'] = 'com.bright.aiwprtuon' resp = r.post('https://m.sfcappwz3.com/tools/_ajax/OG1K3/betSingle', headers=headers, json=json_params) if resp.json()['code'] != 'success': print(resp.text) print("下注【", choose, "】 金额【", buy_price, "】") print('=' * 50) # 6.下注算法 def predict(): global result_list global cur_price_pos global cur_purchase_type curissueNo = get_result() print("开奖数字:", result_list) size_str_list = [] single_str_list = [] for num in result_list: if num > 10: size_str_list.append('大') else: size_str_list.append('小') if num % 2 == 0: single_str_list.append('双') else: single_str_list.append('单') print("大小结果:", size_str_list) print("单双结果:", single_str_list) # 获取第一项 size_first = size_str_list[0] single_first = single_str_list[0] # 判断上一把有没有中,中了重置投钱下标 if cur_purchase_type == '': pass elif cur_purchase_type == size_first or cur_purchase_type == single_first: cur_price_pos = 0 print("中了!!!") get_money() else: cur_price_pos += 1 print("没中!!!") # 判断相同记录条数 repeat_count = 1 for single in single_str_list[1:8]: if single == single_first: repeat_count += 1 else: break if repeat_count in [1, 3, 8]: if single_first == '单': auto_buy("双", curissueNo) else: auto_buy("单", curissueNo) elif repeat_count == 2: if single_str_list[2] == single_str_list[3]: if single_first == '单': auto_buy("双", curissueNo) else: auto_buy("单", curissueNo) else: auto_buy(single_first, curissueNo) elif repeat_count in [4, 5, 6, 7]: auto_buy(single_first, curissueNo) # 构建倍率列表,保证赢前后收益 - 投入 > 购买基数 def init_purchase_list(): global price_list cost = purchase_base price_list = [purchase_base] # 其他进行动态计算 for i in range(10): # 购买价格其实区间(2倍) start_price = purchase_base * (2 ** i) # 购买价格极限区间(3倍) end_price = purchase_base * (3 ** i) # 保证没把不亏就行 for j in range(start_price, end_price + 1): if j * ratio - cost - j > 1 and cost + j <= round(cur_money / 2): cost += j price_list.append(j) break print("生成投入金额列表:", price_list) # 重新登录 def login_again(): print("重新登录!") fetch_cookies() auto_login() if __name__ == '__main__': init_purchase_list() fetch_cookies() auto_login() predict() scheduler = BlockingScheduler() # 每隔60s下注一次 scheduler.add_job(predict, 'interval', max_instances=10, seconds=60) scheduler.start() 复制代码
接着就可以把脚本丢到云服务上执行了,这里用的是nohup命令让脚本在后台运行。
nohup python3 -u xiaozheng.py > xiao.out 2>&1 & 复制代码
然后执行 tail -f xiao.out 或者 cat xiao.out 可以查看到日志输出记录。
因为用的是官方的接口,也没有出现接口延迟的问题...一切貌似就这样顺理成章的执行着, 然而最后的结果,依旧躲不过输得一干二净。
我开始反省,为何剧本的最后结局都是输光,人投也是采用相同的策略,人赚,脚本投就亏。
- 1.脚本24小时跑, 策略固定 ,而彩票规律可能是不断变化的,人偶尔也会变通下;
- 2.人不会一直买,而且出现连续不中的时候会停止观察,找稍微稳定一点的时间点切入;
既然这样固定策略必凉,为何不让别人在投的时候,顺道也帮我投了呢, 爱屋及乌 !
第六章:爱屋及乌
在我输光输净后小A又疯狂的炫富:
既然小A那么稳,为何不让他投的时候帮我也投了呢,坐收渔翁之利。行吧,既然接口我都有了,为何不能 自己写个APP呢?所以有了下面这样的计划:
- 1.先写一个APP,小A登录的时,顺带也登录下我的账号,然后下注的时候,我的账号也跟着下注。
- 2.编写API接口给APP调用,小A下注的时候顺带调用这个接口,后台接收到下注信息,批量下注。
正当我准备打开自己写好的APP截个图的时候,发现自己写的APP竟然登录不了了,啧啧,应该是昨晚 维护了,把接口改了。
行吧,顽皮,批量替换下基地址,登录成功后,竟然又自动退出来了。利用 Android Profiler 性能调优工具 抓一波包,login接口是success的,lotteryOpenCache的响应码竟然是 nologin :
猜测是Cookie变了,打开它们的APP登录,打开结果页,抓包看看:
果不其然,多了个sto-id-20480,左侧搜下这个串东西,在哪里拿到的,过滤下,只查看响应头:
定位下可以找到:
接着是另外一段:JSESSIONID=53287B9851CF658D255A029F1426C82A,如果炮制找出是在哪个接口 的响应头set-cookie的,如下:
总结下就是依次:
- 1.访问:m.suibianwanba.com/ 拿sto-id
- 2.访问: m.suibianwanba.com/tools/_ajax… 拿JSESSIONID
后续所有访问请求头cookie设置为这两个字符串即可,同样贴出大概的代码,显示接口:
然后是调用页面:
APP的下注页面:
页面简陋,但是功能齐全,好吧,接着就把APP丢给小A先帮我投着先,接下来就是写接口给自己的APP调用了, 不然怎么弄成批量的方式,这里用到的Python轻量级Web库: Flask 。
直接通过pip命令进行安装即可: pip install flask
,官方的一个最简单示例:
# coding=utf-8 from flask import Flask app = Flask(__name__) @app.route("/") def hello(): return "Hello Flask!" if __name__ == "__main__": app.run() 复制代码
运行后打开127.0.0.1:500可以看到返回了Hello Flask!
关于Flask的使用,这里不会讲解,因为也不涉及到什么高深内容,更多内容可以自行查阅官方文档: flask.pocoo.org/docs/1.0/ 简单说下我们要做的事情,需要两个接口(传参用Json字符串)。
- add_account : 添加账号 , POST ,传参:用户名与密码,拿到数据后模拟登录,拿到对应的Cookies,存到 MySQL 数据库中;
- bet : 下注 , POST ,传参:下注类型与下注金额,拿到数据后批量调用下注方法。
行吧,官方貌似又改接口了,又重新抓了一波包(其实就是改了跟地址而已)...
限于篇幅,不太过具体的去讲解代码,显示工程的结构:
创建了一个app目录,下面有一个 __init__.py
文件:
from flask import Flask from flask_sqlalchemy import SQLAlchemy app = Flask(__name__) app.config.from_object('config') db = SQLAlchemy(app) from app import models, views 复制代码
代码中初始化了一个Flask实例,读取配置文件,创建了一个SQLAlchemy实例,导入了models和views文件。 config.py内容如下:
SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://root:Jay12345@localhost:3306/q9g' SQLALCHEMY_TRACK_MODIFICATIONS = True 复制代码
然后是定义数据结构: 账户名+密码+Cookie+账户ID(下注用) ,这里并不使用原生 SQL 语句去操作MySQL数据库,而是使用ORM框架—— SQLAlchemy ,直接通过pip命令安装即可: pip install flask-sqlalchemy
,model.py的代码如下:
from app import db class User(db.Model): __tablename = 'user' __table_args__ = {'useexisting': True} _id = db.Column(db.Integer, primary_key=True, autoincrement=True) account = db.Column(db.TEXT) pwd = db.Column(db.TEXT) cookies = db.Column(db.TEXT) accoutId = db.Column(db.TEXT) @property def id(self): return self.id if __name__ == '__main__': db.create_all() 复制代码
还有安装一个 flask-script 模块,用于通过命令行来操作Flask,同样可以通过pip命令进行安装: pip install flask-script
,新建一个manager.py,在里面启用Flask项目。
from app import app from flask_script import Manager manager = Manager(app) if __name__ == '__main__': manager.run() 复制代码
准备工作差不多了,接着开始编写我们的登录接口:
import hashlib import time import requests as r from flask import request, jsonify from app import app, db from app.models import User headers = { 'origin': 'https://m.suibianwanba3.com', 'user-agent': 'Mozilla/5.0 (Linux; Android 8.1.0; OE106 Build/OPM1.171019.026; wv) AppleWebKit/537.36 ' '(KHTML, like Gecko) Version/4.0 Chrome/62.0.3202.84 Mobile Safari/537.36 ', 'content-type': 'application/json', 'x-requested-with': 'com.bright.extnetiop', } @app.route("/add_account", methods=['GET', 'POST']) def add_account(): account = '' pwd = '' if request.method == 'GET': account = request.args.get("account") pwd = request.args.get("pwd") elif request.method == 'POST': account = request.json['account'] pwd = request.json['pwd'] # 密码加密 hl = hashlib.md5() hl.update(pwd.encode(encoding='utf-8')) # 实例化用户实例 user = User() user.account = account user.pwd = hl.hexdigest() msg = auto_login(user) return jsonify( {'code': '200', 'data': [{'account': account, 'pwd': pwd}], 'msg': (msg if msg is not None else "登录成功")}) @app.route("/bet", methods=['GET', 'POST']) def bet(): choose = '' price = '' cur_no = '' if request.method == 'GET': choose = request.args.get("choose") price = request.args.get("price") cur_no = request.args.get("cur_no") elif request.method == 'POST': choose = request.json['choose'] price = request.json['price'] cur_no = request.json['cur_no'] # 批量下注 result_list = [] users = User.query.all() for user in users: result_list.append(auto_bet(user, choose, price, cur_no)) return jsonify({'code': '200', 'data': result_list, 'msg': '访问成功'}) # 获取Cookie def fetch_cookies(user): if 'cookie' in headers: headers.pop("cookie") cookie_resp = r.post("https://m.suibianwanba3.com/tools/_ajax/cache/getSiteInitData", headers=headers, json={"requirement": ["footerConfig", "helpConfig", "h5BannerList", "gradeList", "noticeData", "rankingList", "activityConfig", "defaultPhotoList", "lotteryConfig", "lotteryList", "rewardData", "config"], "cacheData": {}}) if cookie_resp is not None: cookie = cookie_resp.headers.get('set-cookie') if cookie is not None: headers['cookie'] = cookie.split(';')[0] user.cookies = cookie.split(';')[0] # 模拟登录 def auto_login(user): fetch_cookies(user) json_params = { 'loginName': user.account, 'loginPwd': user.pwd, 'validCode': '', 'validateDate': str(int(round(time.time() * 1000))), 'isdefaultLogin': 'true' } resp = r.post("https://m.suibianwanba3.com/tools/_ajax/login", headers=headers, json=json_params) if resp is not None: if resp.json()['code'] == 'success': user.accoutId = resp.json()['data']['user']['userDetail']['accountId'] db.session.add(user) db.session.commit() else: print(resp.json()['msg']) return resp.json()['msg'] 复制代码
运行项目,然后使用浏览器或者PostMan模拟请求:
调用这个接口数次,获取账户名+密码+Cookie+账户ID,然后存入数据库,存入后的结果如图所示:
可以,都存到数据库里,接着我们来编写下注接口:
playIds = ['K3002001010', 'K3002001011'] # 下注种类,依次为大小和单双 @app.route("/bet", methods=['GET', 'POST']) def bet(): choose = '' price = '' cur_no = '' if request.method == 'GET': choose = request.args.get("choose") price = request.args.get("price") cur_no = request.args.get("cur_no") elif request.method == 'POST': choose = request.json['choose'] price = request.json['price'] cur_no = request.json['cur_no'] # 批量下注 result_list = [] users = User.query.all() for user in users: result_list.append(auto_bet(user, choose, price, cur_no)) return jsonify({'code': '200', 'data': result_list, 'msg': '访问成功'}) # 下注 def auto_bet(user, choose, price, cur_no): play_id = playIds[0] if choose in ['单', '双']: play_id = playIds[1] json_params = { 'accountId': user.accoutId, 'clientTime': str(int(round(time.time() * 1000))), 'gameId': 'OG1K3', 'issue': str(cur_no), 'item': [str({ 'methodid': 'K3002001001', 'nums': 1, 'rebate': '0.00', 'times': price, 'money': price, 'playId': [play_id], 'mode': '1', 'issueNo': str(cur_no), 'codes': choose })] } headers['cookie'] = user.cookies resp = r.post('https://m.suibianwanba3.com/tools/_ajax/OG1K3/betSingle', headers=headers, json=json_params) print(resp.json()) return resp.json() 复制代码
同样模拟请求一波,看看响应的结果:
这里没有做cookie过期的相关处理逻辑,做的话也比较简单,对异常信息进行过滤,然后调用登录相关的 方法重新登录,更新一下数据库里账户对应的Cookie即可。
行吧,本地接口跑通了,接下来把项目部署到服务器上,让外网能够访问我们的接口,感觉用 Docker 部署 就有点装逼了,所以这里还是只用FTP/SFTP工具把代码上传到云服务器上。
第七章:言听计从
官方维护...明天再更
第八章:屠龙计划
官方维护...明天再更
第九章:终章(填坑)
1.到底什么是洗钱 2.彩票开奖结果真的是随机的吗? 等等...
Join in
欢迎大家加入小猪的Python学习交流群一起讨论,可以添加下述的机器人小号 RobotPig ,验证信息里包含: Python , python , py , Py , 加群 , 交易 , 屁眼 中的一个关键词即可通过;发送『加群』加入群聊。
或者在公众号『 抠腚男孩 』中发送加群~
参考文献:
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
The Art of Computer Programming, Volume 2
Knuth, Donald E. / Addison-Wesley Professional / 1997-11-04 / USD 79.99
Finally, after a wait of more than thirty-five years, the first part of Volume 4 is at last ready for publication. Check out the boxed set that brings together Volumes 1 - 4A in one elegant case, and ......一起来看看 《The Art of Computer Programming, Volume 2》 这本书的介绍吧!