Python と News API を使ってニュース記事を収集する
はじめに
ニュース記事を閲覧できるウェブサイトは各種ありますが、データ解析などの目的である程度まとまった量のニュース記事を機械的に収集したい場合には有料サービスを利用する必要があり、誰でも簡単にできるわけではありません。
この記事では、簡単な Python のプログラムと、開発目的ならば無償で利用できる NEWS API を使って、ニュース記事を収集する方法を紹介します。なお、読者は Python, JSON, HTTP に関する基本事項を理解していることを想定しています。
News API とは
NEWS API は、世界中のニュースソースから現在および過去のニュース記事を単純な REST API で取得できるサービスです。多少の制約はありますが、日本の大手新聞社やニュースサイトの日本語記事も取得できます。
NEWS API は基本的に有料サービスですが、開発目的の場合は制限付きながら無償で利用できます。主な制限は以下の通りです(2022年2月現在)。
- 新着記事は 1 時間遅れ
- 検索可能な記事は過去 1 か月以内
- 1 回のリクエストで取得可能な記事数は 100 件まで
- 1 日に実行可能なリクエスト数は 100 回まで
認証
NEWS API を使用するためには、毎回のリクエストで API key を提示する必要があります。API key を取得するためには、以下のページからユーザ登録をします(クレジットカードは不要)。
入力が必要な情報は以下の通りです。
- First name: 自分の名前
- Email address: 有効なメールアドレス
- Choose a password: 任意のパスワード
- You are...: 個人かビジネスかを選択
- 私はロボットではありません: チェック
- I agree to the terms: 規約を確認
登録が完了するとメールアドレスに API key(32文字のハッシュ値)が送られてきます。
API 仕様
NEWS API では、トピックやキーワードなどを指定して過去のニュース記事を検索する Everything と、国やカテゴリーなどを指定して現在のトップニュースを取得する Top headlines の二つのエンドポイントが提供されています。各エンドポイントの入出力を以下の表に要約します。なお、詳細は公式ドキュメント[1] を参照してください。
Everything エンドポイント(/v2/everything)
入力(リクエストパラメータ)
パラメータ | 機能 | デフォルト値 | 備考 |
---|---|---|---|
apiKey | API key | 必須 | HTTP ヘッダで指定可 |
q | 検索キーワード | - | 論理条件を指定可 |
searchIn | 検索対象フィールド | 全てのフィールド | 複数指定可 |
sources | ニュースソースID | - | 複数指定可 |
domains | 検索対象ドメイン | - | 複数指定可 |
excludeDomains | 除外するドメイン | - | 複数指定可 |
from | 検索対象範囲 | 最も古い日時 | ISO 8601 形式 |
to | 検索対象範囲 | 最も新しい日時 | ISO 8601 形式 |
language | 言語 | 全ての言語 | 日本語指定不可 |
sortBy | 出力順序 | publishedAt | 他に relevancy, popularity |
pageSize | 最大記事数/ページ | 20 | 最大 100 |
page | ページ番号 | 1 |
出力(レスポンスオブジェクト)
フィールド | 内容 | データ型 | 備考 |
---|---|---|---|
status | リクエスト結果 | string | ok または ステータスコード |
totalResults | ヒットした総記事数 | int | 返却は pageSize 単位 |
articles | 検索した記事 | list | 以降のフィールドの繰り返し |
source | ニュースソースIDと名前 | id + name | |
author | 著作者 | string | |
title | タイトル | string | |
descripriotn | 記事要約 | string | |
url | 記事URL | string | |
urlToImage | 記事画像URL | string | |
publishedAt | 日時 | string | ISO 8601 形式 |
content | 記事内容 | string | None が多い |
Top headlines エンドポイント(/v2/top-headlines)
入力(リクエストパラメータ)
パラメータ | 機能 | デフォルト値 | 備考 |
---|---|---|---|
apiKey | API key | 必須 | HTTP ヘッダで指定可 |
country | 国記号 | 全ての国 | 日本は jp |
categry | カテゴリ | 全てのカテゴリ | business, entertainment, general, health, science, sports, technology |
sources | ニュースソースID | - | 複数指定可 |
domains | 検索対象ドメイン | - | 複数指定可 |
q | 検索キーワード | - | |
pageSize | 最大記事数/ページ | 20 | 最大 100 |
page | ページ番号 | 1 |
出力(レスポンスオブジェクト)
Everything エンドポイントと同じ
Python での利用方法
NEWS API は Python を含む各言語用のクライアントライブラリ(SDK)を提供していますが、単純な REST API なので、Python の標準モジュール requests[2] を使った簡単なプログラムでニュース記事を取得できます。以下、各エンドポイントの利用方法を説明します。
Everything エンドポイントの利用
最初に、requests をインポートし、ユーザ登録によって取得した API Key を含むリクエストヘッダを作成します。
import requests
headers = {'X-Api-Key': 'API Key 文字列'}
次に、記事の検索条件を含むリクエストURL とパラメータを作成します。パラメータは URLエンコードする必要がありますが、requests は辞書形式から自動的にエンコードしてくれます。例えば、「コロナウイルス」と「ワクチン」の両方の語を含む記事を新しい順に最大100件検索したい場合は、以下のように指定します。
url = 'https://newsapi.org/v2/everything'
params = {
'q': 'コロナウイルス AND ワクチン',
'sortBy': 'publishedAt',
'pageSize': 100
}
最後に、URL、ヘッダ、パラメータを指定してリクエストを送信し、レスポンスを受信します。
response = requests.get(url, headers=headers, params=params)
print(response)
<Response [200]> が返ってくれば成功です。
レスポンスの中身は、json 形式で見ることができます。
print(response.json())
以下のような内容になっています。
{'status': 'ok',
'totalResults': 255,
'articles': [{'source': {'id': None, 'name': 'Sputnik International'},
'author': 'Sputnik 日本',
'title': 'NZ首都でコロナ規制の抗議デモ\u3000警察が強制排除',
'description': 'ニュージーランドの首都ウェリントンにある国会議事堂近くで2日、新型コロナウイルス対策の規制に抗議するデモが行われた。このデモは先月8日から続いており、参加者はワクチン接種の義務化の反対などを訴えている。',
'url': 'https://jp.sputniknews.com/20220303/nz-10289597.html',
'urlToImage': 'https://cdnn1.img.jp.sputniknews.com/images/sharing/article/jpn/10289597.jpg?102895981646299239',
'publishedAt': '2022-03-03T09:05:00Z',
'content': "https://jp.sputniknews.com/20220303/nz-10289597.html\r\n/html/head/meta[@name='og:title']/@content\r\n/html/head/meta[@name='og:description']/@content\r\nhttps://cdnn1.img.jp.sputniknews.com/img/07e6/03/03… [+666 chars]"},
{'source': {'id': None, 'name': 'Nhk.or.jp'},
…
取得した記事は、pandas のデータフレームに変換するとその後の取り扱いが楽になります。以下は、レスポンス中の記事をデータフレームに変換した後、日時、タイトル、URL の三つの列を表示するコードです。なお、見やすくするために各列の表示幅を25文字に制限しています。
import pandas as pd
pd.options.display.max_colwidth = 25
if response.ok:
data = response.json()
df = pd.DataFrame(data['articles'])
print('totalResults:', data['totalResults'])
print(df[[ 'publishedAt', 'title', 'url']])
実行結果は以下のようになります。
totalResults: 255
publishedAt title url
0 2022-03-03T09:05:00Z NZ首都でコロナ規制の抗議デモ 警察が強制排除 https://jp.sputniknew...
1 2022-03-03T02:21:50Z 米 新たなコロナ対策発表 ワクチン接種率向... https://www3.nhk.or.j...
2 2022-03-03T02:00:00Z 【5月実施の新型コロナウイルス職域接種(大... https://prtimes.jp/ma...
3 2022-03-02T17:05:04Z 北海道情報大学北海道情報大学が3月18日か... https://japan.cnet.co...
4 2022-03-02T12:20:40Z 「新規感染者数 しばらくは高いレベルで推移... https://www3.nhk.or.j...
.. ... ... ...
95 2022-02-16T21:32:08Z コロナ 抗体持つ人は各地で約95% 免疫が... https://www3.nhk.or.j...
96 2022-02-16T17:00:00Z 【東京・小池知事】「コロナから高齢者と子ど... http://fxya.blog129.f...
97 2022-02-16T15:00:10Z コロナ後遺症、ワクチン接種で半減 英政府調査 http://fxya.blog129.f...
98 2022-02-16T14:34:17Z 新型コロナ 愛知で新規感染者6591人 1... https://news.livedoor...
99 2022-02-16T14:13:19Z 【コロナ】さいたま市でワクチン2回接種の1... https://www.2nn.jp/ne...
[100 rows x 3 columns]
検索条件にヒットした総記事数(totalResults)がページサイズ(pageSize)よりも大きい場合は、ページ番号(page)を指定することにより残りの記事を取得できます。
Top headlines エンドポイントの利用
Everything エンドポイントの時とは URL とパラメータの内容が異なるだけで、利用方法は同じです。
例えば、ビジネス分野の日本語記事のヘッドラインを最大20件(デフォルトの件数)検索したい場合は、以下のように指定します。
# Top headlines Endpoint
url = 'https://newsapi.org/v2/top-headlines'
params = {
'category': 'business',
'country': 'jp'
}
# Get response
response = requests.get(url, headers=headers, params=params)
# Make dataframe
if response.ok:
data = response.json()
df = pd.DataFrame(data['articles'])
print('totalResults:', data['totalResults'])
print(df[[ 'publishedAt', 'title', 'url']])
結果は以下のようになります。
totalResults: 68
publishedAt title url
0 2022-03-03T11:00:00Z 走行中の東北新幹線で車掌の顔を殴る…暴行事... https://www.fnn.jp/ar...
1 2022-03-03T10:14:26Z 『うめきた』新駅の現状を公開!工事の8割が... https://www.youtube.c...
2 2022-03-03T10:05:56Z 無人コンテナ船 東京湾へ 荒れる海の次は過... https://www.youtube.c...
3 2022-03-03T10:02:34Z カセットコンロ、ガス共に値上げへ 原油高騰... https://www.youtube.c...
4 2022-03-03T09:11:54Z アネスト岩田 ターンパイク箱根(箱根小田原... https://www.hamakei.c...
5 2022-03-03T09:00:00Z イオンなど50社、業種超え共同配送 人手不... https://www.nikkei.co...
6 2022-03-03T08:41:42Z JAL、東京/羽田〜ロンドン/ヒースロー線... https://www.traicy.co...
…
17 2022-03-03T05:12:00Z 日本初 LNG燃料フェリー「さんふらわあ ... https://trafficnews.j...
18 2022-03-03T05:04:03Z ルネサス、インド・タタ系とEV技術を共同開... https://www.nikkei.co...
19 2022-03-03T04:44:40Z Windows 11プレビュー版、新セキュ... https://pc.watch.impr...
おわりに
以上説明したように、News API を使用することにより、各種のニュース記事を Python のプログラムによって自動的に収集できます。なお、実際に利用する際には無償利用時の制限に加えて、以下の点を考慮しておく必要があります。
- 短い記事を除き、本文全体を取得できない
- 日本語のニュースソースID が使用できない
- Everything エンドポイントでは、日本語を直接指定できない
- Top headlines エンドポイントでは、パラメータの組み合わせに制限がある
- 期待通りの検索結果が得られない場合がある(特に、from, to の日時指定時)
Discussion