[Python] Créer automatiquement un tableau de comparaison de listes de deck pour la finale JCG

introduction

** * Cet article est une suite de l'article précédent "Agréger automatiquement la distribution de deck JCG avec Python". ** ** Veuillez également vous référer à la partie qui réutilise la méthode d'analyse et le code utilisés dans l'article précédent.

En outre, cet article suppose les connaissances suivantes.

・ Grammaire de base de Python ・ Grattage Web ・ Création d'une table avec des pandas ・ Visualisation des données par matplotlib

Puisque la première moitié se concentre sur les grandes lignes de l'analyse, je pense que vous pouvez obtenir une certaine image sans connaissance de Python. La seconde moitié se concentrera sur le codage réel en Python.

Cet article contient du code de programmation, donc ** nous vous recommandons de l'afficher dans un navigateur PC **.

Objectif

Nous regrouperons les decks qui ont atteint le tournoi final JCG et effectuerons une ** analyse comparative du nombre de cartes utilisées.

Dans Article précédent, nous avons analysé la distribution de deck de JCG, mais dans cet article, nous analyserons la liste de deck en détail, donc le tableau ci-dessous Est automatiquement créé.

** Exemple: JCG Shadowverse vendredi 28 août, tournoi final du tournoi de rotation **

Contenu précédent: Analyse de la distribution des archétypes class_bar_2389.png

** Contenu de cette fois **: Analyse comparative des fiches de recrutement Exemple: Spell W スペルW_2389.png

approche

Suivez les étapes ci-dessous pour procéder à l'analyse.

  1. Obtenez le fichier JCG JSON
  2. Jugement Architype
  3. Obtenez la liste de deck sur le portail Shadowverse (ci-après dénommé le portail)
  4. Graphique des données agrégées

Il existe de nombreux chevauchements avec le contenu précédent concernant les étapes 1 et 2, veuillez donc vous référer à ici pour une explication plus détaillée.

Obtenir le fichier JSON

Comme dans l'article précédent (https://qiita.com/somey/items/7e76a1cf6456619345e0), ** Récupérez le fichier JSON sur le site JCG **. Un exemple du fichier JSON acquis est présenté ci-dessous.

example.json


