Abril de 2018. Eu tinha 14 anos. Meus amigos e eu jogamos no popular questionário online “Clover” do VKontakte. Um de nós (geralmente eu) estava sempre atrás de um laptop para tentar rapidamente pesquisar no Google perguntas e procurar nos resultados da pesquisa a resposta correta. Mas de repente percebi que estava fazendo a mesma coisa todas as vezes e decidi tentar escrevê-lo em Python 3, parcialmente conhecido por mim na época.
Etapa 0. O que está acontecendo aqui?
Para começar, atualizarei em sua memória a mecânica de "Clover".
O jogo para todos começa ao mesmo tempo - às 13:00 e às 20:00, horário de Moscou. Para jogar, você precisa entrar no aplicativo no momento e se conectar à transmissão ao vivo. O jogo dura 15 minutos, durante o qual as perguntas são enviadas aos participantes no telefone
ao mesmo tempo . A resposta é
10 segundos. Então a resposta correta é anunciada. Todos os que adivinharam vão além. Existem 12 perguntas no total e, se você responder a todas, receberá um prêmio em dinheiro.

Acontece que nossa tarefa é capturar instantaneamente novas perguntas do servidor Clover, processá-las por meio de um mecanismo de pesquisa e determinar a resposta correta com base nos resultados da pesquisa. Foi decidido enviar a resposta em um bot de telegrama, para que as notificações aparecessem no telefone durante o jogo. E tudo isso é desejável em alguns segundos, porque o tempo de resposta é muito limitado. Se você quiser ver como um código bastante simples, mas funcional (e olhar para este será útil para iniciantes) nos ajudou a vencer o Clover - bem-vindo ao corte.
Etapa 1. Obtenha perguntas do servidor
A princípio, parecia o estágio mais difícil. Eu já respirei fundo e estava pronta para entrar no mundo selvagem, como visão computacional, interceptando tráfego ou descompilando o aplicativo ... Quando de repente uma surpresa me esperava - Clover tem uma API aberta! Não está documentado em nenhum lugar, mas se durante o jogo, assim que todos os jogadores tiverem feito uma pergunta, fizer uma solicitação no api.vk.com, em resposta, obteremos a pergunta e as opções de resposta em JSON:

https://api.vk.com/method/execute.getLastQuestion?v=5.5&access_token=VK_USER_TOKEN
Como access_token, é necessário transferir o token da API de qualquer usuário do VKontakte, mas é importante que ele tenha sido originalmente emitido especificamente para o Clover. O app_id dele é 6334949.
Etapa 2. Processamos o problema por meio de um mecanismo de pesquisa
Havia duas opções: usar a API oficial do mecanismo de pesquisa ou adicionar argumentos de pesquisa diretamente à barra de endereços e analisar os resultados. No começo, eu tentei o segundo, mas não só às vezes peguei captcha, como também perdi muito tempo, porque as páginas eram carregadas em média em 2 segundos. E lembro que é aconselhável que cumpramos esses dois segundos. Bem, e o mais importante, não recebi textos grandes e estruturados dos mecanismos de pesquisa sobre o tópico necessário, pois apenas pequenas partes do material necessário, chamado
snippets, ficam na página de pesquisa:

