Doporuceni

Snippets vs. Clover – Porážka nejpopulárnějšího kvízu v reálném čase / Habr

Duben 2018. Bylo mi 14. S kamarády jsme hráli tehdy velmi populární online kvízovou hru „Clover“ z VKontakte. Jeden z nás (obvykle já) byl pořád u notebooku a snažil se rychle googlovat otázky a očima najít ve výsledcích vyhledávání správnou odpověď. Najednou jsem si ale uvědomil, že dělám pokaždé totéž, a rozhodl jsem se to zkusit napsat v Pythonu 3, který jsem tehdy částečně ovládal.

Krok 0. Co se tady děje

Nejdříve ti osvěžím paměť ohledně mechaniky Cloveru.

Hra začíná pro všechny ve stejnou dobu – ve 13:00 a ve 20:00 moskevského času. Chcete-li hrát, musíte v tuto dobu přejít do aplikace a připojit se k živému vysílání. Hra trvá 15 minut, během kterých účastníci přijímají telefonní hovor. zároveň otázky přicházejí. Odpověď je dána 10 sekund. Poté je oznámena správná odpověď. Všichni, kteří uhodli správně, postoupí dál. Celkem je 12 otázek a pokud na všechny odpovíte, získáte peněžní odměnu.

Ukazuje se, že naším úkolem je okamžitě zachytit nové otázky ze serveru Clover, zpracovat je pomocí nějakého vyhledávače a na základě výsledků určit správnou odpověď. Bylo rozhodnuto odeslat odpověď telegramovému botovi, aby se z něj během hry na telefonu zobrazovala oznámení. A to vše je žádoucí během několika sekund, protože čas na odpověď je velmi omezený. Pokud chcete vidět, jak nám poměrně jednoduchý, ale funkční kód (a pro začátečníky bude užitečné se na něj podívat) pomohl porazit Clover – vítejte pod řezem.

Krok 1. Přijměte otázky od serveru

Zpočátku se to zdálo jako ta nejtěžší část. Už jsem se zhluboka nadechl a byl jsem připraven ponořit se do divočiny věcí, jako je počítačové vidění, zachycování provozu nebo dekompilace aplikací… Najednou mě ale čekalo překvapení – Clover má otevřené API! Není to nikde zdokumentováno, ale pokud během hry, jakmile je všem hráčům položena otázka, zadáme požadavek na api.vk.com, pak jako odpověď obdržíme položenou otázku a možnosti odpovědi na ni ve formátu JSON:

https://api.vk.com/method/execute.getLastQuestion?v=5.5&access_token=VK_USER_TOKEN

Jako access_token je potřeba předat API token libovolného uživatele VKontakte, ale je důležité, aby byl původně napsán speciálně pro Clover. Jeho app_id je 6334949.

Krok 2. Zpracujte otázku pomocí vyhledávače

Existovaly dvě možnosti: použít oficiální API vyhledávače nebo přidat argumenty vyhledávání přímo do adresního řádku a výsledky analyzovat. Nejdříve jsem zkusil druhou možnost, ale nejenže jsem občas chytil captchu, ale také jsem ztratil spoustu času, protože stránky se načítaly v průměru za 2 sekundy. A připomenu vám, že je žádoucí, abychom se do těchto dvou sekund vešli. No a hlavně jsem od vyhledávačů nedostával rozsáhlé a strukturované texty na požadované téma, protože na stránce s vyhledáváním visí pouze malé kousky požadovaného materiálu, které se nazývají úryvky:

Přečtěte si více
Pasení stáda

Tak jsem začal hledat API. Google nefungoval – jejich řešení byla velmi omezená a vracela velmi málo dat. Yandex.XML se ukázal jako nejštědřejší – umožňuje odesílat 10000 5 požadavků denně, ne více než 100 za sekundu, a vrací data velmi rychle. Požadavek na něj volitelně obsahuje počet stránek (až XNUMX) a počet pasáží – speciální hodnoty, které se používají k vytváření úryvků. Data dostáváme v XML. Jsou to však stále ty samé úryvky.

