[TOC]
趣消除App自動(dòng)化 - 成語(yǔ)消消樂-全自動(dòng)化
目標(biāo)
趣消除App自動(dòng)化 - 成語(yǔ)消消樂-半自動(dòng)化
這篇文章實(shí)現(xiàn)了成語(yǔ)消消樂
的半自動(dòng)化:
- 用戶點(diǎn)擊開始一局游戲
- 代碼自動(dòng)答題
- 對(duì)代碼沒有找到的成語(yǔ)数冬,用戶自己點(diǎn)擊成語(yǔ)贏得游戲
這篇文章的目的是全自動(dòng)化:
- 代碼自動(dòng)開始一局游戲
- 代碼自動(dòng)答題
- 對(duì)沒有全部找到的,放棄這局:等待對(duì)方贏得游戲衩椒;
- 開始下一局游戲
寫在前面:
- 自己的文章從不介紹背景知識(shí)境钟,直接上代碼折汞;因?yàn)槎ㄎ粚?shí)戰(zhàn)锅尘,非教程
- 看了些評(píng)論井辜,多是
不明覺厲
著摔,希望你可以評(píng)主題相關(guān)的討論或感謝 - 這篇文章
威力巨大
[呵呵]缓窜,所以不要做惡;不要做惡;不要做惡禾锤;
不要做惡:
比如游戲有12個(gè)成語(yǔ)要找私股,但代碼只答對(duì)了11個(gè),還有1個(gè)成語(yǔ)4個(gè)字恩掷,共有4*3*2*1=24
種排列組合倡鲸,請(qǐng)讀者不要發(fā)24個(gè)請(qǐng)求來找到這最后一個(gè)成語(yǔ),這是樓主認(rèn)為的'做惡'黄娘,也是對(duì)自動(dòng)化:對(duì)沒有全部找到的峭状,放棄這局:等待對(duì)方贏得游戲
做出的取舍;你可以用游戲里的認(rèn)輸
和提示
寫這篇文章與代碼的目的:
- 虛榮:有讀者閱讀逼争、評(píng)論
- 金錢:贏得游戲有幾分錢
- 時(shí)間:游戲里插了很廣告优床,跳過廣告;自動(dòng)化節(jié)約自己時(shí)間
- 能力:要寫能用的代碼誓焦,一定要學(xué)點(diǎn)什么胆敞,比如學(xué)習(xí)了websocket庫(kù)
- 愛惜:自己的手機(jī)用了3年了,移植到電腦上來執(zhí)行杂伟,可以讓手機(jī)再戰(zhàn)一年啊
- 成就:代碼和文章等作品移层;不同維度地'虐人'的快感[鄙視]
好了,希望你找到了學(xué)習(xí)的興趣與動(dòng)力赫粥,上代碼
測(cè)試環(huán)境
App: 趣消除App
iOS版本幽钢、扶我起來學(xué)數(shù)學(xué)App
iOS版本
工具: python、Charles傅是、python第三方庫(kù)websocket
背景知識(shí):python匪燕、抓包、websocket
解決
分析
成語(yǔ)消消樂
有2個(gè)接口:
- https://king.hddgood.com/king_api/v1/game/join_game[http]
- wss://king.hddgood.com/websock_m/websock_message?uid={}&gameid={}&token={}[websocket]
-
game/join_game
接口會(huì)返回websock_m/websock_message
接口需要的gameid
喧笔;gameid
每局都不同 -
uid
對(duì)每個(gè)賬號(hào)是固定 -
token
對(duì)一次登入是固定帽驯,每局游戲都一樣; - 游戲的消息來回傳遞都在
websock_m/websock_message
接口websocket協(xié)議里完成
POST /king_api/v1/game/join_game HTTP/1.1
Host: king.hddgood.com
A-Token-Header: PTtWUFdWUkBFHEVZCVcNdUtVWwdc=
Cookie: UM_distinctid=16b27e625da1ef-038c4847dc733-336d7451-4a640-16b27e625dd490; cn_1276022107_dplus=%7B%22distinct_id%22%3A%20%2216b27e625da1ef-038c4847dc733-336d7451-4a640-16b27e625dd490%22%2C%22%24_sessionid%22%3A%20104%2C%22%24_sessionTime%22%3A%201561087099%2C%22%24dp%22%3A%200%2C%22%24_sessionPVTime%22%3A%201561087099%2C%22initial_view_time%22%3A%20%221559738991%22%2C%22initial_referrer%22%3A%20%22%24direct%22%2C%22initial_referrer_domain%22%3A%20%22%24direct%22%2C%22%24recent_outside_referrer%22%3A%20%22%24direct%22%7D; CNZZDATA1276022107=326225286-1559738991-%7C1561086230
uid=1457362&rank=11&type=G
HTTP/1.1 200
Content-Type: application/json;charset=UTF-8
Connection: close
{"success":true,"msg":"操作成功","code":"200","codemsg":"操作成功","result":{"gameid":"G11-810737","dup":0,"starter":472251}}
工作原理
寫2個(gè)文件:chengyu-auto.py
[代碼文件]书闸、chengyu.text
[數(shù)據(jù)文件]
-
chengyu-auto.py
從asking
消息里解析出ask_string
到chengyu.text
文件里查找是否包含相應(yīng)的成語(yǔ) - 自動(dòng)提交成語(yǔ)答案
-
chengyu.text
文件剛開始是空的尼变;在每局游戲結(jié)束時(shí),游戲都會(huì)發(fā)送game_result
消息給我們浆劲,里面有這局游戲的答案成語(yǔ)嫌术,把這些成語(yǔ)寫到文件中 - 玩的局?jǐn)?shù)越多,
chengyu.text
文件包含的成語(yǔ)越多牌借,查找到答案的可能性越大
代碼
需要安裝第三方python庫(kù):websockets
chengyu-auto.py
:
#!/usr/bin/env python3
# coding=utf-8
'''
# 趣消除App-成語(yǔ)消消樂全自動(dòng)化度气;
# App版本:1.1.2
# App地址:https://itunes.apple.com/cn/app/id1449545954
提現(xiàn)非常迅速
'''
import re
import time
import datetime
import random
import json
import sys
import logging
import collections
import pathlib
import requests
Red = '\033[0;31m'
Green = '\033[0;32m'
Yellow = '\033[0;33m'
Blue = '\033[0;34m'
Purple = '\033[0;35m'
Cyan = '\033[0;36m'
White = '\033[0;37m'
colors = {
0:Red,
1:Purple,
2:Yellow,
3:Blue,
4:White,
}
# 這些變量的值可以通過像Charles抓包軟件獲得
# 賬號(hào)變量
# ------------------------------------------------
# A_Token_Header的一些結(jié)論:
# 1.每個(gè)賬號(hào)不同;
# 2.同一個(gè)賬號(hào)每次登錄時(shí)也是不一樣的
# 3.同一個(gè)賬號(hào)膨报,退出時(shí)磷籍,只要不登錄适荣,上次的A-Token-Header的值還有效,只有再登錄時(shí)院领,上次的token值才失敗
A_Token_Header_zxg = 'PTtWUFdWUkBFHEVZCVcNdUtVWwdc'
# Cookie的一些結(jié)論:
# 1.同一個(gè)賬號(hào)弛矛,退出或再登錄,都不用修改比然,一直有效
# 2.值為空也可以
Cookie_zxg = ''
# UUID的一些結(jié)論:
# 1.固定不變
UUID_zxg = '1457362'
# ------------------------------------------------
api_ = 'https://king.hddgood.com/king_api/v1/'
class QuXiaoChuUser():
headers = {
'Host': 'king.hddgood.com',
'Accept': 'application/json, text/plain, */*',
'Accept-Language': 'zh-cn',
'Origin': 'https://king.hddgood.com',
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 12_1_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/16D57/; quxiaochu/ios v1.1.2',
'Referer': 'https://king.hddgood.com/'
}
data = {
'uid': '',
'channel': '',
'version': '1.1.2',
'os': 'ios',
'web_ver': '20190261'
}
SLEEP = 0.5
def __init__(self, uid, token_header, cookie):
self.uid = uid
self.headers = dict(QuXiaoChuUser.headers)
self.headers['A-Token-Header'] = token_header
self.token_header = token_header
self.headers['Cookie'] = cookie
def game_chengyu_join_game(self, rank):
'''
成語(yǔ)消消樂-獲取游戲id
https://king.hddgood.com/king_api/v1/game/join_game
{"success":true,"msg":"操作成功","code":"200","codemsg":"操作成功","result":{"gameid":"G15-3232777","dup":0,"starter":531492}}
'''
print("成語(yǔ)消消樂-獲取游戲id {}".format(self.uid))
data = self._uid_data()
# 1:書童丈氓;2:儒生;15:殿閣大學(xué)士
data['rank'] = str(rank)
data['type'] = 'G'
api = self._genapi('game/join_game')
result = self._post(api, self.headers, data)
return json.loads(result)
def _uid_data(self):
return {'uid': self.uid}
@staticmethod
def _genapi(path):
return 'https://king.hddgood.com/king_api/v1/' + path
@staticmethod
def _post(api, headers, data, p=logging.warning):
time.sleep(QuXiaoChuUser.SLEEP)
res = requests.post(api, headers=headers, data=data, verify=False)
print(res.url)
result = res.text
print(result)
print('')
return result
class Chengyu(object):
def __init__(self):
path = pathlib.PurePath(__file__)
path = path.parent.joinpath('chengyu.text')
self.dictpath = str(path)
self.chengyu = set()
with open(self.dictpath, 'rt') as f:
for line in f.readlines():
self.chengyu.add(line.strip())
self.answers = list()
self.ask_string = ''
# {'和':[1,8], '我':[11]}
self.char_indexs_dict = dict()
# {1:'和', 8:'和', 11:'我'}
self.index_char_dict = dict()
self.count = 0
# 自動(dòng)提交答案的網(wǎng)絡(luò)發(fā)送次數(shù)
self.auto_send_answers = list()
self.ack_true_answers = list()
# 找到的的成語(yǔ)中各異字符為2個(gè)的答案數(shù)量:如 [真真假假]
self.answer_2chars_count = 0
# {'中流砥柱':[1,9,21,25]}
self.answer_indexs_dict = dict()
# {'中流砥柱':set('中流砥柱')}
self.answer_charset_dict = dict()
# 查找到的錯(cuò)誤答案
self.error_answers = []
# ---------------------------------------------
def find_answers_v2(self, ask_string):
'''
在內(nèi)存成語(yǔ)字典查找答案
'''
ask_set = set(ask_string)
for i, c in enumerate(ask_string):
self.char_indexs_dict.setdefault(c, []).append(i)
self.index_char_dict = dict( zip(range(len(ask_string)), ask_string))
max_count = (len(ask_string) / 4 ) * 1.5
for item in self.chengyu:
item_set = self.answer_charset_dict.setdefault(item, set(item))
if not (item_set - ask_set):
self.answers.append(item)
if len(item_set)<4:
self.answer_2chars_count += 1
if len(self.answers) - self.answer_2chars_count >= max_count :
self.count = len(self.answers)
return
self.count = len(self.answers)
async def auto_answer(self, flow):
if len(self.answers):
item = self.answers[0]
answer_index = []
counter = collections.Counter(item)
for char, count in counter.items():
if self.char_indexs_dict[char]:
if len(self.char_indexs_dict[char]) < count:
self.error_answers.append(item)
self.answers.remove(item)
return
else:
pass
for c in item:
if self.char_indexs_dict[c]:
index = self.char_indexs_dict[c][0]
answer_index.append( str(index) )
del self.char_indexs_dict[c][0]
else:
pass
if len(set(answer_index)) < 4:
print('算法有錯(cuò)誤:{} 小于4'.format(answer_index))
send_message = {
'answer': item,
'answer_index': answer_index,
'type': 'answer'
}
mm = json.dumps(send_message)
# -----------------------
print(mm)
# -----------------------
self.answer_indexs_dict[item] = answer_index
# 向服務(wù)器發(fā)送消息
self.auto_send_answers.append(item)
self.answers.remove(item)
await flow.send(mm)
# time.sleep(0.5)
def add_new_worlds_to_memory(self, m):
'''
把答案增加到內(nèi)存字典中
'''
if len(self.ack_true_answers) < len(m['all_answer']):
for answer in m['all_answer']:
self.chengyu.add(answer['phrase'])
print('\033[1;31m 共收錄{}個(gè)成語(yǔ) \033[0m'.format(len(self.chengyu)))
def add_new_worlds_to_file(self, m):
'''
把答案增加到文件中
'''
if len(self.ack_true_answers) < len(m['all_answer']):
with open(self.dictpath, 'wt') as f:
l = list(self.chengyu)
l.sort()
for item in l:
f.write(item)
f.write('\n')
def print_answers(self):
'''
圖形化强法、色彩化顯示答案
'''
self.print_color('共找到 {}/{} 個(gè)成語(yǔ)'.format(self.count, len(self.ask_string)//4))
self.print_color('錯(cuò)誤成語(yǔ) {}'.format(self.error_answers))
self.print_color('共自動(dòng) {} 次提交:{}'.format(len(self.auto_send_answers),self.auto_send_answers))
self.print_color('已確認(rèn) {} 個(gè)提交:{}'.format(len(self.ack_true_answers),self.ack_true_answers))
self.print_color('問題 {}'.format(self.ask_string))
for item in self.answers:
self.print_color(item)
# self.print_matrix(item)
if (not self.answers) and self.index_char_dict:
self.print_matrix()
def print_matrix(self, item = []):
chars_in_line = 6
length = len(self.ask_string)
lines = (length + chars_in_line - 1) // chars_in_line
PADDING = ' '*(lines * chars_in_line - length)
is_need_padding = len(PADDING) != 0
self.print_color('--'*chars_in_line)
global colors, White
for i, c in self.index_char_dict.items():
end = ''
if (i+1) % chars_in_line == 0 or (i+1) == length:
end = '\n'
color = White
if c in item:
color = colors[item.index(c)]
line, first = divmod(i, chars_in_line)
if is_need_padding and first == 0 and (line + 1 == lines):
c = PADDING + c
self.print_color(c, end=end, color=color)
self.print_color('--'*chars_in_line)
def print_color(self, message, end='\n', color=Red):
print('{}{}\033[0m'.format(color, message), end=end)
def reset_data_to_init(self):
self.ask_string = ''
self.answers.clear()
self.index_char_dict.clear()
self.count = 0
self.answer_2chars_count = 0
self.answer_indexs_dict.clear()
self.char_indexs_dict.clear()
self.error_answers.clear()
self.ack_true_answers.clear()
self.auto_send_answers.clear()
def chengyu_auto_answer(user: QuXiaoChuUser):
'''
成語(yǔ)消消樂自動(dòng)答題
wss://king.hddgood.com/websock_m/websock_message?uid=472251&gameid=G15-3232777&token=JSdLVVRRV0ZCH0INUlYNchcDUlc=
'''
result = user.game_chengyu_join_game(g_rank)
if result['success']:
gameid = result['result']['gameid']
url = 'wss://king.hddgood.com/websock_m/websock_message?uid={}&gameid={}&token={}'
url = url.format(user.uid, gameid, user.token_header)
print(url)
import asyncio
import websockets
async def chengyu():
async with websockets.connect(url) as websocket:
print('連接成功')
global chengyu
live = True
count = 0
while live:
if count % 10 == 0:
keeplive = json.dumps({"type":"keepalive"})
await websocket.send(keeplive)
print('send keeplive')
# await asyncio.sleep(0.5)
count += 1
m = await websocket.recv()
print(f"\n{m}\n")
m = json.loads(m)
message_type = m['type']
if m.get('ask_string'):
chengyu.ask_string = m['ask_string']
# 計(jì)算答案
chengyu.find_answers_v2(chengyu.ask_string)
if message_type == 'answer':
chengyu.answer_indexs_dict[m['answer']] = m['answer_index']
# 刪除已回答正確的答案
if m.get('ack') == 1:
answer = m['answer']
chengyu.ack_true_answers.append(answer)
answer_index = chengyu.answer_indexs_dict.get(answer,[])
for i in answer_index:
chengyu.index_char_dict[int(i)] = ' '
try:
chengyu.answers.remove(m['answer'])
except:
pass
# 自動(dòng)答題
await chengyu.auto_answer(websocket)
# 顯示答案
if len(chengyu.ask_string):
chengyu.print_answers()
if message_type == 'game_result':
live = False
# 把答案增加到內(nèi)存字典中
chengyu.add_new_worlds_to_memory(m)
chengyu.add_new_worlds_to_file(m)
chengyu.reset_data_to_init()
# 其它解析
for item in m['scores']:
if str(item['uid']) == user.uid:
global g_rank
g_rank = item['rank']
print('\033[1;31m 獲得金幣: {} Rank: {}\033[0m'.format(m['coin'], g_rank))
print('\033[1;31m 游戲結(jié)束 \033[0m')
asyncio.get_event_loop().run_until_complete(chengyu())
def genUsers():
yield QuXiaoChuUser(UUID_zxg, A_Token_Header_zxg, Cookie_zxg)
g_rank = 15
chengyu = Chengyu()
if __name__ == "__main__":
for user in genUsers():
start_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
for _ in range(20):
chengyu_auto_answer(user)
time.sleep(1)
print('開始時(shí)間 ', start_time)
print('結(jié)束時(shí)間 ', time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
chengyu.text
一勞永逸
一擲千金
一曝十寒
一石二鳥
一籌莫展
一落千丈
一衣帶水
一語(yǔ)破的
...
注意:
chengyu.text
與chengyu-auto.py
放在同一目錄下
chengyu.text
收集約1926個(gè)成語(yǔ)万俗,98%能找到全部答案
參考
樓主的趣消除App
系列文章