我正在参与「兔了个兔」构思投稿大赛,详情请看:「兔了个兔」构思投稿大赛

0x0、事出必有因

新年开工榜首周,节后综合征,无心作业~

Van♂Python | 对春联?我无敌,你随意~

(图片出处:深圳卫健委公号),咱们都讨了多少开门红包哇?说粗来,让杰哥酸一下~

Van♂Python | 对春联?我无敌,你随意~

记住春节前最终一周,本想玩小游戏消磨时刻,成果却被一个 “孤岛求生” 的玩法拿捏,一怒之下 手搓”辅佐”,利用 “科技” 降维打击,直接屠榜,最终还写了一篇文章 《手搓游戏”辅佐”,你怎样跟我玩?》 记录详细的实践进程 。

Van♂Python | 对春联?我无敌,你随意~

分数是 第二名的两倍你怎样跟我玩?

Van♂Python | 对春联?我无敌,你随意~

然后,这小游戏春节的时分很接地气地推出了一系列 “春节活动”,其中有个形式叫 “以诗会友”,玩法如下:

Van♂Python | 对春联?我无敌,你随意~

em?这不纯纯的 对春联 吗?(也叫对对子、对春等),依据上联对出下联。而在游戏里的规则是这样的 :

体系给出 完好上联部分下联 (也可能全不给) 及一些 备选词,玩家依据这些 猜出完好下联,然后 将对应备选词拖拽到正确的框框中 补全下联。下联正确取得积分,切到下一题,如此循环,直至倒计时完,游戏完毕。

简略,鄙人可是 七省文状元兼参谋将军,绰号对王之王的对穿肠,会怕这个?直接开对~

Van♂Python | 对春联?我无敌,你随意~

在经历了好几局一个都对不出来后,杰哥:

Van♂Python | 对春联?我无敌,你随意~

em… 智力不够科技凑,老老实实想办法整个 辅佐 吧!

思路分析

对春联的玩法本质上便是常见的 问答类游戏,记住之前有段时刻,这类小游戏超火,什么全民答题赢现金,当时涌现了不少的 “辅佐”。剖析下这类辅佐的完成原理,能够简略拆解成这三步:

  • 辨认问题:原生类-拿到问题组件直接提取文本,非原生类-截图然后进行OCR文字辨认;
  • 检索答案:利用查找引擎、问答机器人、查题API、题库等获取问题的正确答案;
  • 主动答题:拿着检索到的答案模仿用户答题,如填空、点击选项、勾选、拖拽点击等;

思路非常清晰,接着便是依据这款小游戏的实际情况,来开发对春联的 “辅佐” 了~

Van♂Python | 对春联?我无敌,你随意~


0x1、问题辨认

小游戏非原生,直接 无脑OCR,截个屏,丢 chineseocr_lite 辨认看下作用:

Van♂Python | 对春联?我无敌,你随意~

还能够,上联正确辨认,下联只错了一个字。拿上下联的大约坐标区域 裁剪 一下,扫除无关项进步辨认速度之余,看能否进步准确度~

Van♂Python | 对春联?我无敌,你随意~

裁剪后的图片:

Van♂Python | 对春联?我无敌,你随意~

速度好像快了,但辨认率反而降低了:

Van♂Python | 对春联?我无敌,你随意~

转灰度后仍旧如此:

Van♂Python | 对春联?我无敌,你随意~

我又写了一个拼接图片的办法,测验将上下联水平拼接一波:

Van♂Python | 对春联?我无敌,你随意~

间距设置为400,辨认成果如下:

Van♂Python | 对春联?我无敌,你随意~

奇特,居然好一点,再灰度化下试试看:

Van♂Python | 对春联?我无敌,你随意~

更好了,换成其它对联试试:

Van♂Python | 对春联?我无敌,你随意~

辨认成果:

Van♂Python | 对春联?我无敌,你随意~

擦,由于填空的框框,上下联直接被拆散了,所以为了保险点,还要对辨认成果做下处理:

依据坐标判断是上联仍是下联,正则提取中文(有时会辨认出一些标点符号),最终拼接

详细代码如下:

Van♂Python | 对春联?我无敌,你随意~

运转看看作用:

Van♂Python | 对春联?我无敌,你随意~

能够,又试了几个样本发现都能比较准确地拿到上下联~


0x2、检索答案

上联拿到了,接着便是检索答案了,杰哥的思路有三:查找引擎、ChatGPT API、题库,一一测验~

① 查找引擎

没找到直接能用的查找API,只能 浏览器拜访咯,一种最粗犷的办法便是用 webbrowser 恳求URL,以百度查找为例:

while True:
    input() # 操控台每按一次回车触发一次检索
    first_couplet = extract_couplet() # 解析当时上联
    # 查找下联
    webbrowser.open("https://www.baidu.com/s?wd={}的下联".format(first_couplet)) 

