なろう分析記録

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

『なろう小説API』を用いて、なろうの『全作品情報データを一括取得する』Pythonスクリプト※コード改良しました

pythonを使ってなろうの全ての情報を取得する

なろうが提供する「なろう小説API」を用いて、なろうに存在するすべての小説情報データを全件取得するコードです。
とりあず手元にデータを持った上で解析を行いたい人向けの全部をすべて取得するコードです。

f:id:karupoimou:20190430224419p:plain:w400
全件取得例

なろう小説APIで取得できる全作品情報データの全34項目を一括取得できます。(2019年5月現在約64万件分)

取得データについては、「なろうディベロッパー」サイトを御覧ください。

https://dev.syosetu.com/man/api/:なろう小説API(なろうディベロッパー)

このスクリプトを使うことで「ポチポチ」で全件取得が可能となります。

Githubのページ

github.com



f:id:karupoimou:20190430214817p:plain:w400
Githubで.pyをDLする方法

使用準備

以下のパッケージを使用していますのでインストールしていない場合はインストールしてご利用ください。

pip install pandas
pip install tqdm
pip install requests

追加:2019/9/29

pip install xlsxwriter

使用方法の説明

pythonを使って、なろうAPIからすべての小説情報データを引っ張ってきて、一つの.xlsx(エクセル形式)ファイルで出力するスクリプトです。
約半日動かせば、なろうのすべてが取得できます。コードの改良で約90分で全取得できるようなりました。

使用方法

Anacondaのjupyter notebookやPython3.5で.pyを実行してください。
実行ファイルと同じフォルダに

#出力ファイル名
filename ='All_OUTPUT.xlsx'

で指定したエクセルファイルが出力されます。約200MB

取得項目

なろう小説APIで取得できる全40項目を取得します。

title
ncode
userid
writer
story
biggenre
genre
gensaku
keyword
general_firstup
general_lastup
novel_type
end
general_all_no
length
time
isstop
isr15
isbl
isgl
iszankoku
istensei
istenni
pc_or_k
global_point
daily_point
weekly_point
monthly_point
quarter_point
yearly_point
fav_novel_cnt
impression_cnt
review_cnt
all_point
all_hyoka_cnt
sasie_cnt
kaiwaritu
novelupdated_at
updated_at
weekly_unique
※2019.8.20より追加
daily_point
weekly_point
monthly_point
quarter_point
yearly_point
impression_cnt

トラブルシューティング

「pandas」が見つからないというエラーが出る。

pip install pandas

このスクリプトでは「pandasパッケージ」を使っています。なのでpipからpandasをインストールしてください。
anacondaの場合は、スタートメニューのなかにあるanaconda promptで実行し、jupyter notebookを再起動してください。

取れないデータがある。数が合わない

なぜか落とせないデータはあるみたいです。
落とせないデータについてはpassする様に設定しています。

エクセルで開くとエラーが出る

何件かのデータがバッグっているのでデータを初めて読み込んだ時は「修復しますか?」とダイアログが出るので「修復する」を選択して下さい。

エクセルで開けないほど重い

エクセルで扱えないというほど大きいファイルサイズではないですが、ゴリゴリ解析していくのには時間がかかります。
ピポットデーブルで作業する場合は、作業用に必要な列だけ抜き出したシートを用意して行ったほうが効率的です。
本格的な解析はpythonみたいなソフトで行った方が効率的なのは確かです。

全件取得スクリプト

#『なろう小説API』を用いて、なろうの『全作品情報データを一括取得する』Pythonスクリプト
#2019-09-27更新
import requests
import pandas as pd
import json
import time as tm
import datetime
import gzip
import re
from tqdm import tqdm
import xlsxwriter

#出力ファイル名
filename ='Narou_All_OUTPUT_09_27.xlsx'

#リクエストの秒数間隔(1以上を推奨)
interval=1

#取得するGETパラメータの「lastup」リスト
temp_lastup_list=[]   

#レスポンスの一時リスト
res_list=[]

#各情報を一時的に保存していくための配列の準備
temp_data_list=[]   
    
#取得パラメータを指定
column_name_list = ['title',
                   'ncode',
                   'userid',
                   'writer',
                   'story',
                   'biggenre',
                   'genre',
                   'gensaku',
                   'keyword',
                   'general_firstup',
                   'general_lastup',
                   'novel_type',
                   'end',
                   'general_all_no',
                   'length','time',
                   'isstop',
                   'isr15',
                   'isbl',
                   'isgl',
                   'iszankoku',
                   'istensei',
                   'istenni',
                   'pc_or_k',
                   'global_point',
                   'daily_point',
                   'weekly_point',
                   'monthly_point',
                   'quarter_point',
                   'yearly_point',               
                   'fav_novel_cnt',
                   'impression_cnt',
                   'review_cnt',
                   'all_point',
                   'all_hyoka_cnt',
                   'sasie_cnt',
                   'kaiwaritu',
                   'novelupdated_at',
                   'updated_at',
                   'weekly_unique']