Abyste se mohli seznámit a pohrát si s tím, co Yandex vrací, zde je příklad odpovědi na dotaz „Jak se jmenuje hlavní protivník v sérii videoher „The Legend of Zelda“?“: Yandex.Disk.

Měl jsem štěstí a ukázalo se, že pypi už pro to má samostatný modul s názvem yandex-search. Zkusil jsem tedy získat otázku ze serveru, najít ji v Yandexu, z úryvků vytvořit jeden velký text a rozdělit ho do vět:

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"] # , , ], 'stop_time': 0, 'is_first': 0, 'is_last': 1, 'number': 12, 'id': 22, 'sent_time': 1533921436> question = str(clever_response["text"]) ans1, ans2, ans3 = str(clever_response["answers"][0]["text"]).lower(), str(clever_response["answers"][1]["text"]).lower(), str(clever_response["answers"][2]["text"]).lower() def yandexfind(question): finded = yandex.search(question).items snips = "" for i in finded: snips += (i.get("snippet")) + "n" return snips items = yandexfind(question) itemslist = list(items.split(". "))

Krok 3: Hledání odpovědí

Zpočátku se mi úkol přesného rozpoznání odpovědi z úryvků zdál nereálný (vzpomeňte si, že když jsem psal kód, byl jsem naprostý začátečník). Rozhodl jsem se tedy nejprve zjednodušit úkol, který jsme prováděli při ručním vyhledávání.

Co jsme s přáteli udělali, když jsme zadali naši otázku do vyhledávače? Začali jsme rychle hledat odpovědi ve výsledcích. Jaký je s tímto přístupem problém? mnoho písmen přítomnost velkého množství zbytečných vět, které neobsahují informace o odpovědích. Někdy trvalo dlouho hledat očima. Proto jsem se jako první rozhodl zvýraznit všechny věty, které zmiňovaly některou z odpovědí, a zobrazit je na obrazovce, abychom odpověď hledali ve velmi malém textu, který přesně obsahuje potřebné informace.

hint = [] #Список предложений, содержащих один из вариантов ответа for sentence in itemslist: #Чекаем каждое предложение из сниппетов if (ans1 in sentence) or (ans2 in sentence) or (ans3 in sentence): hint.append(sentence) if len(hint) > 4: break 

Zdálo by se, sežeňte potřebné věty, přečtěte si je a správně odpovězte. Ale co dělat, když jsme stále nenašli ani jednu potřebnou větu? V tomto případě jsem se rozhodl slova zkrátit, abych je nepřehlédl, pokud jsou v jiném pádě. A také abych zachytil ta, která jsou utvořena z původních. Zkrátka jsem jejich koncovky jednoduše zkrátil dvěma symboly:

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: #Чекаем каждое предложение из сниппетов if (short_ans1 in pred) or (short_ans2 in pred) or (short_ans3 in pred) hint.append(pred)

Ale i po této záchranné síti se stále vyskytovaly případy, kdy nápověda zůstala prázdná, jednoduše proto, že výsledky se ne vždy jakkoli dotýkaly odpovědí. Například k otázce „Který z těchto autorů má příběh pojmenovaný po písni skupiny Bi 2?“ Neexistuje přesná odpověď. V tomto případě jsem použil opačný přístup – zkontroloval jsem odpovědi a odvodil možnost na základě toho, jak často byla slova v otázce ve výsledcích zmíněna.

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) #Чуть позже я сделал этот процесс асинхронным, но это было костыльно count_ans1, count_ans2, count_ans3 = 0, 0, 0 for w in questionlist: count_ans1 += yandex_ans1.count(w) count_ans2 += yandex_ans2.count(w) count_ans3 += yandex_ans3.count(w) if (count_ans1 + count_ans2 + count_ans3) > 5: if count_ans1 > (count_ans2 + count_ans3): print(ans1) elif count_ans2 > (count_ans1 + count_ans3): print(ans2) elif count_ans3 > (count_ans2 + count_ans1): print(ans3) 