运转后,每次回车都会翻开浏览器检索:

Van♂Python | 对春联?我无敌,你随意~

从查找成果中,杰哥发现了一个问题:一个上联可能有多个匹配的下联,但游戏里只要 “一个正确答案”,这就需求咱们用肉眼 + 脑子来筛选出匹配的下联。费时费力,难顶…

Van♂Python | 对春联?我无敌,你随意~

得把这个进程主动化,主动解析成果并辨认出适宜对联,思路马上来:取得网页源码 + 正则提取,先试下 request库 直接恳求URL:

Van♂Python | 对春联?我无敌,你随意~

情理之中,直接触发了 百度安全验证,那就浏览器模仿拜访吧。直接 Puppeteer库 走一波,这库之前介绍过了:

Puppeteer 是Google官方出品的经过DevTools协议口操控headless Chrome的 NodeJS 库,经过其供给的API可直接操控Chrome模仿大部分用户操作,来进行UI Test、爬虫拜访页面收集数据。而 Pyppeteer 则是Puppeteer的Python完成,背面也是依赖类似于Chrome的浏览器 → Chromium 来模仿。

直接写代码拿到网页源码:

Van♂Python | 对春联?我无敌,你随意~

运转下看看:

Van♂Python | 对春联?我无敌,你随意~

能够,成功拿到网页源码,接着便是思考怎么 写正则 了,直接写出最粗犷的匹配表达式 (应该能看懂吧~):

# 上联 → 要么是中英文逗号中的一个,要么没有 → 中文{上联的长度}
match_pattern = re.compile(r"{}[,,]?([\u4e00-\u9fa5]{{{count}}})".format(first_couplet, count=len(first_couplet)), re.S)

匹配下试试,同时把成果放到set中间接 去重

Van♂Python | 对春联?我无敌,你随意~

运转看看:

Van♂Python | 对春联?我无敌,你随意~

作用很赞,再往下细化便是:遍历 部分下联+可选词,然后核算每个下联中呈现这些字的比重(个数),最高的那个便是 “正确答案” 啦!

Van♂Python | 对春联?我无敌,你随意~

查找引擎这Part就到这,接着试试 ChatGPT ~


② ChatGPT API

ChatGPT就不用介绍了,前阵子火得一塌糊涂,注册办法能够看我之前写的《无聊试试最近很火的ChatGPT (附:注册办法)》,或许某宝直接买别人注册好的。

这里不需求像百度查找相同经过浏览器拜访,由于它供给了API,注册完账号,登录后翻开 API keys,点击 Create new secret key,创立一个秘钥:

Van♂Python | 对春联?我无敌,你随意~

注意,这个Secret Key要自己存好!网站不供给后续检查,忘记了的话只能删掉从头创立。先pip装下库:

pip install openai
# 假如很慢的话,能够用清华镜像源
# pip install -i https://pypi.tuna.tsinghua.edu.cn/simple openai

直接copy样例:

import openai
start_sequence = "\nA:"
restart_sequence = "Q: "
# Replace `<your_api_key>` with your actual OpenAI API key
openai.api_key = "<your_api_key>"
prompt = " "
while len(prompt) != 0:
    # Ask a question
    prompt = input(restart_sequence)
    # prompt = "tell me in Chinese:" + input("\n请输入要翻译的内容:")
    # Get my answer
    response = openai.Completion.create(
        engine="text-davinci-003",
        prompt=prompt,
        temperature=1,
        max_tokens=2000,
        frequency_penalty=0,
        presence_penalty=0
    )
    # Print my answer
    print(start_sequence, response["choices"][0]["text"].strip())

运转,测验发问:

Van♂Python | 对春联?我无敌,你随意~

这啥?AI自己乱编?调整话术再次打听:

Van♂Python | 对春联?我无敌,你随意~

啊,这…我多嘴问了两句:

Van♂Python | 对春联?我无敌,你随意~

牛,直接把我整无语了,可能我需求学习下《发问的艺术》吧,看来ChatGPT的创造性不太适合咱们的业务场景…

Van♂Python | 对春联?我无敌,你随意~

附:几个根本参数的意义

  • model → 要运用的模型的 ID,拜访 OpenAI Docs Models 页面能够检查悉数可用的模型
  • prompt → 生成成果的提示文本,即你想要得到的内容描绘
  • max_tokens → 生成成果时的最大 tokens 数,不能超过模型的上下文长度,能够把成果内容复制到 OpenAI Tokenizer 来了解 tokens 的计数办法
  • temperature → 操控成果的随机性,假如希望成果更有构思能够测验 0.9,或许希望有固定成果能够测验 0.0
  • top_p → 一个可用于代替 temperature 的参数,对应机器学习中 nucleus sampling,假如设置 0.1 意味着只考虑构成前 10% 概率质量的 tokens
  • frequency_penalty → -2.0 ~ 2.0 之间的数字,正值会依据新 tokens 在文本中的现有频率对其进行赏罚,然后降低模型逐字重复同一行的可能性
  • presence_penalty → -2.0 ~ 2.0 之间的数字,正值会依据到目前为止是否呈现在文本中来赏罚新 – tokens,然后添加模型谈论新主题的可能性
  • stop → 最大长度为 4 的字符串列表,一旦生成的 tokens 包括其中的内容,将中止生成并回来成果

