[PYTHON] Afficher le temps d'attente de Disney avec le bot LINE

table des matières

** Bold ** est l'endroit où j'ai eu du mal

Aperçu

J'ai créé un bot avec Python au lieu de node.js en me référant au site suivant. De plus, les informations obtenues par grattage ont été obtenues à partir du même site que celui indiqué ci-dessus.

J'ai créé un bot LINE qui me dit le temps d'attente de Disney

Étant donné que ce site est censé être facile à utiliser, il existe de nombreuses chaînes de caractères, mais au contraire, nous avons utilisé le menu riche et Flex Message afin que l'utilisateur puisse sélectionner les données souhaitées. Les menus riches, les messages Flex, etc. ne sont pas organisés, j'ai donc regardé la référence et j'ai fait des allers-retours entre différents sites, j'espère donc les résumer également.

Création du bot LINE

Je vais d'abord coller la version terminée. Veuillez vous inscrire et l'utiliser si vous le souhaitez! Pour lire directement, cliquez ici

Le code source est disponible sur GitHub. Si vous souhaitez voir plus de détails tels que le code de scraping, veuillez cliquer ici (https://github.com/ryodisney/disney_wait)

Structure du répertoire

Diagramme

J'ai tout mis dans un dossier appelé disney. Puisque .git était un fichier caché, il n'apparaît pas ici, mais il se trouve dans la même hiérarchie que deploy.bat.

disney
├  deploy.bat
├  main.py
├  scrape_requests.py
├  makejsonfile.py
├  Procfile
├  runtime.txt
├  requirements.txt
│  
└─templates
        land_theme.json
        recipt.json
        sea_theme.json
        theme_select.json

Présentation de chaque fichier

La partie qui déplace le bot LINE sera expliquée plus tard, de sorte que le contenu du fichier de configuration est répertorié ci-dessous.

** deploy.bat **: Cela vous évite d'avoir à taper toutes les commandes lors du report d'une version modifiée à Heroku.

deploy.bat


git add . && git commit -m 'Improve' && git push

** Procfile **: Crée un Procfile, un fichier de configuration qui enseigne à Heroku comment démarrer le programme. Après vous être déplacé vers le répertoire actuel à l'invite de commande, entrez la commande ci-dessous. À ce stade, placez celui qui commence en premier à l'endroit où main.py est écrit. Le nom ne doit pas nécessairement être main.py.

Procfile


echo web: python main.py > Procfile

** runtime.txt **: la version de Python à utiliser est répertoriée ici.

runtime.txt


python-3.7.0

** requirements.txt **: L'installation pip des modules utilisés en Python est écrite ici. Maintenant, vous pouvez également utiliser ces modules côté Heroku.

requirements.txt


Flask==1.1.1
line-bot-sdk==1.15.0
requests==2.21.0
bs4==0.0.1
lxml==4.4.2
https://github.com/heroku/heroku-buildpack-chromedriver.git
https://github.com/heroku/heroku-buildpack-google-chrome.git

Flux de fonctionnement

  1. Appuyez sur le bouton d'accueil (menu riche décrit ci-dessous)
  2. Sélection du parc
  3. Contrôle d'ouverture
  4. Si le parc est ouvert, sélectionnez la catégorie de temps d'attente que vous souhaitez obtenir (menu riche décrit plus loin)
  5. Grattage → Sortie avec recette de message Flex

Créer un menu riche

La partie en 6 parties montrée dans l'image ci-dessous est le menu riche. Cette fois, je ne vais pas le construire moi-même, mais utiliser les fonctions de LINE Official Manager. Je voulais vraiment utiliser la publication, donc je voulais le faire complètement moi-même, mais j'ai fait un compromis parce que je ne comprenais pas comment l'implémenter même après avoir lu la référence.

LINE Official Manager Une fois connecté, cliquez sur le cadre rouge ci-dessous. Si vous appuyez sur le bouton Créer à cet endroit, la page suivante s'affiche. Le titre peut être n'importe quoi. Il semble distinguer lorsque vous créez plusieurs menus riches. (Il semble que vous ne pouvez pas changer le menu riche avec le même compte à moins que vous ne le fassiez vous-même) Je pense que la période d'affichage devrait être mise de côté plus longtemps. La date de début ne sortira que si elle est antérieure à la date de mise en œuvre. (Bien sûr)

Descendez dans ** Paramètres de contenu **. Vous pouvez sélectionner le nombre de divisions en appuyant sur ** Sélectionner modèle **. J'ai choisi 6 divisions ici. Si vous sélectionnez ** Télécharger l'image d'arrière-plan **, ce sera une image unilatérale, donc si vous souhaitez joindre une image individuellement à 6 divisions, appuyez sur ** Créer une image ** ci-dessous. Vous pouvez également choisir la réaction lorsque vous appuyez dessus avec une action. Cette fois, cela mènera à l'événement après cela, donc je vais en faire un texte. (Je ne pense pas avoir beaucoup d'occasions d'utiliser les autres) Voici quelques points lors de la création d'une image. Tout d'abord, vous pouvez télécharger l'image en appuyant sur l'icône du cercle rouge. Et le cadre extérieur est encadré par l'icône du cercle bleu. Je pense que ce serait mieux si nous ne pouvions pas comprendre les limites sans cela. Avec l'épaisseur par défaut, il y avait un espace, donc le bord était juste avec un maximum de 5. En outre, appuyez sur ** Appliquer ** dans le coin supérieur droit après tout. Si vous appuyez dessus au milieu, elle sera enregistrée comme une seule image en arrière-plan et vous ne pourrez pas la modifier individuellement. Ce menu riche est le résultat.

Le bouton d'accueil écrit dans le déroulement des opérations est l'icône Mickey en bas au centre. Il est responsable de renvoyer le texte "Accueil" lorsqu'il est pressé. Les cinq autres servent tous à sélectionner une catégorie, ils sont donc différents du bouton d'accueil.

Sélection de parc (bouton)

Après avoir appuyé sur le bouton d'accueil, un bouton comme celui ci-dessous apparaîtra afin que vous puissiez sélectionner un parc. Je décrirai approximativement le traitement lorsque vous appuyez sur le bouton d'accueil. Après cela, il y aura un événement post-back, et il y a des informations que je veux enregistrer, telles que le parc sélectionné, donc j'utilise des variables globales compte tenu de la portée des variables. Le processus après avoir appuyé sur le bouton d'accueil commence par ** les = "les" **. Les points importants sont les deux points suivants.

--Comment afficher les fichiers json

home_button.py


@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
    global park,genre,area,info_url,target_url,counter,situation

    text = event.message.text
    userid = event.source.user_id

    #Au début et réinitialiser
    if text == "domicile":
        #Initialisation
        park = "park"
        genre = "genre"
        area = "area"
        info_url = ""
        target_url = ""
        counter = 0
        situation = ""


        les = "les"
        template = template_env.get_template('theme_select.json')
        data = template.render(dict(items=les))


        select__theme_massage = FlexSendMessage(
                alt_text="Sélection du thème",
                contents=BubbleContainer.new_from_json_dict(json.loads(data))
                )
            
        line_bot_api.push_message(userid, messages=select__theme_massage) 

La première chose sur laquelle je veux écrire est TextMessage et FlexSendMessage. Ceux-ci doivent être falsifiés en haut du code source copié et collé en retour de perroquet. Il semble que le système d'événement, d'action et de message doit être importé comme indiqué ci-dessous. Si vous obtenez une erreur, veuillez vérifier si elle est décrite ici.

from linebot.models import (
    MessageEvent, TextMessage, PostbackTemplateAction, PostbackEvent, PostbackAction, QuickReplyButton, QuickReply,
    FlexSendMessage, BubbleContainer, CarouselContainer, TextSendMessage
)

Afficher les fichiers JSON

Pour être honnête, je ne sais comment l'appliquer qu'au modèle en utilisant jinja2, donc je ne comprends pas grand-chose. Par conséquent, si vous êtes débutant, il sera plus rapide de copier ** les = "les" ** ou moins.

  1. Créez un fichier json

J'ai utilisé Flex Message Simulator pour jouer avec le produit fini et le mettre en forme pour le moment.

```json:theme_select.json
{
"type": "bubble",
"hero": {
  "type": "image",
  "url": "https://secured.disney.co.jp/content/disney/jp/secured/dcc/tokuten/bf-tdr-prk-tckt/_jcr_content/par/dcc_hero_panel_image/image1.img.jpg/1474355301452.jpg ",
  "size": "full",
  "aspectRatio": "20:13",
  "aspectMode": "cover"
},
"body": {
  "type": "box",
  "layout": "vertical",
  "contents": [
    {
      "type": "text",
      "text": "Veuillez sélectionner un parc",
      "weight": "bold",
      "size": "lg"
    }
  ]
},
"footer": {
  "type": "box",
  "layout": "vertical",
  "spacing": "sm",
  "contents": [
    {
      "type": "button",
      "style": "link",
      "height": "sm",
      "action": {
        "type": "postback",
        "label": "terre",
        "data": "land"
      }
    },
    {
      "type": "button",
      "style": "link",
      "height": "sm",
      "action": {
        "type": "postback",
        "label": "C",
        "data": "sea"
      }
    },
    {
      "type": "spacer",
      "size": "sm"
    }
  ],
  "flex": 0
}

} ``` Le contenu de "action" est - type - label - data

«Type» est la forme d'échange de données, «étiquette» est ce qui est écrit sur le bouton (dans ce cas, «terre», «mer») et «données» est les données à recevoir. Il semble que les images et les sons soient également inclus dans les «données». Pour plus d'informations, veuillez lire Reference. (Supplément) Sélectionnez "type" d '"action": {} en fonction de l'objectif. Si vous souhaitez qu'il apparaisse sous forme de message lorsque l'autre partie appuie dessus, vous devez utiliser "type": message.

Important!

Pour enregistrer le fichier json, créez un dossier appelé templates dans la même hiérarchie et enregistrez-le dans ce dossier! Il semble qu'il lit à partir de là.

  1. Remplacez le code ci-dessous Remplacez la partie chaîne de caractères.

    template = template_env.get_template('theme_select.json')
    
  2. Lors de la mise en œuvre d'un carrousel (diapositive horizontale 1), passez au code ci-dessous Passer du conteneur à bulles au conteneur carrousel.

    select__theme_massage = FlexSendMessage(
            alt_text="Sélection du thème",
            contents=CarouselContainer.new_from_json_dict(json.loads(data))
            )

Différence entre push et reply

Vous pouvez pousser plusieurs fois pour un événement, mais la réponse ne semble possible qu'une seule fois. Donc, si vous répondez, vous ne pourrez plus envoyer de messages après cela. Par exemple, en supposant que le scraping prendra un certain temps, si vous souhaitez afficher "Traitement" lors de la réception d'un message de l'utilisateur puis afficher le résultat dans un fichier json, appuyez sur "Traitement" et envoyez le fichier json. Il sera résolu en répondant. En outre, push doit préparer l'ID utilisateur et le message. Regardez button.py ci-dessus et imitez-le.

push.py


line_bot_api.push_message(userid, messages=select__theme_massage) 

reply.py


line_bot_api.reply_message(
    event.reply_token,
    FlexSendMessage(
        alt_text="Affichage des résultats",
        contents=BubbleContainer.new_from_json_dict(json.loads(data))
    )
) 

Contrôle d'ouverture

La date / heure est utilisée pour afficher "fermé" à l'exception des heures d'ouverture. Voici les deux codes. La première consiste à recevoir les données de sélection de parc dans une publication, à vérifier les heures d'ouverture et à répondre à l'utilisateur avec la valeur de retour. Le second est un code qui confirme les heures d'ouverture. (prime)

** Remarque: ** Si le fuseau horaire d'Heroku n'est pas défini sur le Japon, datetime sera le fuseau horaire américain. Pour le réglage du fuseau horaire → cet article

postback_park.py


@handler.add(PostbackEvent)
def handle_postback(event):
    global park,genre,area,info_url,target_url,counter,situation
    area = ""

    post_data = event.postback.data
    userid = event.source.user_id

    if post_data == "land" or post_data == "sea":
        park = post_data
        if park == "land":
            #Liens tels que les heures d'ouverture et la météo
            info_url = "https://tokyodisneyresort.info/index.php?park=land"
            park_ja = "terre"
        
        elif park == "sea":
            #Liens tels que les heures d'ouverture et la météo
            info_url = "https://tokyodisneyresort.info/index.php?park=sea"
            park_ja ="C"

        #Vérifiez les heures d'ouverture
        business_hour = Scrape_day(info_url)
        situation = Check_park(business_hour)

        if situation == "close":
            print("close")
            line_bot_api.reply_message(
                event.reply_token,
                TextSendMessage(text="Le parc est fermé")
                )
                
        elif situation == "open":
            park_message = TextSendMessage(text= str(park_ja) + "Est sélectionné\n catégories dans le menu ci-dessous\n Veuillez sélectionner")
            line_bot_api.push_message(userid, messages=park_message)

Vider la zone évite les erreurs en supposant que vous appuyez accidentellement sur le bouton plusieurs fois.

check_park.py


#Vérifiez si c'est l'heure d'ouverture maintenant
def Check_park(business_hour):
    #Vérifiez l'heure et la date actuelles
    dt_now = dt.now()

    #La date d'aujourd'hui
    year = int(dt_now.year)
    month = int(dt_now.month)
    day = int(dt_now.day)

    #Division des heures d'ouverture
    open_time = business_hour.split("~")[0]
    if open_time.split(":")[0] == "":
        return "close"

    else:
        open_hour = int(open_time.split(":")[0])
        open_minute = int(open_time.split(":")[1])

        #Division de l'heure de fermeture
        close_time = business_hour.split("~")[1]
        close_hour = int(close_time.split(":")[0])
        close_minute = int(close_time.split(":")[1])

        #datetime
        open_datetime = dt(year,month,day,open_hour,open_minute)
        close_datetime = dt(year,month,day,close_hour,close_minute)


        if open_datetime < dt_now < close_datetime:
            return "open"

        else:
            return "close"

L'argument business_hour est une chaîne d'heures ouvrées extraite du site.

Sélectionnez la catégorie de temps d'attente que vous souhaitez obtenir si le parc est ouvert

Suite à la sélection du parc, s'il est ouvert, passez à l'étape suivante. Appuyez sur le menu riche que vous venez de créer et sélectionnez la catégorie dont vous souhaitez voir la latence. À ce stade, la catégorie sélectionnée s'affiche sous forme de texte à l'écran. La seule façon d'éviter cela est de créer votre propre menu riche.

Grattage → Sortie avec recette de message Flex

Comme mentionné ci-dessus, le code entier est publié sur github, je n'écrirai donc rien sur le scraping de latence. Cette section décrit comment utiliser la recette de Flex Message lors de la sortie de la valeur acquise. Si le nombre de chaînes de caractères à afficher est petit ou si vous ne vous souciez pas de la forme, le push ou la réponse décrit ci-dessus est suffisant, vous pouvez donc sauter ici.

Je vais également jouer avec le fichier json cette fois, mais je vais faire trois choses principales.

J'ai édité la recette de Flex Message Simulator et créé le fichier json suivant.

recipt.json


{
    "type": "bubble",
    "styles": {
    "footer": {
        "separator": true
    }
    },
    "body": {
    "type": "box",
    "layout": "vertical",
    "contents": [
        {
        "type": "text",
        "text": "Temps d'attente",
        "weight": "bold",
        "color": "#1DB446",
        "size": "sm"
        },
        {
        "type": "text",
        "text": "thème",
        "weight": "bold",
        "size": "xl",
        "margin": "md"
        },
        {
        "type": "separator",
        "margin": "xxl"
        },
        {
        "type": "box",
        "layout": "vertical",
        "margin": "xxl",
        "spacing": "sm",
        "contents": [
            
        ]
        }
    ]
    }
}

Incorporer des variables en partie

Je veux changer la partie où "texte": "thème" est écrit dans "texte": "caractère acquis", alors effectuez le traitement suivant.

set_json.py


def Send_area(area):
    json_file = open('templates/recipt.json', 'r',encoding="utf-8-sig")
    json_object = json.load(json_file)
    json_object["body"]["contents"][1]["text"] = str(area)
    #l'écriture
    new_json_file = open('templates/recipt.json', 'w',encoding="utf-8")
    json.dump(json_object, new_json_file, indent=2,ensure_ascii=False)

Comme procédure

  1. Tout d'abord, lisez le fichier json ci-dessus sous une forme inscriptible
  2. Allez là où se trouve le "texte": "thème" en spécifiant les éléments de la liste complexe (peut être facile à trouver dans certains éditeurs)
  3. Et si vous affectez une variable au contenu de "texte", vous pouvez affecter une variable à une pièce. C'est comme ça.

Intégrez des éléments qui changent de temps en temps

Ce problème a été résolu en incorporant une variable dans une boîte de forme fixe et en l'insérant en plus.

new_json.py


def Make_jsonfile(attraction,info):
    json_file = open('templates/recipt.json', 'r',encoding="utf-8-sig")
    json_object = json.load(json_file)

    new =   {
                "type": "box",
                "layout": "vertical",
                "margin": "xxl",
                "spacing": "sm",
                "contents": [
                {
                    "type": "box",
                    "layout": "horizontal",
                    "contents": [
                    {
                        "type": "text",
                        "text": str(attraction),
                        "size": "sm",
                        "color": "#555555",
                        "flex": 0
                    },
                    {
                        "type": "text",
                        "text": str(info),
                        "size": "md",
                        "color": "#111111",
                        "align": "end"
                    }
                    ]
                }
            ]
        }

    json_object["body"]["contents"][3]["contents"].append(new)

    new_json_file = open('templates/recipt.json', 'w',encoding="utf-8")
    json.dump(json_object, new_json_file, indent=2,ensure_ascii=False)

C'est compliqué, donc c'est difficile à comprendre, mais l'important est que nous faisons append (nouveau). Le contenu vide en bas du fichier recette.json ci-dessus est au format liste, vous pouvez donc y répondre en y ajoutant même si vous ne connaissez pas le nombre de données à afficher à l'avance. Dans new_json.py, le nom de l'attraction et le temps d'attente sont intégrés dans des variables, et une boîte qui les résume est insérée dans le contenu.

Initialisation du fichier

Bien sûr, si vous répétez l'ajout sans l'initialiser, les informations jusqu'à présent resteront. Avant de créer le recipt, il est initialisé en écrasant le recipt.json ci-dessus.

Résumé et futurs numéros

Même si c'était mon premier message, il est devenu assez long. Cette fois, je me suis concentré sur le menu riche et Flex Message que j'ai eu du mal, et j'espère que cela sera utile à quelqu'un. Les défis qui peuvent être soulevés sont

--Si vous pouvez obtenir des informations sur le site officiel, plus d'articles peuvent être affichés (même si je pense que c'est strict en termes de sécurité) ――Je veux créer mon propre menu riche et utiliser le menu riche lui-même de manière dynamique (lorsque j'appuie sur le menu riche, un nouveau menu riche apparaît à la place d'un bouton)

