[PYTHON] Comment créer un LINE BOT 004 interactif (répondre à la date de clôture d'une société cotée)

Aperçu

La dernière fois, j'ai implémenté une fonction pour acquérir des informations sur le cours des actions, mais en fait, "C'est vrai, j'ai utilisé l'application boursière sans demander au BOT. Ce n'est qu'une question de temps avant que le tsukkomi ne dise: «C'est plus pratique», et j'utilise probablement une certaine application de gestion de portefeuille quotidiennement, alors j'aimerais que BOT identifie le cours de l'action. Il n'en vient pas à avoir le besoin. Je suis donc retourné au point de départ, je me suis demandé quel type de fonction je souhaitais et j'ai recherché une fonction plus pratique.

"Oui, ce serait pratique si nous pouvions saisir les dates de règlement (prévues) d'un seul coup."

Si vous possédez beaucoup d'actions, il est assez difficile de suivre quotidiennement le calendrier des actions individuelles, les résultats financiers semestriels, les résultats financiers trimestriels, etc. Ce serait pratique s'il y avait une fonction qui puisse collecter et visualiser cela de manière centralisée, et surtout, je pense que ce serait bien si c'était la manière originale de BOT.

Donc, cette fois, je voudrais faire une technique de grattage extrêmement avancée visant à renforcer les compétences pour extraire et analyser les informations du site Web.

Configuration du système

Lorsque vous entrez le code d'activation comprenant le code de la marque à partir de l'application LINE (①), le BOT accède au site Web, examine la dernière date d'annonce des résultats financiers (prévue) et répond (②). Il est également supposé que les actions individuelles seront spécifiées ou qu'un portefeuille sera défini à l'avance et plusieurs actions seront acquises à la fois.

システム構成004.png

1. Sélection du site Web cible

Nous utiliserons un site appelé Stock Forecast. Lorsque vous ouvrez la page des actions individuelles, la dernière date d'annonce des résultats financiers (prévue) est affichée à la position indiquée dans la figure ci-dessous. Si les résultats financiers ont été annoncés, ce fait sera affiché avec la date. Si son annonce est prévue à l'avenir, elle sera affichée avec la date comme date d'annonce prévue. La source HTML correspondant à cette position est la classe «" header_main "» commençant à la ligne 222. Vous pouvez voir que toutes les informations que vous souhaitez sont incluses en dessous.

HTML BODY.png

Par conséquent, il semble que cette mission puisse être réalisée en comprenant les compétences des trois processus suivants.

  1. Obtenez la source HTML
  2. Perspective, extraction de la balise <div class =" header_main ">
  3. Formatage des chaînes

Donc, si vous écrivez d'abord la conclusion Pour 1. demandes 2. Pour "Belle soupe" 3. Pour «re» Un codage très intelligent est réalisé en utilisant chacun d'eux.

2. Obtenir la source HTML par requêtes

La requête ayant déjà été packagée lors de la mise en œuvre du chatbot, les détails sont omis. L'exemple de codage est le suivant

(Exemple d'exécution de script)Comment utiliser les demandes


(botenv2) [botenv2]$ python
Python 3.6.7 (default, Dec  5 2018, 15:02:16) 
>>> import requests

#Obtenir la source HTML
>>> r = requests.get('https://kabuyoho.ifis.co.jp/index.php?action=tp1&sa=report_top&bcode=4689')

#Confirmation de contenu
>>> print(r.headers)
{'Cache-Control': 'max-age=1', 'Content-Encoding': 'gzip', 'Content-Type': 'text/html; charset=UTF-8', (réduction)
>>> print(r.encoding)
UTF-8
>>> print(r.content)
(réduction)

Avec ce sentiment, aucune explication particulière n'est nécessaire. Puisque toute la partie du corps est stockée dans r.content, elle sera bouillie ou cuite par la suite. Vous pouvez utiliser la balise HTML cible comme clé pour extraire des informations.

3. Introduction de Beautiful Soup (parser)

Il semble que ce soit un package célèbre et implémente déjà divers analyseurs. Lorsque je l'ai présenté, j'ai pu atteindre 90% de l'objectif cette fois. .. Comparé à l'époque où je jouais avec le langage C, je me sens comme un monde à part.

Belle installation de soupe


(botenv2) [botenv2]$ pip install BeautifulSoup4

(Exemple d'exécution de script@A continué)Comment utiliser Beautiful Soup


>>> from bs4 import BeautifulSoup

#Analyse de la partie Body avec un analyseur
>>> soup = BeautifulSoup(r.content, "html.parser")

Essayez d'afficher la classe header_main.

python


>>> print(soup.find("div", class_="header_main"))

Résultat d'exécution



<div class="header_main">
<div class="stock_code left">4689</div>
<div class="stock_name left">Participations Z</div>
<div class="block_update right">
<div class="title left">
Revenus annoncés
                                                        </div>
<div class="settle left">
                                                                        2Q
                                                        </div>
<div class="date left">
                                                                                                   2019/11/01
                                                                                                </div>
<div class="float_end"></div>
</div>
<div class="float_end"></div>
</div>

C'est incroyable. C'est trop pratique d'arrêter de trembler.

3. Formatage des chaînes

Il ne reste plus qu'à supprimer les chaînes de caractères inutiles. Étant donné que les balises HTML ne sont pas requises, utilisez la méthode text.

(Exemple d'exécution de script@A continué)Extraction de texte


>>> s = soup.find("div", class_="header_main").text
>>> print(s)
4689
Participations Z


Revenus annoncés
                                                 

                                                                        2Q
                                                 

                                                                                                   2019/11/01
                                                                                         




>>> 

Les balises ont été effacées, mais il reste encore beaucoup de lacunes mystérieuses. Je ne savais pas s'il s'agissait d'un espace ou d'un méta-personnage, alors j'en suis tombé amoureux pendant un moment. Dans un tel cas, la substance peut être vue en l'affichant sous forme d'octet.

(référence)Confirmation du code de caractère


>>> s.encode()
b'\n4689\n\xef\xbc\xba\xe3\x83\x9b\xe3\x83\xbc\xe3\x83\xab\xe3\x83\x87\xe3\x82\xa3\xe3\x83\xb3\xe3\x82\xb0\xe3\x82\xb9\n\n\n\t\t\t\t\t\t\t\t\t\xe6\xb1\xba\xe7\xae\x97\xe7\x99\xba\xe8\xa1\xa8\xe6\xb8\x88\n\t\t\t\t\t\t\t\n\n\t\t\t\t\t\t\t\t\t2Q\n\t\t\t\t\t\t\t\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t2019/11/01\n\t\t\t\t\t\t\t\t\t\t\t\t\n\n\n\n'

Le but est de supprimer / n et / t. Remplaçons-le sans pitié par une virgule et enterrons-le.

(Exemple d'exécution de script@A continué)Suppression de méta-caractères


>>> import re
>>> s = re.sub(r'[\n\t]+', ',', s)
>>> print(s)
,4689,Participations Z,Revenus annoncés,2Q,2019/11/01,

Si vous supprimez les virgules inquiétantes avant et après la fin

(Exemple d'exécution de script@A continué)


>>> s = re.sub(r'(^,)|(,$)','', s)
>>> print(s)
4689,Participations Z,Revenus annoncés,2Q,2019/11/01

Ça fait du bien. Il semble qu'il puisse être converti en CSV ou en dataframe tel quel.

À propos, lorsqu'un code de marque qui n'existe pas est acquis, le code de caractère suivant reste après le traitement ci-dessus.

Pour code stock inexistant


>>> print(s)
b'\xc2\xa0'

Ce \ xc2 \ xa0 signifie NO-BREAK SPACE en Unicode et correspond à & nbsp en HTML. Si ce code de caractère est inclus, il interférera avec le traitement ultérieur, il est donc souhaitable de le supprimer si possible. (Cela semble être un problème courant lors du scraping de pages Web.)

(Référence) [Python3] Que faire si vous rencontrez [\ xa0] pendant le scraping

&suppression de nbsp


s = re.sub(r'[\xc2\xa0]','', s)

4. Implémenté dans l'application BOT

Voici une version fonctionnalisée du processus ci-dessus.

getSettledata.py


import requests
from bs4 import BeautifulSoup
import re
import logging
logger = logging.getLogger('getSettledata')

source = 'https://kabuyoho.ifis.co.jp/index.php?action=tp1&sa=report_top&bcode='

#Fonction d'acquisition de la date de règlement(4689 si l'argument est vide(ZHD)Se référer aux données de)
def get_settleInfo(code="4689"):

  #Rampant
  try:
    logger.debug('read web data cord = ' + code) #logging
    r = requests.get(source + code)
  except:
    logger.debug('read web data ---> Exception Error') #logging
    return None, 'Exception error: access failed'

  #Grattage
  soup = BeautifulSoup(r.content, "html.parser")
  settleInfo = soup.find("div", class_="header_main").text
  settleInfo = re.sub(r'[\n\t]+', ',', settleInfo) #Suppression des méta caractères
  settleInfo = re.sub(r'(^,)|(,$)','', settleInfo) #Supprimer les virgules au début et à la fin des lignes
  settleInfo = re.sub(r'[\xc2\xa0]','', settleInfo) #&nbsp(\xc2\xa0)Faire face au problème
  logger.debug('settleInfo result = ' + settleInfo) #logging

  if not settleInfo:
    settleInfo = 'Il n'y a pas de telle marque ~'

  return settleInfo

if __name__ == '__main__':
  print(get_settleInfo())

Pour le programme principal, ajoutez un traitement de branche conditionnel en identifiant le code d'activation comme d'habitude. Si vous créez votre propre portfolio dans SETTLEVIEW_LIST_CORD à l'avance, vous serez éligible pour l'acquisition par lots.

chatbot.py(★ Ajout)##La partie fonction existante est omise car elle n'est pas modifiée.


# -*- Coding: utf-8 -*-

from django.views.decorators.csrf import csrf_exempt
from django.http import HttpResponse
from django.shortcuts import render
from datetime import datetime
from time import sleep
import requests
import json
import base64
import logging
import os
import random
import log.logconfig
from utils import tools
import re
from .getStockdata import get_chart
from .getSettledata import get_settleInfo

logger = logging.getLogger('commonLogging')

LINE_ENDPOINT = 'https://api.line.me/v2/bot/message/reply'
LINE_ACCESS_TOKEN = ''

###
###Omis
###

SETTLEVIEW_KEY = ['Règlement','settle'] #★ Ajout
SETTLEVIEW_LIST_KEY = ['Liste des résultats financiers'] #★ Ajout
SETTLEVIEW_LIST_CORD = ['4689','3938','4755','1435','3244','3048'] #★ Ajout

@csrf_exempt
def line_handler(request):

    #exception
    if not request.method == 'POST':
      return HttpResponse(status=200)

    logger.debug('line_handler message incoming') #logging
    out_log = tools.outputLog_line_request(request) #logging
    request_json = json.loads(request.body.decode('utf-8'))

    for event in request_json['events']:
      reply_token = event['replyToken']
      message_type = event['message']['type']
      user_id = event['source']['userId']

      #whitelist
      if not user_id == LINE_ALLOW_USER:
        logger.warning('invalid userID:' + user_id) #logging
        return HttpResponse(status=200)

      #action
      if message_type == 'text':
        if:
        ###
        ###Omis
        ###

        elif any(s in event['message']['text'] for s in SETTLEVIEW_KEY): #★ Ajout
          action_data(reply_token,'settleview',event['message']['text']) #★ Ajout

        else:
        ###
        ###Omis
        ###

    return HttpResponse(status=200)

def action_res(reply_token,command,):
    ###
    ###Omis
    ###

def action_data(reply_token,command,value):

    #Graphique boursier
    ###
    ###Omis
    ###

    #######################################################★ Ajout d'ici
    #L'information financière
    elif command == 'settleview':
      logger.debug('get_settleInfo on') #logging

      #Acquisition collective de titres en portefeuille
      if any(s in value for s in SETTLEVIEW_LIST_KEY): 
        logger.debug('get_settleInfo LIST') #logging

        results = []
        for cord in SETTLEVIEW_LIST_CORD:
          results.append(get_settleInfo(cord))

        logger.debug('get_settleInfo LIST ---> ' + '\n'.join(results)) #logging
        response_text(reply_token,'\n'.join(results))

      #Acquisition de stocks individuels
      else:
        cord = re.search('[0-9]+$', value)
        logger.debug('get_settleInfo cord = ' + cord.group()) #logging

        result = get_settleInfo(cord.group())

        if result[0] is not None:
          response_text(reply_token,result)
        else:
          response_text(reply_token,result[1])
    #######################################################★ Ajout jusqu'à ici

def response_image(reply_token,orgUrl,preUrl,text):
    ###
    ###Omis
    ###

def response_text(reply_token,text):
    payload = {
      "replyToken": reply_token,
      "messages":[
        {
          "type": 'text',
          "text": text
        }
      ]
    }
    line_post(payload)

def line_post(payload):
    url = LINE_ENDPOINT
    header = {
      "Content-Type": "application/json",
      "Authorization": "Bearer " + LINE_ACCESS_TOKEN
    }
    requests.post(url, headers=header, data=json.dumps(payload))
    out_log = tools.outputLog_line_response(payload) #logging
    logger.debug('line_handler message -->reply') #logging

def ulocal_chatting(event):
    ###
    ###Omis
    ###

Ceci termine.

line_Lancer le bot


(botenv2) [line_bot]$ gunicorn --bind 127.0.0.1:8000 line_bot.wsgi:application

Si vous déposez un message selon le format de l'application LINE, le résultat sera renvoyé.

sc003.png

Si vous voulez tout obtenir en même temps, entrez «Liste des états financiers».

sc004.png

Il faut environ 1 seconde pour mesurer 6 marques en série. J'ai été impressionné par le fait qu'il a été traité plus rapidement que je ne l'avais imaginé, mais au cas où cela me dérangerait trop, je l'utiliserai modérément pour ne pas y accéder fréquemment. Jusqu'à ici pour cette fois.

Recommended Posts

Comment créer un LINE BOT 004 interactif (répondre à la date de clôture d'une société cotée)
L'explication la plus simple au monde sur la création de LINE BOT (1) [Account preparation]
Comment créer un bot slack
L'explication la plus facile à comprendre au monde sur la création de LINE BOT (3) [Coopération avec un serveur avec Git]
Comment créer un bot LINE à intelligence artificielle avec l'API de messagerie Flask + LINE
Comment mettre un numéro de ligne au début d'un fichier CSV
Comment calculer la volatilité d'une marque
Comment faire un Raspberry Pi qui parle les tweets d'un utilisateur spécifié
Comment créer un article à partir de la ligne de commande
Créez un BOT qui raccourcit l'URL Discord
Comment créer un outil CLI interactif avec Golang
Bases de PyTorch (2) -Comment créer un réseau de neurones-
Comment frapper le document de Magic Function (Line Magic)
Comment afficher la date de modification d'un fichier en langage C jusqu'à nanosecondes
L'explication la plus simple au monde sur la création de LINE BOT (2) [Préparation de l'application Bot dans un environnement local avec Django de Python]
Comment créer un BOT Cisco Webex Teams à l'aide de Flask
[Python] Comment créer une liste de chaînes de caractères caractère par caractère
Créer un LINE BOT (chat)
[Python] J'ai essayé de laisser LINE BOT répondre aux prévisions météo
Comment trouver le coefficient de mise à l'échelle d'une ondelette bipolaire
Comment connecter le contenu de la liste dans une chaîne de caractères
J'ai créé un robot Line qui devine le sexe et l'âge d'une personne à partir de l'image
Comment déterminer l'existence d'un élément sélénium en Python
Comment connaître la structure interne d'un objet en Python
Comment transformer une chaîne en tableau ou un tableau en chaîne en Python
Comment vérifier la taille de la mémoire d'une variable en Python
Créez le thème de Pythonista 3 comme Monokai (comment créer votre propre thème)
Comment faire une commande pour lire le fichier de paramètres avec pyramide
Comment vérifier la taille de la mémoire d'un dictionnaire en Python
Comment trouver l'adresse mémoire de la valeur de la trame de données Pandas
Comment afficher le résultat de sortie de la commande man Linux dans un fichier
Comment obtenir les coordonnées de sommet d'une entité dans ArcPy
Comment extraire la chaîne de caractères souhaitée à partir d'une ligne 4 commandes
[Python] Comment créer une matrice de motifs répétitifs (repmat / tile)
[NNabla] Comment supprimer le niveau intermédiaire d'un réseau prédéfini
Comment faire une traduction japonais-anglais
Comment créer un robot - Avancé
Comment créer une fonction récursive
[Blender] Comment créer un plug-in Blender
Comment créer un robot - Basic
L'histoire de la recherche d'un magasin BOT (AI LINE BOT) pour Go To EAT dans la préfecture de Chiba (1)
[Fabric] J'étais accro à l'utilisation de booléen comme argument, alors notez les contre-mesures.
L'histoire de la création d'un robot LINE pour le petit-déjeuner d'une université de 100 yens avec Python
Les débutants en Python ont décidé de créer un bot LINE avec Flask (commentaire approximatif de Flask)
Comment créer un bot Janken qui peut être facilement déplacé (commentaire)
[Introduction à Python] Comment trier efficacement le contenu d'une liste avec le tri par liste
[NNabla] Comment ajouter une couche de quantification à la couche intermédiaire d'un modèle entraîné
Comment créer un wrapper qui préserve la signature de la fonction à envelopper
Comment lire une vidéo tout en regardant le nombre d'images (Mac)
Un exemple de réponse à la question de référence de la session d'étude. Avec python.
[Python] Comment rendre une classe itérable
Comment vérifier la version de Django
Histoire de faire une recherche de magasin BOT (AI LINE BOT) pour Go To EAT dans la préfecture de Chiba (2) [Présentation]
Partie 1 J'ai écrit un exemple de la réponse au problème de référence de l'écriture hors ligne en temps réel en Python
Comment enregistrer les informations de point caractéristique de l'image dans un fichier et l'utiliser pour la mise en correspondance
Comment créer un indicateur personnalisé Backtrader
Comment créer un plan de site Pelican
Création d'un bot Slack qui confirme et notifie à AWS Lambda la date d'expiration d'un certificat SSL