Então comecei a procurar uma API. O Google não se encaixou - suas soluções eram muito limitadas e retornavam muito poucos dados.
O Yandex.XML acabou sendo o mais generoso - permite enviar 10.000 solicitações por dia, não mais que 5 por segundo, e retorna dados muito rapidamente. A solicitação é opcionalmente o número de páginas (até 100) e o número de passagens - valores especiais que são usados para formar trechos. Nós obtemos os dados em XML. No entanto, esses são todos os mesmos trechos.
Para que você possa se familiarizar e brincar com o que o Yandex retorna, aqui está um exemplo de resposta à pergunta "Qual é o nome do principal antagonista da série de vídeos" The Legend of Zelda? ":
Yandex. Dirija .
Tive sorte e, no pypi, já existe um módulo de
pesquisa yandex para isso. Então, tentei obter a pergunta do servidor, encontrá-la no Yandex, criar um grande texto com trechos e dividi-lo em frases:
import requests as req import yandex_search import json apiurl = "https://api.vk.com/method/execute.getLastQuestion?access_token=VK_USER_TOKEN&v=5.5" clever_response = (json.loads(req.get(apiurl).content))["response"]
Etapa 3. Procurando respostas
Inicialmente, a tarefa de reconhecer com precisão a resposta de acordo com os trechos parecia irreal para mim (lembro que, na hora de escrever o código, eu era um iniciante absoluto). Portanto, decidi primeiro simplificar a tarefa que realizamos com uma pesquisa manual.
O que meus amigos e eu fizemos ao direcionar nossa pergunta para um mecanismo de pesquisa? Eles começaram a procurar rapidamente nos olhos por respostas nos resultados. Qual é o problema com essa abordagem? Em
várias letras, há um grande número de propostas desnecessárias, que não contêm informações sobre respostas. Pesquisando com meus olhos às vezes levava muito tempo. Portanto, a primeira coisa que decidi fazer foi selecionar todas as frases com uma menção de qualquer uma das respostas e exibi-las na tela para que procurássemos a resposta em um texto muito pequeno que contenha com precisão as informações de que precisamos.
hint = []
Parece que receba as ofertas certas, leia-as e responda corretamente. Mas e se não encontrarmos uma única frase? Nesse caso, decidi aparar as palavras para não perdê-las, se estiverem em outro caso. E também para capturar aqueles que são formados a partir da fonte. Em resumo, acabei de aparar o final deles em dois caracteres:
if len(hint) == 0: def cut(string): if len(string) > 2: return string[0:-2] else: return string short_ans1, short_ans2, short_ans3 = cut(ans1), cut(ans2), cut(ans3) for pred in itemslist:
Mas mesmo depois dessa rede de segurança, ainda havia casos em que a dica permanecia vazia, simplesmente porque os resultados nem sempre tocavam nas respostas. Diga, para a pergunta
"Qual desses escritores tem uma história, nomeada como a música do grupo Bi 2?" nenhuma resposta exata pode ser encontrada. Nesse caso, recorri à abordagem oposta - perguntei sobre as respostas e deduzi a opção com base na frequência com que as palavras da pergunta são mencionadas nos resultados.
if len(hint) == 0: questionlist = question.split(" ") blacklist = ["", "", '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', ''] for w in questionlist: if w in blacklist: questionlist.remove(w) yandex_ans1 = yandexfind(ans1) yandex_ans2 = yandexfind(ans2) yandex_ans3 = yandexfind(ans3)
Nesse ponto, o script ganhou funcionalidade básica. E agora, apenas uma semana e meia após o lançamento de Clover, estamos sentados e já brincando com uma “fraude” feita por nós mesmos. Você deveria ter visto nossos rostos com um amigo quando
vencemos o jogo , lendo sugestões na linha de comando como se por mágica!
Etapa 4. Exibir respostas claras
Mas logo esse formato está cansado. Primeiro, você tinha que sentar com um laptop em todos os jogos. Em segundo lugar, meus amigos pediram o script e estou cansado de explicar a todos como inserir seu token VKontakte, como configurar o Yandex.XML (está vinculado ao IP, ou seja, era necessário criar uma conta para cada usuário do script) e como instalar o python no computador.
Seria muito melhor se as respostas aparecessem em notificações push no telefone durante o jogo! Basta olhar para o topo da tela e responder como está escrito na notificação por push! E você pode organizar isso para todos se criar seu canal de telegrama para o script! Maravilhoso!
Mas simplesmente exibir as mesmas frases em telegramas não é uma opção. Lê-los a partir do seu telefone é extremamente inconveniente. Portanto, eu mesmo tive que aprender o roteiro para entender qual resposta está correta.
Importamos
telebot e
alteramos todas
as funções
print () para
send_tg () e
notsure () , que usaremos no último método, pois ele perde um pouco mais do que outros:
def send_tg(ans): bot.send_message("@autoclever", str(ans).capitalize()) print(str(ans)) return def notsure(ans): send_tg(ans.capitalize() + ". !") hint.append("WE TRIED!")
E naquele momento, percebi que trechos são muito melhores que textos longos! Como o mecanismo de pesquisa está se esforçando muito para
responder ao nosso pedido, e não apenas para encontrar correspondências em palavras. E ele consegue - os trechos frequentemente continham as respostas corretas do que as erradas, ou seja, não havia necessidade de analisar o texto. E eu, de fato, não sabia como.
Portanto, somos simples de contar a menção de palavras nos resultados:
anscounts = { ans1: 0, ans2: 0, ans3: 0 } for s in hint: for a in [ans1, ans2, ans3]: anscounts[a] += s.count(a) right = (max(anscounts, key=anscounts.get)) send_tg(right)
O que aconteceu como resultado:

Destino adicional
Para ser justo, devo dizer que não tive sucesso na máquina da morte. Em média, o bot respondeu corretamente apenas 9 a 10 das 12 perguntas. É compreensível, porque houve pessoas complicadas que não sucumbiram à análise da pesquisa Yandex. Eu e meus amigos estávamos cansados de voar constantemente sobre algumas perguntas e esperar por um jogo bem-sucedido, no qual o bot finalmente responderia tudo corretamente. Um milagre não aconteceu, eu realmente não queria mais modificar o script e, depois de deixar de ter esperanças de uma vitória fácil, abandonamos o jogo.
Com o tempo, minha ideia começou a surgir na cabeça de outros jovens desenvolvedores. No final de 2018, havia pelo menos 10 bots e sites exibindo suas suposições sobre problemas no Clover. A tarefa não é tão difícil. Mas o que é surpreendente, nenhum deles já ultrapassou a faixa de 9 a 10 perguntas por jogo e depois caiu para 7-8, como meu bot. Aparentemente, os compiladores das perguntas deixaram claro como compor as perguntas para que o trabalho dos mecanismos de pesquisa fosse irrelevante.
Infelizmente, o bot não pode mais ser finalizado, porque em 31 de dezembro Clover passou a última transmissão e eu não tinha mais perguntas. No entanto, foi uma ótima experiência para um programador iniciante. E certamente haveria um grande desafio para o avançado - imagine a dupla word2vec e text2vec, solicitações assíncronas para Yandex, Google e Wikipedia ao mesmo tempo, um classificador avançado de perguntas e um algoritmo para reformular a pergunta em caso de falha ... Eh! Talvez por essas oportunidades eu amei esse jogo mais do que pela jogabilidade em si.