{
    "result": "success",
    "participants": [
        {
            "id": "42155", 
            "chk": 1, #Statut d'enregistrement
            "nm":  "somey", #Nom enregistré
            "dk": [ #Informations sur le pont
                {
                    "cl": 3, #Classe 1
                    "hs": "3.3.6so2A.6so2A.6so2A.5-gkQ.5-gkQ.5-gkQ.6_X7Q.6_X7Q.6_X7Q.6_djc.6_djc.6_djc.5-gka.5-gka.5-gka.6turQ.6turQ.6turQ.6xnsw.6xnsw.6xnsw.6_ZZg.6_ZZg.6_ZZg.gPWp2.gPWp2.gPWp2.6q8sC.6q8sC.6q8sC.6twYy.6twYy.6twYy.6xpaI.5-glM.5-glM.5-glM.6t_RI.6t_RI.6t_RI"
                }, #Liste des cartes Deck 1 (pour être exact, une partie de l'URL du portail)
                {
                    "cl": 8, #Classe 2
                    "hs": "3.8.71TeA.71TeA.71TeA.6zemS.6zemS.6zemS.71QTC.71QTC.71QTC.6zd2w.6zd2w.6zd2w.6s2wi.6zcK2.6zcK2.6zcK2.6s65g.6zcKC.6zcKC.6zcKC.6s5My.6s5My.6s5My.6zhCY.6zhxQ.6zhxQ.6zhxQ.6-UTo.6-UTo.71Xo6.71Xo6.71Xo6.6oEnY.6oEnY.6oEnY.6oHDo.6oHDo.6vvW6.6vvW6.6vvW6"
                } #Liste des cartes Deck 2 (pour être exact, une partie de l'URL du portail)
            ],
            "en": 1527921725,
            "te": 1, #Information gagnante
            "pr": 1,
            "cu": 0
        },

Parmi eux, une liste de 40 caractères alphanumériques ci-dessous "hs": `(exemple:` "3.3.6so2A. ‥ Omis ‥ .6t_RI" `` `) est une liste de cartes et un portail Représente une partie de l'URL de.

Utilisez ces informations pour ** la détermination de l'archétype ** et ** obtenir des informations de deck à partir du portail **.

Jugement Architype

L'archétype est déterminé à l'aide de la liste de 40 cartes obtenue à partir du fichier JSON. La logique utilisée pour le jugement est la même que Article précédent, et le jugement est rendu par ** si la carte-clé est incluse **.

** Exemple: comprend 3 magasins spécialisés d'outils magiques → Magasin spécialisé sorcière **

Obtenez l'URL du portail

Effectuez ** Web scraping ** pour collecter des informations sur le nom et le numéro de la carte à partir du portail L'URL du portail a la structure suivante.

** (Exemple: Spellwitch) ** https://shadowverse-portal.com/deckbuilder/create/3?hash=3.3.6so2A.6so2A.6so2A.5-gkQ.5-gkQ.5-gkQ.6_X7Q.6_X7Q.6_X7Q.6_djc.6_djc.6_djc.5-gka.5-gka.5-gka.6turQ.6turQ.6turQ.6xnsw.6xnsw.6xnsw.6_ZZg.6_ZZg.6_ZZg.gPWp2.gPWp2.gPWp2.6q8sC.6q8sC.6q8sC.6twYy.6twYy.6twYy.6xpaI.5-glM.5-glM.5-glM.6t_RI.6t_RI.6t_RI?lang=ja

Si vous le comparez à la valeur stockée dans hs '' du fichier JSON, vous pouvez voir qu'il représente le suivant de l'URL du portail hash represents`. Utilisez ceci pour générer l'URL du portail.

Obtenez des informations sur le deck depuis le portail

Demandez le fichier HTML du portail à partir de l'URL générée et effectuez une analyse structurelle du HTML avec Beautiful Soup. ** Beautiful Soup est une bibliothèque qui extrait des informations à partir de fichiers HTML **.

Concernant le scraping Web du portail, je me suis référé à cet article.

Obtenez les données du deck Shadowverse à l'aide de Beautiful Soup et de l'API Twitter en Python

Examinons de plus près le fichier HTML du portail. [Ici](https://shadowverse-portal.com/deck/3.3.6so2A.6so2A.6so2A.5-gkQ.5-gkQ.5-gkQ.6_X7Q.6_X7Q.6_X7Q.6-Ntw.6_djc.6_djc. 6_djc.6turQ.6turQ.6turQ.6xnsw.6xnsw.6xnsw.6_ZZg.6_ZZg.6_ZZg.6q8sC.6q8sC.6q8sC.6twYy.6twYy.6twYy.6t_RI.6t_RI.6t_RI.5- Le jeu de cartes gPWp2.gPWp2.gPWp2.5-glM.5-glM.5-glM? Lang = ja) sera expliqué à titre d'exemple. Tout d'abord, affichez le code source HTML avec la fonction du navigateur (dans le cas de Chorme, clic droit → afficher la source de la page)

En parcourant les pages, vous trouverez des informations sur le nom de la carte et le nombre de cartes.

example.html


<p class="el-card-list-info-name">
<span class="el-card-list-info-name-text">Lumière de sagesse</span>
</p>
<p class="el-card-list-info-count">×3</p>
<p class="el-card-list-link">
<a
class="el-icon-search is-small tooltipify"
href="/card/100314010"
target="_blank"
data-card-tribe-name="-"
data-card-atk="0"
data-card-evo-atk="0"
data-card-life="0"
data-card-evo-life="0"
data-card-name="Lumière de sagesse"
data-card-skill-disc="Dessiner une carte."

De même, en regardant d'autres cartes, le nom de la carte est el-card-list-info-name-text et le numéro est ```el-card-list-info-count`` Vous pouvez voir que l'attribut class est donné.

En utilisant la fonction de sélection de Beautiful soup, vous pouvez ** extraire les éléments des attributs de classe et des balises spécifiés à la fois **.

Représentation graphique de données agrégées

Les dernières données agrégées sont tabulées avec Pandas et représentées graphiquement avec matplotlib.

codage

Importer la bibliothèque

Importez d'abord les bibliothèques requises.

import.py


import requests
import bs4
import json
import pandas as pd
import sys

Fonction de détermination d'Architype

Définit une fonction qui détermine l'architype. Passez les ** informations de classe ** (`` sv_class```) et la ** liste de 40 cartes ** ( `sv_deck```) comme arguments, et triez les archétypes selon la logique de jugement définie. Je vais. En tant que valeur de retour, le nom architype du résultat du jugement est renvoyé.

archetype.py


#Liste des architypes
arche_dict = {"E":["Reno Seus E", "Amatsu E", "Autre E"],"R": ["Évolution R", "Coopération R", "Autre R"],"W": ["Épeler W", "Magasin spécialisé W", "Arcane W", "Autre W"],"D": ["Jeter D", "Baleine D", "Autre D"],"Nc": ["Meifu Nc", "Funérailles Nc",  "Autre Nc"],"V": ["Contrôle V", "Frénésie V", "Autre V"],"B": ["Eira B", "Contrôle B", "Autre B"],"Nm": ["AFNm", "Autre Nm"]}

#Analyse de classe, de type de pont
def deck_arche_analysis(sv_deck, sv_class):

    if sv_class == 1: #Elfe
        if sv_deck.count("6lZu2") == 3:
            return arche_dict["E"][0]
        elif sv_deck.count("6pQTI") == 3:
            return arche_dict["E"][1]
        else:
            return arche_dict["E"][2]
    elif sv_class == 2: #Royal
        if sv_deck.count("6td16") > 1:
            return arche_dict["R"][0]
        elif sv_deck.count("6_B9A") == 3:
            return arche_dict["R"][1]
        else:
            return arche_dict["R"][2]
    elif sv_class == 3: #Sorcière
        if sv_deck.count("6_djc") == 3:
            return arche_dict["W"][0]
        elif sv_deck.count("6q95g") == 3:
            return arche_dict["W"][1]
        elif sv_deck.count("6t_Rc") == 3:
            return arche_dict["W"][2]
        else:
            return arche_dict["W"][3]
    elif sv_class == 4: #Dragon
        if sv_deck.count("6yB-y") == 3:
            return arche_dict["D"][0]
        elif sv_deck.count("6_zhY") == 3:
            return arche_dict["D"][1]
        else:
            return arche_dict["D"][2]
    elif sv_class == 5: #Nécromancien
        if sv_deck.count("6n7-I") > 1:
            return arche_dict["Nc"][0]
        elif sv_deck.count("70OYI") == 3:
            return arche_dict["Nc"][1]
        else:
            return arche_dict["Nc"][2]
    elif sv_class == 6: #Vampire
        if sv_deck.count("6rGOA") == 3:
            return arche_dict["V"][0]
        elif sv_deck.count("6v1MC") ==3:
            return arche_dict["V"][1]
        else:
            return arche_dict["V"][2]
    elif sv_class == 7: #Évêque
        if sv_deck.count("6nupS") == 3:
            return arche_dict["B"][0]
        elif sv_deck.count("6nsN2") == 3:
            return arche_dict["B"][1]
        else:
            return arche_dict["B"][2]
    elif sv_class == 8: #Némésis
        if sv_deck.count("6zcK2") == 3:
            return arche_dict["Nm"][0]
        else:
            return arche_dict["Nm"][1]

Obtenez le nom et le numéro de la carte sur le portail

À partir de l'URL du portail, créez une fonction qui génère la combinaison du nom et du nombre de cartes utilisées. En tant que valeur de retour, toutes les paires de nom de carte et de nombre de cartes sont renvoyées sous forme de variables de type dictionnaire.

get_card-list.py


#Obtenez le deck sur le portail
def get_deck(url):
    #Demander un fichier html
    response = requests.get(url)
    #codage
    response.encoding = response.apparent_encoding
    #analyse html
    soup = bs4.BeautifulSoup(response.text, "html.parser")
    #Obtenez une liste de noms de cartes
    names = soup.select(r".el-card-list-info-name-text")
    #Obtenez une liste de feuilles
    counts = soup.select(r".el-card-list-info-count")
    #{nom de la carte:Nombre de feuilles}Créer un dictionnaire de
    deck = {name.text: int(count.text[1:]) for name, count in zip(names, counts)}
    return deck

Je me suis référé à cet article pour la fonction permettant d'obtenir la liste de deck à partir du portail.

Obtenez les données du deck Shadowverse à l'aide de Beautiful Soup et de l'API Twitter en Python

Obtenir le fichier JSON

Spécifiez le tournoi JCG que vous souhaitez vérifier et obtenez le fichier JSON. Définissez également arche_search comme nom d'archétype que vous souhaitez rechercher. Ceci est comparé au résultat de la fonction de jugement de l'archétype et utilisé pour vérifier s'il s'agit de l'architype souhaité.

json.py


#Entrez le numéro du tournoi JCG
compe_num = input("Veuillez saisir le numéro du tournoi JCG que vous souhaitez rechercher")
#Entrez l'archétype que vous souhaitez rechercher
arche_search = input("Entrez l'archétype que vous souhaitez rechercher")
#URL du fichier JSON du tournoi
jcg_url = "https://sv.j-cg.com/compe/view/entrylist/" +  str(compe_num) + "/json"
#Demander un fichier json
res_jcg = requests.get(jcg_url)
#Enregistrer au format texte json
j_txt = json.loads(res_jcg.text)

#Si ce n'est pas le tournoi final, terminez le programme
if not len(j_txt["participants"]) == 32:
    sys.exit()

Dans la dernière partie, il est jugé si le numéro de tournoi saisi est le tournoi final. S'il s'agit d'un groupe de qualification, le programme sera interrompu.

Collection du nom de la carte et du nombre de feuilles

analysis.py


#Variable de type dictionnaire qui stocke le nom d'utilisateur, le nom de la carte et le nombre de feuilles
arche_summary = {}

#La partie d'en-tête du portail
dbsp_header = "https://shadowverse-portal.com/deck/"

#Obtenez le nombre de cours
for i in range(len(j_txt["participants"])):
    #Confirmation des informations gagnantes
    if j_txt["participants"][i]["te"] == 0: #Perdu
        continue
    elif j_txt["participants"][i]["te"] == 1: #Gagnant
        for j in range(2):
            #Obtenir des informations sur la classe
            class_ij = j_txt["participants"][i]["dk"][j]["cl"]
            #Acquisition des informations de la carte
            deck_ij = j_txt["participants"][i]["dk"][j]["hs"]
            #Déterminer l'archétype à partir des informations de la carte de classe
            archetype = deck_arche_analysis(deck_ij, class_ij)

            #Lorsque le résultat du jugement correspond à l'architype que vous souhaitez vérifier
            if archetype == arche_search:
                #Générer l'URL du portail
                dbsp_url = dbsp_header+deck_ij
                #Obtenez la combinaison du nom de la carte et du nombre de cartes à partir du portail
                deck_dict = get_deck(dbsp_url)
                #arche_Rédiger des informations en résumé
                arche_summary[j_txt["participants"][i]["nm"]] = deck_dict
            else:
                continue
    else:
        continue

Graphisme

Enfin, convertissez le résultat agrégé au format Pandas DataFrame et tracez-le avec matplotlib.

** * Si vous souhaitez exécuter le code suivant tel quel, vous devez définir la police japonaise dans matplotlib. ** ** Si vous souhaitez l'exécuter tel quel, téléchargez la police se référant à l'article suivant et placez-la dans le même répertoire que ce fichier python.

Dessinez un graphique de matplotlib sur Heroku

graphs.py


#Importer matplotlib
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
#Les deux lignes suivantes concernent les paramètres japonais, vous devez télécharger la police à l'avance
from matplotlib.font_manager import FontProperties
fontprop = FontProperties(fname="ipaexg.ttf")

#Convertir les résultats agrégés au format DataFrame
df_arche_summary = pd.DataFrame(arche_summary)
df_arche_summary = df_arche_summary.fillna(0).astype("int")

#Paramètres de table avancés
fig, ax = plt.subplots()
ax.axis("off")
ax.axis("tight")
tb = ax.table(cellText=df_arche_summary.values,colLabels=df_arche_summary.columns,rowLabels=df_arche_summary.index,colWidths=[0.15]*len(df_arche_summary.columns),loc='center',bbox=[0,0,1,1], cellLoc="center", rowLoc="right")
tb.auto_set_font_size(False)
tb.set_fontsize(8)
for i in range(len(df_arche_summary.columns)):
    tb[0,i].set_text_props(font_properties=fontprop, weight='bold', color="w")
    tb[0,i].set_facecolor('#2b333b')
for k in range(1,len(df_arche_summary.index)+1):
    tb[k,-1].set_text_props(font_properties=fontprop,weight='bold', color="w")
    tb[k,-1].set_facecolor('#2b333b')
plt.savefig(arche_search + "_" + compe_num + ".png ",bbox_inches="tight")

Résultat d'exécution

** Ligne de commande **

python


$ python JCG_decklist.py
Entrez le numéro du tournoi JCG que vous souhaitez rechercher: 2389
Entrez l'archétype que vous souhaitez rechercher: Spell W

** Résultat d'exécution ** スペルW_2389.png

en conclusion

Dans cet article, j'ai présenté comment obtenir la liste des cartes du tournoi final JCG par web scraping. Le code de l'article précédent et le code de cette époque ont beaucoup en commun, vous pouvez donc combiner les deux fonctions en un seul programme.

En passant, la partie du codage qui prend le plus de temps est la mise en page du tableau. Le nombre de colonnes et de lignes a changé à chaque fois, et j'ai eu beaucoup de problèmes avec les paramètres de réglage.

Si vous avez des corrections ou des erreurs concernant le code ou la méthode d'analyse, veuillez nous en informer dans les commentaires.

Recommended Posts

[Python] Créer automatiquement un tableau de comparaison de listes de deck pour la finale JCG
Créez un Twitter BOT avec le SDK GoogleAppEngine pour Python
Distribution totale automatique du deck JCG avec Python
Python: préparez un sérialiseur pour l'instance de classe:
Script Python pour obtenir une liste d'exemples d'entrée pour le concours AtCoder
amateur python tente de résumer la liste ②
Créer une couche pour AWS Lambda Python dans Docker
[CRUD] [Django] Créer un site CRUD en utilisant le framework Python Django ~ 2 ~
Python: obtenir une liste de méthodes pour un objet
[CRUD] [Django] Créer un site CRUD en utilisant le framework Python Django ~ 3 ~
[CRUD] [Django] Créer un site CRUD en utilisant le framework Python Django ~ 4 ~
[CRUD] [Django] Créer un site CRUD en utilisant le framework Python Django ~ 5 ~
Rechercher la table à l'aide de sqlalchemy et créer un dictionnaire
Programme pour rechercher la même image
[Django] Que faire quand il y a de nombreux champs dans le modèle que vous souhaitez créer
[Ev3dev] Créez un programme qui capture LCD (écran) en utilisant python
J'ai fait un programme qui calcule automatiquement le zodiaque avec tkinter
[Python] Créer automatiquement un tableau de comparaison de listes de deck pour la finale JCG
Créer un environnement Python
J'ai créé un outil pour générer automatiquement un simple diagramme ER à partir de l'instruction CREATE TABLE
Obtenez une liste des métriques CloudWatch et une table de correspondance des unités unitaires avec Python boto
[Python] Comment créer une table à partir d'une liste (opération de base de création de table / changement de nom de matrice)
[Python] Création d'un environnement Python virtuel pour le didacticiel sur la pyramide (résumé)
Comment obtenir la dernière (dernière) valeur d'une liste en Python
Python: créer un dictionnaire à partir d'une liste de clés et de valeurs
Créer un script Python pour Wake on LAN (Wake on LAN over NAT [5])
Créer une nouvelle liste en combinant des éléments en double dans la liste
Créer un environnement virtuel pour python sur mac [Très facile]
Je veux créer un Dockerfile pour le moment.
[Python] Créer un écran pour le code d'état HTTP 403/404/500 avec Django
Extraire la valeur la plus proche d'une valeur à partir d'un élément de liste en Python
La liste Python n'est pas une liste
Créer un tableau numpy python
[Python / PyQ] 4. liste, pour instruction
#List Python pour les super débutants
Créer un répertoire avec python
L'histoire de la création d'un pilote standard pour db avec python.
Utilisez sqlalchemy pour rechercher la table DB et créer un Dataflame pour les pandas
[Introduction à Python] Comment utiliser l'opérateur in dans l'instruction for?
[Ev3dev] Créez un programme qui capture LCD (écran) en utilisant python
[Introduction à Python] Comment obtenir la taille d'une liste avec la taille de la liste
Python vba pour créer une chaîne de date pour créer un nom de fichier
J'ai essayé de créer un outil d'échafaudage pour le framework Web Python Bottle
python Remarque: map -faire la même chose pour chaque élément de la liste
[Mac] Créer un environnement d'exécution Python 3 à partir de l'état entièrement initialisé
[Python] Un programme qui fait pivoter le contenu de la liste vers la gauche
Créer un Ubuntu de démarrage USB avec un environnement Python pour l'analyse des données
Créez un programme de jugement de compatibilité avec le module aléatoire de python.
[Python] Comment créer une liste de types de dictionnaire, ajouter / modifier / supprimer des éléments et extraire avec une instruction for