なろう分析記録

『小説家になろう』をふくめ『ネット小説投稿サイト』を分析する。コード置き場,主にPython,javascript,たまに創作。

Pythonで行う「なろう小説API」の分析 コード例、環境準備、トラブルシューティング

なろう小説APIを使って『小説家になろう』を分析する

小説家になろうでは作品情報を扱うことができるAPIが提供されているため、それを利用することでさまざまなデータを簡単に得ることが出来ます。
ここでは、Pythonを使ってそれらを落としてくる方法を解説します。


手っ取り早くコピペコードでなろうデータを全取得したい人はこちら
『なろう小説API』を用いて、なろうの『全作品情報データを一括取得する』Pythonスクリプト※コード改良しました - なろう分析記録

Pythonを使う環境の準備

windowsユーザ向け
Anacondaの「jupyter notebook」を使うのが簡単。普通に日本語で使えます。

qiita.com
www.anaconda.com




インストーラの説明に従ってインストールすれば完了。
必要なパッケージは全部入っている。


より快適に使う設定は下記の記事をご参照ください。

karupoimou.hatenablog.com

コード編

最もシンプルなコード

import requests
import yaml

payload = {'out': 'yaml'}
r = requests.get('https://api.syosetu.com/novelapi/api/', params=payload).text

print(r)

ポイント上限とポイント下限を指定

import requests
import yaml

payload = {'out': 'yaml','min_globalpoint':38,'max_globalpoint':50}
r = requests.get('https://api.syosetu.com/novelapi/api/', params=payload).text

print(r)

表示件数を500に

import requests
import yaml

