[Python / GAS] Une histoire sur la création d'une API Web personnelle qui vous permet de tout savoir sur comment devenir un romancier en écriture verticale, puis en faire un bot LINE.

introduction

Aimez-vous tous votre vie de retenue? Je ne peux pas entrer à l'université, alors je passe mon temps à étudier la programmation à la maison, ce qui n'a rien à voir avec la recherche. ~~ Plus amusant que la recherche ... ~~

De plus, j'ai plus de temps pour lire. Même si vous dites lire, le pourcentage de personnes qui lisent «Devenir romancier» est élevé.

Donc, afin de rendre une telle vie de retenue aussi confortable que possible

** Vous pouvez lire plusieurs épisodes du travail de devenir romancier en écriture verticale **

J'ai fait une telle API Web.

mouvement

L'API Web créée cette fois est

-------- API Naro Novel --------

** Recherche de romans par mot spécifié **   ↓ ** Sélectionnez l'œuvre avec le plus grand total de points et obtenez NCODE **   ↓ -------- API Naro Novel --------   ↓ ** Supprimez l'histoire dans la plage spécifiée **   ↓ ** Formaté verticalement en HTML de type roman **   ↓ ** À condition de **

Je traite dans le flux.

Lorsqu'il est accessible depuis un smartphone, il ressemble à ce qui suit. Vous pouvez le lire en le faisant défiler horizontalement. (D'après 10 épisodes de réincarnation au chômage) image.png

À partir du PC image.png

la mise en oeuvre

Python D'abord de Python Le grattage peut être surmonté avec juste des «demandes» et «re», et la partie serveur utilise «Flask».

# -*- coding: utf-8 -*-
from flask import Flask
from requests import get
import re

app = Flask(__name__)


def narou_html(keyword, num=1, pivot='e'):
    honbun_ = ""
    item = get(
        f"https://api.syosetu.com/novelapi/api/?out=json&of=t-n&lim=1&order=hyoka&word={keyword}"
    ).json()[1]
    #item = max(items[1:], key=lambda x: x["global_point"])  #Vestiges d'une époque où vous ne saviez pas que vous pouviez accéder à l'API sous une forme triée
    url = "https://ncode.syosetu.com/"
    ncode = item["ncode"]
    headers = {
        'User-Agent':
        'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36'
    }
    t = get(url + ncode, headers=headers).text
    slist = []
    sl = re.findall('<dl class="novel_sublist2">(.+?)</dl>',
                    t.replace("\n", ""))
    for i in sl[-num:] if pivot == 'e' else sl[:num +
                                               1] if pivot == 's' else sl[
                                                   int(pivot) - 1:int(pivot) +
                                                   num - 1]:
        groups = re.search(
            '<a href="/(.+?)/">(.+?)</a></dd><dt class="long_update">(.+?)[(?:<span)|(?:</dt>)]',
            i)
        slist.append({
            "title": groups.group(2),
            "href": groups.group(1),
            "long_update": groups.group(3)
        })
    for s in range(len(slist)):
        t = get(url + slist[s]["href"], headers=headers).text
        honbun = re.search(
            '<p class="novel_subtitle">(?:.|\s)+?<div id="novel_honbun"(?:.|\s)+?</p>\n</div>',
            t).group(0)
        for j, i in enumerate(honbun.splitlines()):
            if i[:2] == "<p":
                groups = re.search("(<p.*?>)(.+?)(</p>)", i)
                i = re.sub('(\d{1,4})',
                           '<span class="text-combine">\\1</span>',
                           groups.group(2))
                if i[0] in ('(', '「', '(', '『',
                            '【') and honbun_[-9] not in (')', ')', '」', '』',
                                                         '】'):
                    i = '<br><br>' + i
                if i[-1] in (')', ')', '」', '』', '】'):
                    i += '<br><br>'
                if i[0] == '・': i = '<br>' + i + '<br>'
                elif j > 1 and i[0] != '<' and honbun_[-1] != '>':
                    if re.match("\s", i):
                        i = i[1:]
                elif not re.match('\s', i) and i[0] not in ('(', '「', '(', '『',
                                                            '【'):
                    i = " " + i
                if j == 0:
                    i = '<h3>' + i + '</h3>\n<br><br>'
            honbun_ += i
        honbun_ += "<br>" * 25 + "\n"
    honbun_ = '''<html>

<head>
    <meta name="viewport" content="initial-scale=1.3,minimum-scale=1.3">
    <style>
        body {
            margin-top: 3.5%;
            margin-bottom: 3%;
            white-space: break-all;
            -ms-writing-mode: tb-rl;
            writing-mode: vertical-rl;
            text-orientation: upright;
            font-family: "Noto Serif JP", serif;
            font-size: 85%;
        }

        .text-combine {
            -webkit-text-combine: horizontal;
            -ms-text-combine-horizontal: all;
            text-combine-upright: all;
        }
    </style>
    <title>''' + item["title"] + '''</title>
    <link href="https://fonts.googleapis.com/css?family=Noto+Serif+JP&display=swap&subset=japanese" rel="stylesheet">
</head>

<body>
    ''' + honbun_[:-93].replace('→', '↓').replace('-', '|').replace("-", "|") + '''</body>

</html>'''
    return honbun_


