VB.NETを利用したニュースアプリ作成
はじめに
そろそろネタ切れ感出てきましたが、いつまで続くんでしょうか…
さておき今回は
・天気API以外のAPIも利用できるか
・API同士の連動
などを目標に、ニュースアプリの作成をやっていきます。
要件定義
AIに聞いてみた結果、こんな感じで進めるらしいです。
📰 ニュース検索アプリのイメージ
画面構成(Windowsフォーム)
TextBox:キーワード入力欄(例: "AI", "セキュリティ")
Button:「検索」ボタン
DataGridView:記事一覧表示(タイトル・URL・日付など)
処理の流れ
TextBox にキーワード入力 → 「検索」クリック
NewsAPI を叩いて JSON 取得
(例: https://newsapi.org/v2/everything?q=AI&apiKey=「APIキー」)
JSONから「タイトル・URL・日付」を抽出
SQL Server に保存
id(自動採番)
keyword
title
url
published_at
DataGridView に記事一覧を表示
ポイント
複数件のニュース(JSON配列)を処理する → 天気アプリより発展的 ✨
URLをクリックしてブラウザで開けるようにする → ちょっと便利にできる
SQLで履歴管理 → いつ・どんなキーワードで検索したか残せる
難易度
天気アプリ(1件JSON)より少し上
でもやることはほぼ同じ → API呼び出し / JSONパース / SQL保存 / DataGridView表示
2〜3日で完成できるレベル
今回は以上の要件に加えて
・取得する記事は英語なので、翻訳APIを利用して翻訳する機能
・Twitterで読みこんだ記事を共有する
も追加していきたいと思います。
News APIにかかわる実装
APIキーの準備
APIを使うんだから、APIキーを取得しよう、ということです。
こちらから取得します。
こちらのAPIキーは、1000件/日まで無料です。個人利用なら無料と考えていいでしょう。
GET API KEYをクリックしたら

この画面で登録するだけです。

個人利用なら「I am an individual」
企業の場合、または商用利用する場合のうち、開発環境以外でAPIを利用する場合は「I am a business, or am working on behalf of a business」を選択しましょう。

登録したら、APIキーを環境変数に書き込みます。

環境変数の設定は、以下の方法で構築してください。
復習用に3行で要約すると
・ソリューションにDotNetEnvをインストールし「.env」ファイルを作成
・プロパティの出力ディレクトリを「常にコピーする」に設定
・環境変数を書き込み(例)「NEWS_API_KEY=111111」
News APIとの連携
仮画面作成
画面はひとまず、こんな感じで作ります。
DataGridViewは今はまだ使わないけど、作っておいてもいいです。

MessageBoxを用いたテスト
初っ端から、どこに何を入れるのかを考えるのは無謀なので、ひとまずMessageBoxに入れてみて、表示されるかのテストを行います。
全体像はこんな感じで。
Imports System.Net
Imports System.Net.Http
Imports System.Net.Http.Headers
Imports System.Threading.Tasks
Imports System.Text.Json
Imports DotNetEnv
Public Class Form1
Private Async Sub Button_検索_Click(sender As Object, e As EventArgs) Handles Button_検索.Click
' .env を読み込む
Env.Load()
Dim kensaku As String = TextBox_入力.Text.Trim()
If String.IsNullOrEmpty(kensaku) Then
MessageBox.Show("検索ワードを入力してください。")
Return
End If
' APIキーを取得
Dim newsapikey As String = Env.GetString("NEWS_API_KEY")
If String.IsNullOrEmpty(newsapikey) Then
MessageBox.Show("APIキーが読み込めません。")
Return
End If
System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12
' キーワードをURLエンコード
Dim encodedKeyword As String = Uri.EscapeDataString(kensaku)
Dim url As String = $"https://newsapi.org/v2/everything?q={encodedKeyword}&pageSize=5&apiKey={newsapikey}" ' pageSizeで取得件数制限
MessageBox.Show(url)
Try
Using client As New HttpClient()
client.DefaultRequestHeaders.UserAgent.ParseAdd("VBNewsClient/1.0")
Dim res As HttpResponseMessage = Await client.GetAsync(url)
Dim response As String = Await res.Content.ReadAsStringAsync()
If Not res.IsSuccessStatusCode Then
MessageBox.Show("NewsAPIエラー: " & response)
Return
End If
' JSONパース
Dim jsonDoc As JsonDocument = JsonDocument.Parse(response)
Dim root = jsonDoc.RootElement
' ステータスチェック
Dim status As String = root.GetProperty("status").GetString()
If status <> "ok" Then
MessageBox.Show("APIのレスポンスが正常ではありません。")
Return
End If
Dim articles = root.GetProperty("articles")
If articles.GetArrayLength() = 0 Then
MessageBox.Show("記事が見つかりませんでした。")
Return
End If
Dim resultText As String = ""
For Each article In articles.EnumerateArray()
Dim title As String = article.GetProperty("title").GetString()
Dim articleUrl As String = article.GetProperty("url").GetString()
Dim publishedAt As String = article.GetProperty("publishedAt").GetString()
resultText &= $"キーワード: {kensaku}" & vbCrLf &
$"タイトル: {title}" & vbCrLf &
$"URL: {articleUrl}" & vbCrLf &
$"公開日: {publishedAt}" & vbCrLf & vbCrLf
Next
MessageBox.Show(resultText, "検索結果")
End Using
Catch ex As HttpRequestException
MessageBox.Show("HTTPリクエストエラー: " & ex.Message)
Catch ex As JsonException
MessageBox.Show("JSON解析エラー: " & ex.Message)
Catch ex As Exception
MessageBox.Show("その他エラー: " & ex.Message)
End Try
End Sub
End Class
まず、ImportsでHttpやらJsonやら環境変数やらを使えるようにします。
Imports System.Net
Imports System.Net.Http
Imports System.Net.Http.Headers
Imports System.Threading.Tasks
Imports System.Text.Json
Imports DotNetEnv
次に、セキュリティプロトコルをTLS 1.2に対応させます。
System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12
これをコメントアウトして検索すると、以下のようなエラーが出るからです。
ほかのAPIを利用する際も同様のエラーが発生する可能性があるので、今後APIを利用したVB.NET開発でHTTPリクエストエラーが出た際は、これを疑ったほうがいいかもしれません。

また、HttpClientを設定する際に、UserAgentを追加する必要があるらしいので、そちらも追加していきます。
Using client As New HttpClient()
client.DefaultRequestHeaders.UserAgent.ParseAdd("VBNewsClient/1.0")
Dim res As HttpResponseMessage = Await client.GetAsync(url)
Dim response As String = Await res.Content.ReadAsStringAsync()
次に、入力するURLを決定します。
Dim encodedKeyword As String = Uri.EscapeDataString(kensaku)
Dim url As String = $"https://newsapi.org/v2/everything?q={encodedKeyword}&pageSize=5&apiKey={newsapikey}" ' pageSizeで取得件数制限
MessageBox.Show(url)
このへんも、だいたい前回と同じで、クエリのところに検索項目やらapikeyやらを適切にいれてやります。
ブラウザで↑の通りにURLを書いて、q=AI&pageSize=5で検索するとこんな感じで、ニュースっぽいJSON記述が5件出てきます。

あとは大体AIが生成したコードとコメントの解説でわかるかなと。
それでは実際に動くか確認します。
TextBoxに「AI」と書いて入力すると、以下の画像のように、ニュースが5件表示されました。

ということで、NewsAPI側の設定は、これで終了です。お疲れ様でした。
DeepL API Freeとの連携
次は、先程出た英語の記事のタイトルを、DeepL API日本語に翻訳していきます。
こちらのページから、無料版を登録します。
なお、クレカ情報が必要なこと、翻訳は月50万字までであることに留意します。

そしたら、こちらのページでAPIキーを取得します。

APIキーを取得したら、
' DeepL翻訳関数を呼び出す
Dim translatedTitle As String = Await 翻訳(title)
resultText &= $"キーワード: {kensaku}" & vbCrLf &
$"タイトル: {translatedTitle}" & vbCrLf &
$"URL: {articleUrl}" & vbCrLf &
$"公開日: {publishedAt}" & vbCrLf & vbCrLf
これの、タイトルの部分に、DeepLで翻訳したものを代わりに入れます。
せっかくなので、ここからは英文を翻訳する関数を作っていきます。
Private Async Function 翻訳(title As String) As Task(Of String)
Dim deeplapikey As String = Env.GetString("DEEPL_API_KEY")
' DeepLのエンドポイント
Dim deeplUrl As String = "https://api-free.deepl.com/v2/translate" ' 有料版なら api.deepl.com
Using httpclient As New HttpClient()
Dim parameters = New Dictionary(Of String, String) From {
{"auth_key", deeplapikey},
{"text", title},
{"target_lang", "JA"}
}
Dim content = New FormUrlEncodedContent(parameters)
Dim responsetrans As HttpResponseMessage = Await httpclient.PostAsync(deeplUrl, content)
Dim responseString As String = Await responsetrans.Content.ReadAsStringAsync()
Using jsonTrans As JsonDocument = JsonDocument.Parse(responseString)
Dim translatedTitle As String = jsonTrans.RootElement _
.GetProperty("translations")(0) _
.GetProperty("text") _
.GetString()
Return translatedTitle
End Using
End Using
End Function
いつも通り、APIキーやら、エンドポイントURLやら、文字情報を入力する必要があるんですが、DeepLの場合はそれらの情報を上のような構文を作って送っていきます。
このtitleを、翻訳()関数を使って新しくtranslatedTitleとして書き直して実行すると…

翻訳されたタイトルが表示されました。
履歴および、履歴からのリンク機能の実装
次に、こうしてNewsAPIとDeepLで作ったデータを、メッセージボックスに書き込むだけでなく、SSMS側のテーブルにも保存していきます。
ここの過程については、だいたい以下のページでやったことと同じなので、いくつか写真だけ見せて、簡易的に説明。
履歴用のテーブルを用意
ID,キーワード、タイトル、URL、公開日の列を用意

テーブルに書き込む用のストアドを用意
USE [NEWS]
GO
CREATE PROCEDURE [dbo].[記事_追加]
@キーワード NVARCHAR(100),
@タイトル NVARCHAR(500),
@Url NVARCHAR(500),
@公開日 DATETIME
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO [dbo].[履歴] (キーワード, タイトル, URL, 公開日)
VALUES (@キーワード, @タイトル, @Url, @公開日);
END
ストアドに入力する用の関数
resultText &= $"キーワード: {kensaku}" & vbCrLf &
$"タイトル: {translatedTitle}" & vbCrLf &
$"URL: {articleUrl}" & vbCrLf &
$"公開日: {publishedAt}" & vbCrLf & vbCrLf
InsertNewsArticleSP(kensaku, translatedTitle, articleUrl, publishedAt)
Private Sub InsertNewsArticleSP(keyword As String, title As String, url As String, publishedAt As DateTime)
' サーバ、データベース名を取得
Dim server As String = Env.GetString("SERVER")
Dim db As String = Env.GetString("DB")
Dim connectionString As String = "Server=" + server + ";Database=" + db + ";Trusted_Connection=True;TrustServerCertificate=True;"
Using conn As New Microsoft.Data.SqlClient.SqlConnection(connectionString)
conn.Open()
Using cmd As New Microsoft.Data.SqlClient.SqlCommand("記事_追加", conn)
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.AddWithValue("@キーワード", keyword)
cmd.Parameters.AddWithValue("@タイトル", title)
cmd.Parameters.AddWithValue("@Url", url)
cmd.Parameters.AddWithValue("@公開日", publishedAt)
cmd.ExecuteNonQuery()
End Using
End Using
End Sub
実際にSQLのテーブルへの書き込みが機能するか確認

SQLテーブルのデータをDataGridViewへ移植
テーブルを読み込むストアドを作ったら
USE [NEWS]
GO
/****** Object: StoredProcedure [dbo].[履歴_抽出] Script Date: 2025/08/26 16:10:02 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- プロシージャ定義部
ALTER PROCEDURE [dbo].[履歴_抽出]
AS
-- 処理部
BEGIN
SET NOCOUNT ON;
SELECT
タイトル,
URL,
公開日
FROM [dbo].[履歴]
ORDER BY ID
END
ストアドからデータを読み込む関数を、Loadするタイミングで差し込む
Private Sub データ表示()
' .env を読み込む
Env.Load()
Dim server As String = Env.GetString("SERVER")
Dim db As String = Env.GetString("DATABASE")
Dim connectionString As String = $"Server=" + server + ";Database=" + db + ";Trusted_Connection=True;TrustServerCertificate=True;"
Try
Using conn As New SqlConnection(connectionString)
Using cmd As New SqlCommand("履歴_抽出", conn)
cmd.CommandType = CommandType.StoredProcedure
conn.Open()
Using reader As SqlDataReader = cmd.ExecuteReader()
DataGridView_履歴.Rows.Clear()
While reader.Read()
Dim rowIndex As Integer = DataGridView_履歴.Rows.Add()
For i As Integer = 0 To 2
DataGridView_履歴.Rows(rowIndex).Cells(i).Value = If(reader(i) Is DBNull.Value, "", reader(i))
Next
End While
End Using
End Using
End Using
Catch ex As Exception
MessageBox.Show("エラー: " & ex.Message)
End Try
End Sub

ここまでは復習的な部分なので大丈夫ですね
DataGridViewのリンクを有効にする。
これは、URLの列のColumnTypeをDataGridViewLinkColumnにして、クリックしたときにURLに飛べるような処理を作るだけです。

Private Sub DataGridView_履歴_CellContentClick(sender As Object, e As DataGridViewCellEventArgs) Handles DataGridView_履歴.CellContentClick
' URL 列がクリックされた場合
If e.ColumnIndex = DataGridView_履歴.Columns(1).Index AndAlso e.RowIndex >= 0 Then '←今回は2列目にURLを指定
Dim url As String = DataGridView_履歴.Rows(e.RowIndex).Cells(e.ColumnIndex).Value.ToString()
Try
System.Diagnostics.Process.Start(New ProcessStartInfo With {
.FileName = url,
.UseShellExecute = True
})
Catch ex As Exception
MessageBox.Show("リンクを開けません: " & ex.Message)
End Try
End If
End Sub
URLをクリックしたら、そのページに飛べることを確認しました。


余談ですが、いくらVB.NET、SQL、およびAPIの利用法自体を目的として本アプリを作成しているとはいえ、有料記事だらけでロクに読めないのが悲しいところです。
記事をツイートする
最後におまけとして、記事のツイート機能も実装しておきます。
Twitterに投稿する用のURLのクエリ部分を
text=""←ここがツイートの本文(今回は題名を入れてみる)
url=""←ここがリンク(今回はツイートしたい記事のURL)
こう書いてやると、ツイートしたい文章、リンクの両方がついたテキストをツイートできる状態になった画面が表示されるURLが作成できます。
要するに「DataGridViewのリンクを有効にする」でやってることとほぼ同じです。
If e.ColumnIndex = DataGridView_履歴.Columns(3).Index AndAlso e.RowIndex >= 0 Then
Dim url As String = "https://twitter.com/intent/tweet?text=" + DataGridView_履歴.Rows(e.RowIndex).Cells(0).Value.ToString() + "&url=" + DataGridView_履歴.Rows(e.RowIndex).Cells(1).Value.ToString()
Try
System.Diagnostics.Process.Start(New ProcessStartInfo With {
.FileName = url,
.UseShellExecute = True
})
Catch ex As Exception
MessageBox.Show("リンクを開けません: " & ex.Message)
End Try
End If


Twitter(忌み名"X")のツイート機能はいろいろなサイトで実装されているので実用性が高い一方で、やってること自体は非常に単純なので、手軽にすごいことをしてる気分になれてすごいですね。
終わりに
今回は、ニュース取得や翻訳API、そして今まで紹介してきたものを有効活用して、だいぶそれっぽいニュース検索アプリが試作できたんじゃないかと思います。
外国語のタイトルを自動翻訳してくれるので、こういうのをきっかけに外国の情報に興味を持つ人が、もしかしたらいるのかもしれません。
一方、今回のニュース取得APIの個人的評価は(有料記事ばっかり捕まえてくるせいで)いまいちなので、何かしらの形でAPI自体の自作もできたら、もっと実用的に納得のいくアプリになるのかなと思います。
Discussion