payload = {'out': 'yaml','lim:500}
r = requests.get('https://api.syosetu.com/novelapi/api/', params=payload).text

print(r)

ジャンル別の総作品数を表示

import requests
import yaml
import time

genre_set = ['101','102','201','202','301','302','303','304','305','306','307','401','402','403','404','9901','9802','9903','9904','9999','9801']

for genre in genre_set: 
    payload = {'out': 'yaml','st':1,'lim':1,'of':'g','genre':genre}
    r = requests.get('https://api.syosetu.com/novelapi/api/', params=payload).text
    with open("output_genre_num001.yaml","a") as file:
             yaml.dump(r, file, default_flow_style=False,allow_unicode=True)
    time.sleep(1)
    print(r)
print("end")

ここではfor文で繰り返し実行することで可能に。 output_genre_num001.yamlに順に書き込んでいく。

短編・連載の作品数 を出すだけのコード

import requests
import yaml
import time

shousetu_type_set =['t','re']

for shousetu_type in shousetu_type_set:
    payload = {'out': 'yaml','st':1,'lim':1,'of':'n','type':shousetu_type}
    r = requests.get('https://api.syosetu.com/novelapi/api/', params=payload).text
    time.sleep(1)
    print(r)
print("end")

typeによって区別。

YAMLロードする用のコード

import yaml

f = open("output_genre_num001.yaml", "r+")
data = yaml.safe_load(f)

print(data)
print("end")

output_genre_num001.yamlを読み出して表示。
なお「yaml.load()」を使うとエラーがでるので、「safe_load()」にしている。

特定作者の作品一覧を表示

#作者分析 高ポイント順ソートしてテキスト出力するPythonスクリプト
import requests
import yaml
import time
import webbrowser
import datetime

now = datetime.datetime.now()

#出力ファイル名の指定。接頭語+日時
t = 'mine_{0:%Y%m%d}.txt'.format(now) #test_20170910

#時刻の書き込み
dt_now = datetime.datetime.now()
nowtime = dt_now.strftime('%Y-%m-%d %H:%M:%S')
with open(t,mode='w',encoding='utf-8') as f:
    f.write(nowtime)

#ここに作者ユーザーIDをコピペ
userid = ['511777']

#新着更新順にする場合は 'new'  新着投稿順にする場合は 'ncodedesc'
order_set = ['hyoka']

#なろう小説APIへリクエスト
payload_simple = {'out': 'yaml','lim':500,'order':order_set,'userid':userid,'of':'n-t-gp-f-ah-a'}
r1 = requests.get('https://api.syosetu.com/novelapi/api/', params=payload_simple).text

time.sleep(0.1)

payload_all = {'out': 'yaml','lim':500,'order':order_set,'userid':userid,'of':'t-n-s-g-k-gf-gl-ga-l-gp-f-r-a-ah'}
r2 = requests.get('https://api.syosetu.com/novelapi/api/', params=payload_all).text

#書き込みテキストファイルの指定
with open(t,mode='a',encoding='utf-8') as f:
    f.write(r1)
    f.write(r2)
    
#完了時にファイルを自動で開く設定(必要なければ消して良い)
webbrowser.open(t)

print("end")
# 詳しくは なろうデベロッパー
# https://dev.syosetu.com/man/api/ をご参照あれ

作者IDは作者マイページに行けば分かる。
例:
https://mypage.syosetu.com/511777/

エクセル読み出し

import requests
import yaml
import time
import xlrd
import pprint

#読み込みファイル指定
wb = xlrd.open_workbook('word.xlsx')

#シート指定 列指定
sheets = wb.sheets()
sheet = wb.sheet_by_name('sheet1')
word_set = sheet.col_values(0)

# ポイント数
max_globalpoint_set = ['1','101','1001','1000000000000']

for word in word_set: 
      for max_globalpoint in max_globalpoint_set:
            
            payload = {'out': 'yaml','st':1,'lim':1,'of':'n','max_globalpoint':max_globalpoint,'word':word,'title':0,'ex':0,'keyword':1}
            r = requests.get('https://api.syosetu.com/novelapi/api/', params=payload).text
            with open("output_genre_num001.yaml","a") as file:
                     yaml.dump(r, file, default_flow_style=False,allow_unicode=True)
            print(word)
            print(r)
            time.sleep(0.05)
    
print("end")

word.xlsxのsheet1の一列目にある文字を使って、全部解析して、output_genre_num001.yamlに書き込み。
説明が面倒なので実際試してみて下さい。

部品別の説明

結果をテキストファイルに書き込み

import requests
import yaml

payload = {'out': 'yaml'}
r = requests.get('https://api.syosetu.com/novelapi/api/', params=payload).text

print(r)

with open('test001.txt',mode='w',encoding='utf-8') as f:
  f.write(r)

なおmodeを指定することで、追記か、新規作成か選べる。詳細は下に

テキストの「追記」と「完全上書き」

with open('test001.txt',mode='w',encoding='utf-8') as f:

のばあいの「mode='w'」というところで指定している。

w = 上書き もしファイルが無ければ生成。ファイルの初期化にも使う。
a = 追記用

テキストファイルに時間を書き込む

import datetime

dt_now = datetime.datetime.now()
t = dt_now.strftime('%Y-%m-%d %H:%M:%S')

with open('test001.txt',mode='w',encoding='utf-8') as f:
f.write(t)
print(t)

リクエストを始めた時間とか終えた時間のメモに使うとよい。 

ファイル名に日時を使う

##時刻を文字に置き換える
import datetime
now = datetime.datetime.now()
t = 'mine_{0:%Y%m%d}.txt'.format(now) #test_20170910

#書き込みテキストファイルの指定
with open(t,mode='w',encoding='utf-8') as f:
f.write("test")

print(t)

完了の表示

print("end")

これをコードの末尾に加えておくとよい。

完了時にファイルを自動で開く設定

import requests
import yaml
import time
import webbrowser

payload_simple = {'out': 'yaml'}
r = requests.get('https://api.syosetu.com/rank/rankget/', params=payload_simple).text

#書き込みテキストファイルの指定
with open('00003.txt',mode='w',encoding='utf-8') as f:
    f.write(r)
    print(r)
    
#完了時にファイルを自動で開く設定
webbrowser.open('00003.txt')

webbrowserを使って表示を実現。

辞書型データからのデータの取り出し

import requests
import yaml

payload = {'out': 'yaml'}
r = requests.get('https://api.syosetu.com/novelapi/api/', params=payload).text

for data in yaml.safe_load(r):
    try:
        title = data['title']
        print(title)
    except KeyError:
        pass

for文を使って、辞書型データから情報を取り出している。
これを使うことによって、CSVとかに書き込める。

ジャンル別の作品数を出すコード

#ジャンルごとの作品数を表示
import requests
import yaml
import gzip

genre_set = ['101','102','201','202','301','302','303','304','305','306','307','401','402','403','404','9901','9902','9903','9904','9801','9999']

def dump_to_list(r):
    for data in json.loads(r):
        try:            
            print(data['allcount'])
        except KeyError:
            pass

for gen in genre_set:
    payload = {'out': 'json','gzip':5,'of':'n','lim':1,'genre':gen}
    res = requests.get('https://api.syosetu.com/novelapi/api/', params=payload).content
    r =  gzip.decompress(res).decode("utf-8")
   
    print(gen,"    ", end="")
    dump_to_list(r);
    
print("end")

sys関数

pythonの実行環境を表示する
import sys

print(sys.version)
#>>3.6.8 |Anaconda custom (64-bit)| (default, Feb 21 2019, 18:30:04) [MSC v.1916 64 bit (AMD64)]

このコードはpythonレンタルサーバーなどで実行する際などに便利です。

import sys

print(sys.path)

#>>['C:\\ProgramData\\Anaconda3\\python36.zip', 'C:\\ProgramData\\Anaconda3\\DLLs', 'C:\\ProgramData\\Anaconda3\\lib', 'C:\\ProgramData\\Anaconda3', '', 'C:\\ProgramData\\Anaconda3\\lib\\site-packages', 'C:\\ProgramData\\Anaconda3\\lib\\site-packages\\win32', 'C:\\ProgramData\\Anaconda3\\lib\\site-packages\\win32\\lib', 'C:\\ProgramData\\Anaconda3\\lib\\site-packages\\Pythonwin', 'C:\\ProgramData\\Anaconda3\\lib\\site-packages\\IPython\\extensions', 'C:\\Users\\ユーザー名\\.ipython']

このコードも、どの様にpythonのパスが通っているのか調べるために便利です。

ディレクトリ内に存在するファイル名をリストオブジェクトとして取得

import glob

filename=glob.glob("./*")
print(filename)
#>>['.\\jinja2_test.html', '.\\jinja2_test.ipynb', '.\\jinja2_test.py', '.\\jinja2_test.txt']

トラブルシューティング

jupyter notebookが立ち上がらない

コンソール画面を右クリックして「全選択」→「コピー」をしてから、それをwordとかに入りつけれから、URLをクリックすればよい。

コンソールが閉じてしまうのは、ctlr+Cボタンを押しているから。それすると落ちる。

Anacondaがアップデート出来ない

Anaconda Prompt を「管理者権限」で実行する。右クリックすると選べる。

Anaconda Prompt はwindowsメニューの中にある。

全データを一括取得するコード

とりあえず全件取得してから、手元にデータを置いた状態で分析をしたい。という方は以下のコードをご利用下さい。
半日ほどで約200MBの全件データが手に入ります。特に設定の必要はありませんのでポチポチで実行できます。

github.com


参考資料リンク

「なろう小説API」からの情報取得と分析: 楽ちんR編 作者:sleepy moon

https://ncode.syosetu.com/n2140fg/1/