【Python】News APIで検索条件を指定してニュースを取得→CSVに保存

この記事が解決するお悩み
  • News APIでロイターのニュース(他のニュースソースでもOK)を取得したい
  • News APIで検索キーワードを入れたい
  • News APIで検索期間を指定したい

本記事では、News APIを用いて、条件を指定してニュースを取得する方法について徹底解説していきます。News APIを使えばPythonで簡単に世界中のニュースを収集できます。今回は特に、検索キーワードニュースソース期間を指定して、それらに合致する全ニュースを取ってくるPythonコードを紹介します。

はじめに

News APIとは

今回使用するNews APIとは、数多くのニュースサイトからヘッドラインニュースや条件を指定して合致したニュースをJSON形式で返してくれるAPIです。ロイターニュースやBBCニュースをはじめ75,000以上のソースに対応しています。

ためしに、「検索キーワード:Tesla」・「期間:1ヶ月前から今日まで」に合致するニュースを取得してみます。

{
"status": "ok",
"totalResults": 10967,
-"articles": [
  -{
   -"source": {
     "id": "the-irish-times",
     "name": "The Irish Times"
    },
    "author": "The Irish Times",
    "title": "Bitcoin steadies as Elon Musk clarifies comments",
    "description": "Bitcoin steadied after Elon Musk said Tesla hasn’t sold from its holdings of the token, clarifying earlier comments that seemed to imply the electric vehicle maker may sell or has sold its stake. \nThe largest digital currency was at $44,900 as of 7.21am in Lo…",
    "url": "https://www.irishtimes.com/business/technology/bitcoin-steadies-as-elon-musk-clarifies-comments-1.4567260",
    "urlToImage": "https://www.irishtimes.com/image-creator/?id=1.4567259&origw=1440",
    "publishedAt": "2021-05-17T09:49:25Z",
    "content": "Bitcoin steadied after Elon Musk said Tesla hasnt sold from its holdings of the token, clarifying earlier comments that seemed to imply the electric vehicle maker may sell or has sold its stake.\r\nThe… [+2453 chars]"
  },
  -{
   -"source": {
     "id": null,
     "name": "Forbes"
     ・・・・・・

このようにJSON形式で返してくれます。今回のケースでは、検索ヒット数(totalResults)は10967件でした。記事については以下の情報が取得できます。

  • ニュースソース(source
  • 著者(author
  • ニュースタイトル(title
  • ニュース概要(description
  • URL(url
  • イメージURL(urlToImage
  • ニュース発行時刻(publishedAt
  • 内容一部(一部)(content

無料会員でできること

News APIでは、月額会員別にやれることがどんどん解放されていきますが、無料会員でも十分です。以下、主に無料会員で制限されていることです。

  • 新規ニュースは1時間遅れ
  • 期間指定は最長1ヶ月前まで
  • 1日に100リクエストまで
  • 1つの検索条件につき100件(20件×5ページ)の情報まで

今回は、この1ヶ月前までの期間指定と、100リクエスト/日までを最大限に使って、よりたくさんのニュースを取得していくコードを書いていきましょう。

STEP1. News APIへの登録

News APIのページから「Get API Key」を選択してメールアドレスなどの情報を入れれば簡単に登録・API Keyの発行ができます。API Keyの発行が済んだら、Keyを控えておきましょう。

https://newsapi.org/

STEP2. Pythonでニュース取得

ポイントは、以下の通りです。

  • 無料会員のほぼほぼ限界の4週間分のデータを取り切る
  • 検索ヒット数が100件を超えないよう、期間指定は1日分とする

今回は、以下の検索条件を例にコード紹介していきます。

  • ニュースソース:ロイター
  • 検索キーワード:みずほ証券(Mizuho)
  • 期間指定:4週間前から昨日まで

早速コードです。22行目(ハイライト箇所)のapi_keyをSTEP1. で発行した自分のAPI Keyに置き換えて使用ください。

import datetime
import pandas as pd
from newsapi import NewsApiClient
from pandas import json_normalize
import os

#検索キーワード指定
key_word = 'Mizuho'
os.makedirs(key_word, exist_ok=True)

#ニュースソースを指定
news_source = 'reuters'

#4週間分の日付リスト作成
daylist = []
for k in range(28):
    day = datetime.date.today() + datetime.timedelta(days=-29+k)
    daylist.append(day)


# newsapiクライアントを初期化
newsapi = NewsApiClient(api_key='自分のAPI Key') #自分のAPI Key


# 条件指定したニュースを取得
#query: 検索キーワード
#sources:news_sources(ex. 'reuters')
#dayfrom: 指定日時(from)
#dayto:指定日時(to)
#page = pg
def news_json(query, news_sources, dayfrom, dayto, pg):
    
    news_res = newsapi.get_everything(
                                        q = query,
                                        sources = news_sources,
                                        from_param = dayfrom,
                                        to = dayto,
                                        page = pg)
    return news_res


#jsonから必要な情報のみピックアップ
def json2def(json):
    df = json_normalize(json['articles'])
    return df


def main():
    #1リクエストにつき100件(20件×5ページ)までしかニュースを読み込めないため、1日ごとにニュースを取得する
    for day in daylist:
        #検索ヒット数などの基本情報確認
        res_temp = news_json(key_word, news_source, day, day, 1)
        
        #検索ヒット数が存在するかつ100件以内であれば以下を実行
        if( res_temp['totalResults'] > 0 and res_temp['totalResults']<=100):

            #1ページあたり20件なので検索ヒット数から最終ページを計算する
            page_total = -(-res_temp['totalResults'] //20) #切り上げを表現
            
            #1ページ目の処理
            df = json2def(res_temp)
            if (page_total>1):
                #2ページ目以降を取得
                for pg in range(page_total-1):
                    res = news_json(key_word, news_source, day, day, pg+2)
                    df_pg = json2def(res)
                    df = pd.concat([df, df_pg], axis = 0)
                    
            #1ページのみであれば2ページ目以降処理不要のためスキップ
            else:
                pass
            
            #csvに出力
            csvname = key_word + '/' +day.strftime('%Y-%m-%d') + '.csv'
            df.to_csv(csvname)

        
        #検索ヒット数が100件以上だと6ページ目以降を取得できないので、そのメッセージを出力する
        elif (res_temp['totalResults']>100):
            print(day.strftime('%Y-%m-%d') + ': over 100 news exists')
            
        #検索がヒットしないとそもそも取得できないので、そのメッセージを出力する
        else:
            print(day.strftime('%Y-%m-%d') + ': No news exists')

    return

if __name__ == "__main__":
    main()

このコードを一旦回すと出力メッセージは以下のようになります。
今回は、1日ごとにニュースを取得しているので、検索してもヒットしない日もありえます。その際は以下のようにニュースがない旨を出力するようにしています。

また、1日の検索ヒット数が100件(20件×5ページ)を超えてしまっても、6ページ目以降のデータが取得できないので、エラーメッセージを出力するようにしてあります。

今度は出力されたファイルを見てみましょう。新しく「Mizuho」(検索キーワード)というフォルダが作成されて中身は、このようにCSVファイルが日付ごとに並んでいます。


CSVの中身を確認してみても下記画面のように検索でヒットしたニュースが並んでいるのでうまくいっているようです。

STEP.3 CSVデータを一元化(おまけ)

STEP.2まででOKですが、もう少しCSVファイルが整理していきましょう。日付ごとに並んだ複数のCSVファイルを1つのCSVで一元管理するコードを紹介します。

import pandas as pd
import os
from os import listdir

key_word = 'Mizuho' #指定キーワード
main_path='メインパス' #pythonの実装パス
path_csv = main_path + '/' + key_word #csvを格納したフォルダパス

#csvフォルダにある全csvファイルをリストで取得
files_csv = [csvname for csvname in listdir(path_csv) if not csvname.startswith('.')]

#csvフォルダに移動
os.chdir(path_csv)

dflist = []
#1つずつcsvを読み込んでappendでくっつける
for file in files_csv:
    dftemp = pd.read_csv(file)
    dflist.append(dftemp)

#データフレームとして格納して、日付順に並び替え
df = pd.concat(dflist, axis = 0)
df = df.drop(columns = ['Unnamed: 0'])
df['publishedAt'] = pd.to_datetime(df['publishedAt'])
df_sort = df.sort_values(['publishedAt'])

#メインフォルダに移動
os.chdir(main_path)
csvname = key_word + '.csv'
df_sort.to_csv(csvname, index = False)

実装結果によって得られたCSVがこちらになります。これでCSVファイルの一元化は完了です。

2 COMMENTS

沼本裕太

とても貴重な情報ありがとうございます。ロイターではなく日経新聞でもできるのでしょうか?

返信する

コメントを残す

メールアドレスが公開されることはありません。