** Bold ** est l'endroit où j'ai eu du mal
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.
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)
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
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
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.
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
)
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.
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.
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à.
Remplacez le code ci-dessous Remplacez la partie chaîne de caractères.
template = template_env.get_template('theme_select.json')
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))
)
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))
)
)
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.
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.
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": [
]
}
]
}
}
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
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.
La raison pour laquelle l'encodage est effectué avec utf-8-sig est d'éviter les erreurs. Si vous rencontrez une erreur avec utf-8, veuillez consulter ce site → UnicodeDecodeError: When'cp932'appears
Si la vérification du journal de Heroku indique vide, c'est probablement la cause. Le contenu original étant vide, j'obtiens une erreur lors de l'impression si rien n'a été ajouté. Tout d'abord, vérifions si la case est ajoutée au contenu.
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.
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