##### 以上設定、以下関数 ##############
    
#最初に処理される関数 全体の数をメモ
def start_process():
    payload = {'out': 'json','of':'n','lim':1}
    allnum = requests.get('https://api.syosetu.com/novelapi/api/', params=payload).text
    print('対象作品数  ',allnum);

#GETパラメータで取得する「lastup」リストを生成する
def generate_lastup_list():
    
    #現在日時の取得
    now = datetime.datetime.today()
    now_time=int(now.timestamp())
    
    #終点
    dd=datetime.datetime(2004, 1, 1, 1, 1, 1, 1)
    start_day=dd.timestamp()

    #作業経過一時保存用の変数
    unix_time = int(now.timestamp())
   
    #Unixtimeを使った期間指定で作品情報を取得する
    for i in range(100000):

        if start_day < unix_time:

            # 1日以内の投稿
            if now_time-86400 <  unix_time:
                next_time=int(unix_time-3000)

            # 約4日以内の投稿
            elif now_time-330000 <  unix_time <= now_time-86400:
                next_time=int(unix_time-8000)

            # 約十日以内の投稿
            elif now_time-1000000 <  unix_time <= now_time-250000:
                next_time=int(unix_time-12000)

            #約百日以内の投稿
            elif now_time-10000000 <  unix_time <= now_time-1000000:
                next_time=int(unix_time-25000)

            #だいぶ以前の投稿(エポック秒で直接指定していしてます)
            elif 1545000000 <  unix_time <= now_time-10000000:
                next_time=int(unix_time-40000)

            elif 1500000000 <  unix_time <= 1545000000:
                next_time=int(unix_time-80000)

            elif 1405865000 <  unix_time <= 1500000000:
                next_time=int(unix_time-100000)

            elif 1256665000 <  unix_time <= 1405865000:
                next_time=int(unix_time-200000)

            elif unix_time < 1256665000:
                next_time=int(unix_time-1000000)

            #リストに追加する
            lastup="%s-%s"%(next_time,unix_time)
            temp_lastup_list.append(lastup)
           
            #作業完了で次の取得期間を設定する
            unix_time=next_time

#全作品情報の取得
def get_all_novel_info():
         
    #リストを逆順にし、過去から現在に向かって取得していく        
    temp_lastup_list.reverse()
    
    #APIへリクエスト
    for lastup in tqdm(temp_lastup_list):
        payload = {'out': 'json','gzip':5,'opt':'weekly','lim':500,'lastup':lastup} 
        res = requests.get('https://api.syosetu.com/novelapi/api/', params=payload, timeout=30).content
        r =  gzip.decompress(res).decode("utf-8")
        
        #レスポンスを一旦リストに収納する
        res_list.append(r)
        
        #取得間隔を空ける
        tm.sleep(interval)
             
#書き込み処理の関数
def dump_to_list():
    
    global temp_data_list
        
    for i in range(len(column_name_list)):
        temp_data_list.append([])
    
    #レスポンスリストを展開
    for r in res_list:
    
        # temp_data_listに入れる
        for data in json.loads(r):
            try:
                for i in range(len(column_name_list)):               
                    temp_data_list[i].append(data[column_name_list[i]])
            except KeyError:
                pass
        
        #取れていない小説が無いか確認
        for data in json.loads(r):
            try:
                 if 500 <= data["allcount"]:
                    print("取得できなかった作品が存在します。generate_lastup_listの取得間隔を変更してください")
            except KeyError:
                pass
                               
#エクセルファイルに書き込む処理
def dump_to_excel():
    
    print("export process")
        
    exportlist=[]
    
    #各項目のリストを1つにまとめる
    for i in range(len(column_name_list)):
        exportlist.append(temp_data_list[i])
    
    #pandasのデータフレームに収納 
    df = pd.DataFrame(exportlist, index=column_name_list)   
    df= df.T
    
    # .xlsx ファイル出力
    writer = pd.ExcelWriter(filename,options={'strings_to_urls': False}, engine='xlsxwriter')
    df.to_excel(writer, sheet_name="Sheet1")#Writerを通して書き込み
    writer.close() 

####### 関数の実行を指定 ##########
print("start",datetime.datetime.now())

start_process()

generate_lastup_list()
get_all_novel_info()
dump_to_list()
dump_to_excel()

print("end",datetime.datetime.now())
備考

小説家になろう」は株式会社ヒナプロジェクトの登録商標です。
このスクリプトは非公式のものです。

追記:「なろう18禁小説API」全取得コードもアップしました!

karupoimou.hatenablog.com
なろう18禁小説APIむけのコードも作成しましたのでもしご興味ありましたらご覧ください。

資料


karupoimou.hatenablog.com

Anacondaやpythonの基本は上記の記事をご参照ください。


karupoimou.hatenablog.com

Jupyter Notebookの設定は上記の記事をご参照ください。


karupoimou.hatenablog.com

python3.7の環境を使う際にはご参照ください。


karupoimou.hatenablog.com

また定期的に自動実行するときなどには上記の記事をご参照ください。