V tomto okamžiku skript získal základní funkcionalitu. A tady jsme, pouhý týden a půl po vydání Cloveru, a už si hrajeme s takovým domácím „cheatem“. Měli jste vidět naše s kamarádem výrazy, když jsme poprvé. vyhrál zápas, čtení návrhů, které se jako mávnutím kouzelného proutku objevují v příkazovém řádku!

Přečtěte si více
Výměna oleje CVT v Petrohradu — čerpací stanice SPOT

Krok 4. Vypište jasné odpovědi

Ale brzy se tento formát stal nudným. Zaprvé, každou hru jste museli sedět u notebooku. Zadruhé, kamarádi se ptali na skript a já už byl unavený z toho, že jsem všem vysvětloval, jak vložit token VKontakte, jak nastavit Yandex.XML (je vázaný na IP adresu, tzn. pro každého uživatele skriptu musel být vytvořen účet) a jak nainstalovat Python do počítače.

Bylo by mnohem lepší, kdyby se odpovědi zobrazovaly v push notifikacích na telefonu přímo během hry! Stačí se podívat na horní část obrazovky a odpovědět tak, jak je napsáno v push notifikaci! A tohle můžete zorganizovat pro všechny, pokud si pro skript vytvoříte vlastní telegram kanál! Skvělé!

Ale pouhé zobrazování stejných vět v Telegramu není možné. Jejich čtení z telefonu je extrémně nepohodlné. Proto jsem musel naučit samotný skript, aby rozpoznal, která odpověď je správná.

Dovážíme telebot a všechny funkce tisk() změnit send_tg() и nejsem si jistý(), kterou použijeme v poslední metodě, protože mine o něco častěji než ostatní:

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!") 

A v tomto okamžiku jsem si uvědomil, že úryvky jsou mnohem lepší než podrobné texty! Protože se vyhledávač velmi snaží dát odpověď na naši žádost, a ne jen hledat shody podle slov. A funguje to – úryvky obsahovaly více správných odpovědí než nesprávných, to znamená, že nebylo nutné text analyzovat. A já jsem vlastně ani nevěděl jak.

Takže jednoduše spočítáme zmínky slov ve výsledcích:

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) #Ура! 

Co se stalo nakonec:

Další osud

Abych byl spravedlivý, musím říct, že se mi nepodařilo vytvořit stroj na smrt. Bot v průměru odpověděl správně pouze na 9-10 otázek z 12. Je to pochopitelné, protože se objevily i záludné otázky, které vyhledávání na Yandexu nedokázalo analyzovat. S přáteli jsme byli unavení z neustálého selhávání u několika otázek a čekání na úspěšnou hru, ve které bot konečně odpoví správně na všechno. Zázraky se neděly, už se mi moc nechtělo na scénáři pracovat a pak, když jsme přestali doufat v snadné vítězství, jsme hru opustili.

Postupem času se můj nápad začal vkrádat do hlav dalších mladých vývojářů. Do konce roku 2018 existovalo v Cloveru nejméně 10 botů a webů, které generovaly své tipy na otázky. Úkol není tak obtížný. Ale překvapivě žádný z nich nikdy nepřekročil laťku 9-10 otázek na hru a později všichni klesli na 7-8, jako můj bot. Zřejmě autoři otázek přišli na to, jak otázky skládat tak, aby práce vyhledávačů byla irelevantní.

Bot bohužel už nelze dále vylepšovat, protože 31. prosince měl Clover své poslední vysílání a já jsem si neuložil dataset otázek. Nicméně pro začínajícího programátora to byl skvělý zážitek. A pro pokročilého by to byla jistě velká výzva – jen si představte duet word2vec a text2vec, asynchronní požadavky na Yandex, Google a Wikipedii zároveň, pokročilý klasifikátor otázek a algoritmus pro přeformulování otázky v případě selhání. Eh! Možná jsem tuhle hru miloval víc pro takové možnosti než pro samotnou hratelnost.

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *

Back to top button