il y a. En particulier, il y a peu d'articles Python sur le deuxième menu riche, donc si quelqu'un qui lit cet article le connaît, je vous serais reconnaissant de le publier.

Recommended Posts

Afficher le temps d'attente de Disney avec le bot LINE
Surveillez les mises à jour des pages Web avec LINE BOT
J'ai fait un robot de remplacement de tampon avec une ligne
Créer un LINE BOT avec Minette pour Python
LINE BOT avec Python + AWS Lambda + API Gateway
J'ai créé un Bot LINE avec Serverless Framework!
Bot LINE sans serveur conçu avec IBM Cloud Functions
Créer un bot LINE WORKS avec Amazon Lex
[AWS] J'ai créé un BOT de rappel avec LINE WORKS
J'ai créé un bot de livre de compte de ménage avec LINE Bot
Faire un bot d'analyse morphologique de manière lâche avec LINE + Flask
Afficher le numéro de ligne de l'éditeur vim (avec les paramètres par défaut)
J'ai essayé de faire LINE BOT avec Python et Heroku
[Super facile] Faisons un LINE BOT avec Python.
[LINE Messaging API] Créer un BOT de retour de perroquet avec Python
Créer un LINE BOT
LINE BOT si ~ trébuché
Affichage de la barre des tâches avec tqdm
Afficher les séries chronologiques TOPIX
Créez un bot LINE avec GoogleAppEngine / py. Version nue simple
Créez une application d'apprentissage automatique avec ABEJA Platform + LINE Bot
Exécutons la commande à temps avec le bot discord
Jusqu'à ce que Django retourne quelque chose avec un robot de ligne!
[AWS] J'ai créé un BOT de rappel avec LINE WORKS (implémentation)