③ 题库

问答类游戏,根本都是有题库的,玩了几局发现 重复率还挺高,阐明规划不大 (估量30条左右)。然后,这形式随时能够玩,非实时 (所有玩家同时参与),试了下断网还能下一题,猜想是提前把题库下到本地,然后随机抽取生成问题。

综上,很大约率便是本地核算最终提交成绩,假如能 拿到提交成绩的接口,还对个屁春联,直接越过答题环节。

只惋惜,杰哥春节没带 “开发鸡” 回家,抓不了包,同理,没办法抓到题库。

无法直接获取,就只能自己 手动收集 了,自己玩,配合 查找引擎,把做过的题目记下来。

Van♂Python | 对春联?我无敌,你随意~

在记的时分,杰哥又想到了一个 “骚操作”,其实只需求重视 上联的榜首个字 + 备选词 就能够猜到下联了。直接写出代码:

Van♂Python | 对春联?我无敌,你随意~

比方辨认到”爆”字,直接输出下联:

接着便是把 下联和备选词 也抠出来了,核算呈现的比重(次数),最高的便是正确的下联。相同写出代码:

Van♂Python | 对春联?我无敌,你随意~

试验下这三个样本:

Van♂Python | 对春联?我无敌,你随意~

运转输出成果如下:

Van♂Python | 对春联?我无敌,你随意~

牛批,此处应有掌声!!!

Van♂Python | 对春联?我无敌,你随意~

当然,优化空间还有很多,比方即将辨认的文字都拼接到一张图再辨认,减少辨认次数也会快上不少~


0x3、主动答题

滑动的话,adb模仿滑动即可,直接给出东西代码:

def swipe(start_x, start_y, end_x, end_y):
    """
    滑动,从开始坐标点滑动到结尾坐标
    :param start_x: 开始坐标点x坐标
    :param start_y: 开始坐标点y坐标
    :param end_x: 结尾坐标点x坐标
    :param end_y: 结尾坐标点y坐标
    :return:
    """
    return start_cmd('adb shell input swipe %d %d %d %d' % (start_x, start_y, end_x, end_y))

开始坐标,OCR那里能拿到,剩下的难点便是拿到 放置框的坐标,这个也不难,最简略的办法便是:

手动抠坐标点写,死几个组合,依据上联确定是几个字的组合(五六七),然后判断备选词对应第几个字,直接拿到坐标。

当然也能够搞得复杂点,动态核算,先找个适宜的阈值二值化图片 (如130):

Van♂Python | 对春联?我无敌,你随意~

然后便是 水平缓竖直方向遍历坐标点,找到闭合的正方形,直接写出遍历代码 (顺带画出来更直观):

Van♂Python | 对春联?我无敌,你随意~

运转看下作用:

Van♂Python | 对春联?我无敌,你随意~

根本能看到矩形的雏形了,不过得干掉其它的干扰像素点,正方形的四个角 一定是水平缓竖直方向相交的点

Van♂Python | 对春联?我无敌,你随意~

处理后:

Van♂Python | 对春联?我无敌,你随意~

左面坐标点和有点坐标点肯定是对称的,处理下:

Van♂Python | 对春联?我无敌,你随意~

处理后:

Van♂Python | 对春联?我无敌,你随意~

能够,但还有瑕疵,把图片扩大:

Van♂Python | 对春联?我无敌,你随意~

还得再处理下,去掉粘连的点,由于咱们 只需求一个

Van♂Python | 对春联?我无敌,你随意~

运转后能够看到要填 四个字的八个坐标点了,

Van♂Python | 对春联?我无敌,你随意~

同时也能够看到制作出来的四个正方形:

Van♂Python | 对春联?我无敌,你随意~

相同试下其它几个样本:

Van♂Python | 对春联?我无敌,你随意~

牛逼,完美辨认。拿到放置框的坐标,接着算出中心点,调用上面adb滑动的东西办法传参即可~

Van♂Python | 对春联?我无敌,你随意~

当然,动态核算这部分 并不优雅 乃至能够说有些 粗犷 了,用了很多集合和无脑遍历,但时刻仓促,能用就行。

本来想录个主动对春联的视频 显摆显摆,惋惜活动下架了,那只能靠各位读者自行脑补啦~

Van♂Python | 对春联?我无敌,你随意~

行吧,本节就到这,假如对你学习Android主动化有所协助,欢迎三连,感谢~

参考文献

  • 用Python调用OpenAI API做有趣的事