なろう分析記録

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

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

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

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

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

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

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

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スクリプト
#2020-04-26更新
import requests
import pandas as pd
import json
import time as tm
import datetime
import gzip
from tqdm import tqdm
tqdm.pandas()
import xlsxwriter
import sqlite3

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

### なろう小説API・なろう18禁小説API を設定 ####
is_narou = True

now_day = datetime.datetime.now()
now_day = now_day.strftime("%Y_%m_%d")

if is_narou:
    filename = 'Narou_All_OUTPUT_%s.xlsx'%now_day
    sql_filename = 'Narou_All_OUTPUT_%s.sqlite3'%now_day
    api_url="https://api.syosetu.com/novelapi/api/"    
else:
    filename ='Narou_18_ALL_OUTPUT_%s.xlsx'%now_day
    sql_filename = 'Narou_18_ALL_OUTPUT_%s.sqlite3'%now_day
    api_url="https://api.syosetu.com/novel18api/api/"

# データをSqlite3形式でも保存する
is_save_sqlite = False

##### 以上設定、以下関数 ##############
    
#全作品情報の取得
def get_all_novel_info():
       
    df = pd.DataFrame()
    
    payload = {'out': 'json','gzip':5,'of':'n','lim':1}
    res = requests.get(api_url, params=payload).content
    r =  gzip.decompress(res).decode("utf-8") 
    allcount = json.loads(r)[0]["allcount"]

    print('対象作品数  ',allcount);
    
    all_queue_cnt = (allcount // 500) + 10
    
    #現在時刻を取得
    nowtime = datetime.datetime.now().timestamp()
    lastup = int(nowtime)
                     
    for i in tqdm(range(all_queue_cnt)):
        payload = {'out': 'json','gzip':5,'opt':'weekly','lim':500,'lastup':"1073779200-"+str(lastup)}
        
        # なろうAPIにリクエスト
        cnt=0
        while cnt < 5:
            try:
                res = requests.get(api_url, params=payload, timeout=30).content
                break
            except:
                print("Connection Error")
                cnt = cnt + 1
                tm.sleep(120) #接続エラーの場合、120秒後に再リクエストする
            
        r =  gzip.decompress(res).decode("utf-8")   
    
        # pandasのデータフレームに追加する処理
        df_temp = pd.read_json(r)
        df_temp = df_temp.drop(0)

        df = pd.concat([df, df_temp])
        
        last_general_lastup = df.iloc[-1]["general_lastup"]

        lastup = datetime.datetime.strptime(last_general_lastup, "%Y-%m-%d %H:%M:%S").timestamp()
        lastup = int(lastup)

        #取得間隔を空ける
        tm.sleep(interval)
        
    dump_to_excel(df)

#エクセルファイルに書き込む処理
def dump_to_excel(df):

    # allcount列を削除
    df = df.drop("allcount", axis=1)

    # 重複行を削除する
    df.drop_duplicates(subset='ncode', inplace=True)
    df = df.reset_index(drop=True)
    
    print("export_start",datetime.datetime.now())    

    try:
        # .xlsx ファイル出力
        writer = pd.ExcelWriter(filename,options={'strings_to_urls': False}, engine='xlsxwriter')
        df.to_excel(writer, sheet_name="Sheet1")#Writerを通して書き込み
        writer.close()
        
        print('取得成功数  ',len(df));
        
    except:
        pass
    
    ### SQLite3に書き込む処理 (将来エクセルの上限行数を超えたときのため) ###
    if is_save_sqlite == True or len(df) >= 1048576:
        
        # 接続DBファイルの指定
        conn = sqlite3.connect(sql_filename)
        conn.row_factory = sqlite3.Row 
        c = conn.cursor()
        
        df.to_sql('novel_data', conn, if_exists='replace')
        
        c.close()
        conn.close()
        
        print("Sqlite3形式でデータを保存しました")
    

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

get_all_novel_info()

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

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