@app.route("/")
def hello_world():
    return "Usage: http://ip-address:port/title/pivot/num             pivot - s: from the first. e: from the end. m: pick up one."


@app.route('/<keyword>/<pivot>/<num>')
def html_(keyword, pivot, num):
    html = narou_html(keyword, int(num), pivot)
    return html


if __name__ == "__main__":
    app.run(host="0.0.0.0")

(Si vous utilisez beaucoup d'expressions régulières, le code couleur de Qiita s'effondrera à cause d'une barre oblique inverse et ce sera triste) Étant donné que la mise en forme est faite pour bien paraître avec un sens, parfois des phrases qui devraient être brisées sont liées.

Après exécution http: // localhost: 5000 / mot de recherche / décrit plus tard / décrit plus tard (uniquement à partir du terminal d'exécution) ou http: // adresse IP locale du terminal en cours d'exécution: 5000 / mot de recherche / décrit plus tard / décrit plus tard Vous pouvez le lire sur. La partie de «décrite plus loin» est Pour le premier, depuis le premier épisode avec «s», depuis le dernier épisode avec «e», depuis la partie indiquée par «numéro» Qu'y a-t-il derrière, combien d'histoires retourner Vous pouvez spécifier.

GAS(Google Apps Script)

J'ai essayé de le télécharger sur Heroku pour en faire un bot LINE, mais il semblait que je ne pouvais pas me débarrasser du serveur de Heroku pour devenir romancier, alors je l'ai réécrit avec GAS. J'ai fait. Je n'écris pas beaucoup de Javascript lui-même, mais en plus de cela, le code, comme les fonctions spécifiques à GAS, était court mais difficile à essayer et erreur. Surtout, je lance généralement Jupyter immédiatement! Réponse immédiate! Il était fatal que le journal ne puisse pas être affiché correctement parce que je m'y suis habitué.

Utilisation de deux projets à utiliser comme bot LINE, L'un est pour la réponse LINE, Le second est pour l'API Web similaire au code Python ci-dessus C'était fabriqué.

Lorsque vous envoyez un message, le premier projet répondra avec une URL, et lorsque vous accédez à cette URL, le deuxième projet vous fournira une page formatée du roman. C'est un flux. GAS est incroyable que vous puissiez le faire gratuitement. Mais c'est lent.

Le premier renvoie simplement l'URL, donc je vais vous demander de regarder le site qui explique comment créer un bot LINE avec GAS, et je vais juste mettre le deuxième code. En outre, ici, il est simplifié à partir de la version Python, comme l'implémentation uniquement à partir de la dernière histoire pour renvoyer le nombre d'histoires spécifié (plutôt, le côté Python a été amélioré après avoir écrit ceci).

function doGet(e) {
  var keyword = e.parameter.keyword; //Rechercher un mot
  var num = parseInt(e.parameter.num); //Nombre d'histoires
  var getUrl = "https://api.syosetu.com/novelapi/api/?out=json&of=t-n&lim=1&order=hyoka&word="+keyword;
  var response = UrlFetchApp.fetch(getUrl).getContentText('UTF-8');
  var json = JSON.parse(response)[1];
  var title = json["title"]
  var ncode = json["ncode"]
  getUrl = "https://ncode.syosetu.com/"+ncode;
  response = UrlFetchApp.fetch(getUrl).getContentText('UTF-8').replace(/[\r\n]+/g,"");
  var items = response.match(/<dl class="novel_sublist2">(.+?)<\/dl>/gm);
  items = items.slice(items.length-num,items.length);
  var slist = [];
  for (var i = 0;i<num;i++){
    slist.push(items[i].match(/(<a href="\/)(.+?)(\/">)/)[2]); //Collecter des hrefs pour des histoires spécifiées
  }
  var honbun = ""
//En dessous du temps de mise en forme
  for (var s = 0;s<num;s++){
    getUrl = "https://ncode.syosetu.com/"+slist[s];
    response = UrlFetchApp.fetch(getUrl).getContentText('UTF-8');
    var honbun_ = response.match(/<p class="novel_subtitle">(?:.|\s)+?<div id="novel_honbun"(?:.|\s)+?<\/p>\n<\/div>/)[0];
    var sphon=honbun_.split(/[\r\n]+/g);
    for (var i = 0, len=sphon.length;i<len;i++){
        if (sphon[i].slice(0,2) == "<p"){
          var groups = sphon[i].match(/(<p.*?>)(.+?)(<\/p>)/);
          var temp = groups[1] + groups[2].replace(/(\d{2,4})/g, '<span class="text-combine">$1<\/span>') + groups[3];
          if(i == 0){
            temp = '<h3>' + temp + '</h3>';
            Logger.log(temp);
          }
          honbun += temp + "\n"
        }
        else{honbun += sphon[i] + "\n";}
     }
    honbun += "</br></br>";
  }
  honbun = '<html>\n<head>\n <title>' + title + '</title>\n</head>\n<font size="5"><style>\n    body {\n        -ms-writing-mode: tb-rl;\n        writing-mode: vertical-rl;\n        text-orientation: upright;\n       font-family: "Yu Mincho", YuMincho, "Hiragino Mincho ProN W3", "Hiragino Mincho ProN W3", "Hiragino Mincho ProN", "HG Mincho E", "MS P Mincho", "MS demain matin", serif;\n   }\n\n    .text-combine {\n        -webkit-text-combine: horizontal;\n        -ms-text-combine-horizontal: all;\n        text-combine-upright: all;\n    }\n</style>\n\n<body>\n' + honbun + ' \n</body>\n</font>\n</html>'
  var html = HtmlService.createHtmlOutput(honbun);  //Je ne suis pas sûr. Un gars préparatoire pour afficher du HTML dans l'état d'une chaîne de caractères en HTML?
  return html;
}

Publié → Introduit en tant qu'application Web Et l'adresse générée + ? Keyword = mot de recherche & num = nombre d'histoires En accédant, la page formatée verticalement sera affichée. (LINE Bot répondra à cette adresse dans le premier projet.) image.png

Résumé

La lecture progresse ... Le HTML est un amateur, donc si vous ne l'aimez pas, modifiez-le ... …… Lorsque vous l'utilisez, veuillez l'utiliser avec modération afin de ne pas mettre un lourd fardeau sur le serveur pour devenir romancier.

Recommended Posts

[Python / GAS] Une histoire sur la création d'une API Web personnelle qui vous permet de tout savoir sur comment devenir un romancier en écriture verticale, puis en faire un bot LINE.
[Google Photo & Slack Photo Bot] Une histoire sur la création d'un bot qui acquiert une photo dans Google Photo et l'envoie à Slack.
Une histoire sur tout, de la collecte de données au développement d'IA et à la publication d'applications Web en Python (3. développement d'IA)
Créez un plugin qui vous permet de rechercher les onglets Sublime Text 3 en Python
[Python] Une histoire sur la création d'un bot LINE avec une fonction humaine pratique sans utiliser Salesforce [API de messagerie]
Script Python qui explore le flux RSS du statut Azure et le publie sur Hipchat
[Python] À propos de la création d'un outil pour afficher toutes les pages du site Web enregistrées dans le fichier JSON et où il a été pris
Commande de raccourci Jedi-vim qui vous permet de faire référence à la source de la définition et à la destination de la définition en Python
Feuille de route d'apprentissage qui vous permet de développer et de publier des services à partir de zéro avec Python
Une histoire qui facilite l'estimation de la surface habitable à l'aide d'Elasticsearch et de Python