Letztes Mal habe ich eine Funktion zum Abrufen von Aktienkursinformationen implementiert, aber tatsächlich: "Richtig, ich habe die Aktien-App verwendet, ohne BOT zu fragen. Es ist nur eine Frage der Zeit, bis der Tsukkomi sagt: "Es ist bequemer", und ich verwende wahrscheinlich täglich eine bestimmte Portfolio-Management-App. Daher möchte ich, dass BOT den Aktienkurs genau bestimmt. Es kommt nicht dazu, das Bedürfnis zu haben. Also ging ich zurück zum Ausgangspunkt, fragte mich, welche Art von Funktion ich wollte, und suchte nach einer praktischeren Funktion.
"Ja, es wäre praktisch, wenn wir die (geplanten) Abrechnungstermine auf einmal erfassen könnten."
Wenn Sie viele Aktien besitzen, ist es ziemlich mühsam, den Zeitplan für einzelne Aktien, Halbjahresergebnisse, vierteljährliche Finanzergebnisse usw. täglich zu verfolgen. Es wäre praktisch, wenn es eine Funktion gäbe, die dies zentral erfassen und visualisieren könnte, und vor allem denke ich, es wäre gut, wenn es die ursprüngliche Art von BOT wäre.
Dieses Mal möchte ich eine äußerst fortschrittliche Schabetechnik entwickeln, die darauf abzielt, die Fähigkeiten zum Extrahieren und Analysieren von Informationen von der Website zu stärken.
Wenn Sie den Aktivierungscode einschließlich des Markencodes über die LINE-App (①) eingeben, greift BOT auf die Website zu, untersucht das Datum der Ankündigung der letzten Finanzergebnisse (geplant) und antwortet (②). Es wird auch davon ausgegangen, dass einzelne Aktien spezifiziert werden oder ein Portfolio im Voraus festgelegt wird und mehrere Aktien gleichzeitig erworben werden.
Wir werden eine Website namens Stock Forecast verwenden. Wenn Sie die Seite für einzelne Aktien öffnen, wird das Datum der letzten Bekanntgabe der Finanzergebnisse (geplant) an der in der folgenden Abbildung gezeigten Position angezeigt. Wenn die Finanzergebnisse bekannt gegeben wurden, wird diese Tatsache zusammen mit dem Datum angezeigt. Wenn die Ankündigung in Zukunft geplant ist, wird sie zusammen mit dem Datum als geplantes Ankündigungsdatum angezeigt. Die dieser Position entsprechende HTML-Quelle ist die Klasse "header_main", beginnend in Zeile 222. Sie können sehen, dass alle gewünschten Informationen darunter enthalten sind.
Daher scheint es, dass diese Mission durch das Verständnis der Fähigkeiten der folgenden drei Prozesse verwirklicht werden kann.
Also, wenn Sie zuerst die Schlussfolgerung schreiben
Für 1. Anfragen
2. Für "Schöne Suppe"
3. Für "re"
Sehr intelligente Codierung wird realisiert, indem jede von ihnen verwendet wird.
Da die Anforderung bereits bei der Implementierung des Chatbots gepackt wurde, werden Details weggelassen. Das Codierungsbeispiel lautet wie folgt
(Beispiel für die Skriptausführung)Verwendung von Anfragen
(botenv2) [botenv2]$ python
Python 3.6.7 (default, Dec 5 2018, 15:02:16)
>>> import requests
#HTML-Quelle abrufen
>>> r = requests.get('https://kabuyoho.ifis.co.jp/index.php?action=tp1&sa=report_top&bcode=4689')
#Inhaltsbestätigung
>>> print(r.headers)
{'Cache-Control': 'max-age=1', 'Content-Encoding': 'gzip', 'Content-Type': 'text/html; charset=UTF-8', (Kürzung)
>>> print(r.encoding)
UTF-8
>>> print(r.content)
(Kürzung)
Mit diesem Gefühl ist keine besondere Erklärung erforderlich. Da der gesamte Körperteil in r.inhalt gelagert wird, wird er anschließend gekocht oder gebacken. Sie können das Ziel-HTML-Tag als Schlüssel zum Abrufen von Informationen verwenden.
Es scheint, dass es ein berühmtes Paket ist und bereits verschiedene Parser implementiert. Als ich es einführte, konnte ich diesmal 90% des Zwecks erreichen. ..
Schöne Suppeninstallation
(botenv2) [botenv2]$ pip install BeautifulSoup4
(Beispiel für die Skriptausführung@Fortsetzung)Wie man schöne Suppe benutzt
>>> from bs4 import BeautifulSoup
#Analyse des Körperteils mit Parser
>>> soup = BeautifulSoup(r.content, "html.parser")
Versuchen Sie, die Klasse header_main anzuzeigen.
python
>>> print(soup.find("div", class_="header_main"))
Ausführungsergebnis
<div class="header_main">
<div class="stock_code left">4689</div>
<div class="stock_name left">Z Holdings</div>
<div class="block_update right">
<div class="title left">
Ergebnis bekannt gegeben
</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>
Es ist wunderbar. Es ist zu bequem, um nicht mehr zu zittern.
Sie müssen nur noch unnötige Zeichenfolgen löschen. Verwenden Sie die Textmethode, da keine HTML-Tags erforderlich sind.
(Beispiel für die Skriptausführung@Fortsetzung)Textextraktion
>>> s = soup.find("div", class_="header_main").text
>>> print(s)
4689
Z Holdings
Ergebnis bekannt gegeben
2Q
2019/11/01
>>>
Die Tags wurden gelöscht, aber es gibt noch viele mysteriöse Lücken. Ich wusste nicht, ob dies ein Leerzeichen oder ein Meta-Charakter ist, also habe ich mich für einen Moment in ihn verliebt. In einem solchen Fall kann die Substanz angezeigt werden, indem sie im Bytetyp angezeigt wird.
(Referenz)Bestätigung des Zeichencodes
>>> 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'
Der Punkt ist, / n und / t zu entfernen. Ersetzen wir es gnadenlos durch ein Komma und begraben es.
(Beispiel für die Skriptausführung@Fortsetzung)Entfernung von Metazeichen
>>> import re
>>> s = re.sub(r'[\n\t]+', ',', s)
>>> print(s)
,4689,Z Holdings,Ergebnis bekannt gegeben,2Q,2019/11/01,
Wenn Sie die störenden Kommas vor und nach dem Ende entfernen
(Beispiel für die Skriptausführung@Fortsetzung)
>>> s = re.sub(r'(^,)|(,$)','', s)
>>> print(s)
4689,Z Holdings,Ergebnis bekannt gegeben,2Q,2019/11/01
Es fühlt sich gut an. Es scheint, dass es so wie es ist in CSV oder Datenrahmen konvertiert werden kann.
Übrigens, wenn ein nicht existierender Markencode erfasst wird, bleibt der folgende Zeichencode nach der obigen Verarbeitung erhalten.
Für nicht existierenden Bestandscode
>>> print(s)
b'\xc2\xa0'
Dieses \ xc2 \ xa0
bedeutet in Unicode NO-BREAK SPACE und entspricht & nbsp
in HTML.
Wenn dieser Zeichencode enthalten ist, stört er die nachfolgende Verarbeitung, daher ist es wünschenswert, ihn nach Möglichkeit zu entfernen.
(Es scheint ein häufiges Problem beim Scraping von Webseiten zu sein.)
(Referenz) [Python3] Was tun, wenn beim Scraping [\ xa0] auftritt?
&Entfernung von nbsp
s = re.sub(r'[\xc2\xa0]','', s)
Hier ist eine funktionalisierte Version des obigen Prozesses.
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='
#Erfassungsfunktion für das Abrechnungsdatum(4689 wenn das Argument leer ist(ZHD)Siehe die Daten von)
def get_settleInfo(code="4689"):
#Krabbeln
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'
#Schaben
soup = BeautifulSoup(r.content, "html.parser")
settleInfo = soup.find("div", class_="header_main").text
settleInfo = re.sub(r'[\n\t]+', ',', settleInfo) #Entfernen von Metazeichen
settleInfo = re.sub(r'(^,)|(,$)','', settleInfo) #Entfernen Sie Kommas am Anfang und Ende von Zeilen
settleInfo = re.sub(r'[\xc2\xa0]','', settleInfo) # (\xc2\xa0)Umgang mit dem Problem
logger.debug('settleInfo result = ' + settleInfo) #logging
if not settleInfo:
settleInfo = 'Es gibt keine solche Marke ~'
return settleInfo
if __name__ == '__main__':
print(get_settleInfo())
Fügen Sie für das Hauptprogramm die bedingte Verzweigungsverarbeitung hinzu, indem Sie den Aktivierungscode wie gewohnt identifizieren. Wenn Sie im Voraus Ihr eigenes Portfolio in "SETTLEVIEW_LIST_CORD" erstellen, sind Sie zur Chargenerfassung berechtigt.
chatbot.py(★ Ergänzung)##Der vorhandene Funktionsteil wird weggelassen, da er nicht geändert wird.
# -*- 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 = ''
###
###Ausgelassen
###
SETTLEVIEW_KEY = ['Siedlung','settle'] #★ Ergänzung
SETTLEVIEW_LIST_KEY = ['Liste der Finanzergebnisse'] #★ Ergänzung
SETTLEVIEW_LIST_CORD = ['4689','3938','4755','1435','3244','3048'] #★ Ergänzung
@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:
###
###Ausgelassen
###
elif any(s in event['message']['text'] for s in SETTLEVIEW_KEY): #★ Ergänzung
action_data(reply_token,'settleview',event['message']['text']) #★ Ergänzung
else:
###
###Ausgelassen
###
return HttpResponse(status=200)
def action_res(reply_token,command,):
###
###Ausgelassen
###
def action_data(reply_token,command,value):
#Aktienchart
###
###Ausgelassen
###
#######################################################★ Ergänzung von hier
#Finanzinformation
elif command == 'settleview':
logger.debug('get_settleInfo on') #logging
#Kollektiver Erwerb von Portfolioaktien
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))
#Erwerb einzelner Aktien
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])
#######################################################★ Ergänzung bis hierher
def response_image(reply_token,orgUrl,preUrl,text):
###
###Ausgelassen
###
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):
###
###Ausgelassen
###
Damit ist der Vorgang abgeschlossen.
line_Bot starten
(botenv2) [line_bot]$ gunicorn --bind 127.0.0.1:8000 line_bot.wsgi:application
Wenn Sie eine Nachricht gemäß dem Format aus der LINE-App löschen, wird das Ergebnis zurückgegeben.
Wenn Sie alles auf einmal erhalten möchten, geben Sie "Financial Statement List" ein.
Es dauert ungefähr 1 Sekunde, um 6 Marken seriell zu messen. Ich war beeindruckt von der schnelleren Verarbeitung, als ich es mir vorgestellt hatte, aber falls es mich zu sehr stört, werde ich sie mäßig verwenden, um nicht häufig darauf zuzugreifen. Bis hierher für diese Zeit.
Recommended Posts