※当サイトの記事には、広告・プロモーションが含まれます。

Twitter APIを利用できるようにしてみる

gigazine.net

⇧ amazing...

Twitter APIとは?

公式のドキュメントによりますと、

developer.twitter.com

The Twitter API enables programmatic access to Twitter in unique and advanced ways. Tap into core elements of Twitter like: Tweets, Direct Messages, Spaces, Lists, users, and more.

https://developer.twitter.com/en/docs/twitter-api

⇧ プログラム経由でTwitterのコンテンツを取得できるということらしい。

Twitter APIについては、

developer.twitter.com

While the Twitter API v2 is the primary Twitter API, the platform currently supports previous versions (v1.1, Gnip 2.0) as well. We recommend that all users start with v2 as this is where all future innovation will happen. 

https://developer.twitter.com/en/docs/twitter-api

⇧ とりあえず、バージョン2の利用を推奨してるっぽい。

Twitter APIを利用できるようにするためには

Twitter APIを利用できるようにするためには、

zenn.dev

miyastyle.net

di-acc2.com

developer.twitter.com

⇧ 大前提として、Twitterのアカウントが必要らしい。

developer.twitter.com

⇧ 上記ページにアクセスすると、Developer Portalのページが表示されるので、必要項目を入力し、「Let’s do this」を押下。

利用規約の同意にチェックし、「Submit」ボタン押下。

なんか、電話番号の登録が必須みたいね...

電話番号の登録については、

help.twitter.com

Twitterの設定で行う必要がある模様、Developer Portalでできないとはね...

アイコンをクリックし、選択肢から「Go to Twitter」のリンクをクリック。

のアイコンをクリック。

「設定とプライバシー」を選択。

「アカウント」>「アカウント情報」を選択。

「電話」を選択。

電話番号を入力し、「次へ」を押下。

スマホに認証コードを送る旨の許可を求められるので、「OK」押下。

スマホに届く認証コードを入力し、「認証」押下。

電話番号が登録されます。

再度、Developer Portalのページで「Submit」すると、登録しているメールアドレスへメールが届くので、

「Confirm your email」を押下。

Appの名前を入力して、「Get keys」押下。

API Key、API Key Secret、Bearer Tokenが生成されるのですが、ここでしか表示されないっぽいので、メモしときます。

で、

wporz.com

これで、Twitter API v2を使うために必要な「API Key」、「API secret key」、「Access token」、「Access token secret」の取得完了です。

Twitter API v2を使うためのAPI Keyの取得方法:アプリケーションの利用申請からAPI登録まで

⇧ 上記サイト様によりますと、自動で生成されるAPI Key、API Key Secret、Bearer Tokenの他に、「Access token」「Access token secret」も作成しておく必要があるそうな。

「Elevated」の利用申請をしておいたほうが良いようなので、利用申請をしていきます。

Developer Portalで、「Products」の「Twitter API v2」を選択し、

「Elevated」タブを選択し、「Apply」を押下。

質問に対して、英語で回答を入力し終わると、「Elevated」の利用ができるようになるようです。

あとは、「Access Token」と「Access Secret」を作成する。

「Project &Apps」で、作成したAppを選択し、

「Keys and tokens」タブを選択し、「Access Token and Secret」の「Generate」を押下。

作成されるので、値をメモしておきます。

twitter-api-java-sdkTwitter API v2を利用してみる

Twitter API v2を利用できる準備ができたので、Javaで試してみます。

EclipseでSpring Bootのプロジェクトを作成。

⇧ プロジェクトが作成されたら、JavaTwitter API v2を利用できるように依存関係を追加します。

■/twitter-api-example/build.gradle

plugins {
	id 'java'
	id 'org.springframework.boot' version '2.7.8-SNAPSHOT'
	id 'io.spring.dependency-management' version '1.0.15.RELEASE'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'

configurations {
	compileOnly {
		extendsFrom annotationProcessor
	}
}

repositories {
	mavenCentral()
	maven { url 'https://repo.spring.io/milestone' }
	maven { url 'https://repo.spring.io/snapshot' }
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
	implementation 'org.springframework.boot:spring-boot-starter-web'
	implementation 'com.twitter:twitter-api-java-sdk:2.0.3'
	compileOnly 'org.projectlombok:lombok'
	developmentOnly 'org.springframework.boot:spring-boot-devtools'
	annotationProcessor 'org.projectlombok:lombok'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

tasks.named('test') {
	useJUnitPlatform()
}

そしたらば、JavaTwitter API を利用してみる。

■/twitter-api-example/src/main/resources/application.properties

# Twitter API v2 
twitter.api.bearerToken=Twitter APIを利用するためのBEARER TOKEN

■/twitter-api-example/src/main/java/com/example/demo/service/TwitterServiceImpl.java

package com.example.demo.service;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.InterruptedIOException;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.twitter.clientlib.ApiException;
import com.twitter.clientlib.TwitterCredentialsBearer;
import com.twitter.clientlib.api.TwitterApi;

@Service
public class TwitterServiceImpl {
	
	@Value("${twitter.api.bearerToken}")
	private String bearerToken;
	
	private TwitterApi createTwitterApiInstance() {
        TwitterCredentialsBearer credentials = new TwitterCredentialsBearer(this.bearerToken);
        TwitterApi apiInstance = new TwitterApi(credentials);
        return apiInstance;
 	}
	
	private InputStream sampleStream() throws ApiException {
		TwitterApi apiInstance = this.createTwitterApiInstance();
	    Set<String> tweetFields = new HashSet<>();
	    tweetFields.add("author_id");
	    tweetFields.add("id");
	    tweetFields.add("created_at");
	    tweetFields.add("geo");
	    Set<String> expansions = new HashSet<>();
	    expansions.add("geo.place_id");
	    Set<String> placeFields = new HashSet<>();
	    placeFields.add("geo");
	    placeFields.add("id");
	    placeFields.add("name");
	    placeFields.add("place_type");

	    return apiInstance.tweets().sampleStream()
        .backfillMinutes(0)
        .tweetFields(tweetFields).expansions(expansions).placeFields(placeFields)
        .execute();		
	}
	
//	private InputStream searchTwitter() throws ApiException {
//		TwitterApi apiInstance = this.createTwitterApiInstance();
//		Integer backfillMinutes = 3; // Integer | The number of minutes of backfill requested.
//        OffsetDateTime startTime = OffsetDateTime.parse("2023-01-01T00:00:40.000Z"); // OffsetDateTime | YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp from which the Tweets will be provided.
//        OffsetDateTime endTime = OffsetDateTime.parse("2023-01-01T00:01:40.000Z"); // OffsetDateTime | YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Tweets will be provided.
//        Set<String> tweetFields = new HashSet<>(Arrays.asList("id", "author_id", "created_at", "lang", "source", "text", "entities", "public_metrics")); // Set<String> | A comma separated list of Tweet fields to display.
//        Set<String> expansions = new HashSet<>(Arrays.asList()); // Set<String> | A comma separated list of fields to expand.
//	    Set<String> mediaFields = new HashSet<>(Arrays.asList()); // Set<String> | A comma separated list of Media fields to display.
//	    Set<String> pollFields = new HashSet<>(Arrays.asList()); // Set<String> | A comma separated list of Poll fields to display.
//	    Set<String> userFields = new HashSet<>(Arrays.asList()); // Set<String> | A comma separated list of User fields to display.
//	    Set<String> placeFields = new HashSet<>(Arrays.asList()); // Set<String> | A comma separated list of Place fields to display.
//
//	    InputStream response = apiInstance.tweets().searchStream()
//                .backfillMinutes(backfillMinutes)
//                .startTime(startTime)
//                .endTime(endTime)
//                .tweetFields(tweetFields)
//                .expansions(expansions)
//                .mediaFields(mediaFields)
//                .pollFields(pollFields)
//                .userFields(userFields)
//                .placeFields(placeFields)
//                   .execute();
//        try{
//            //JSON json = new JSON();
//            Type localVarReturnType = new TypeToken<FilteredStreamingTweetResponse>(){}.getType();
//            BufferedReader reader = new BufferedReader(new InputStreamReader(response));
//            String line = reader.readLine();
//            while (line != null) {
//              if(line.isEmpty()) {
//                System.out.println("==> Empty line");
//                line = reader.readLine();
//                continue;
//              }
//              Object jsonObject = JSON.getGson().fromJson(line, localVarReturnType);
//              System.out.println(jsonObject != null ? jsonObject.toString() : "Null object");
//              line = reader.readLine();
//            }
//         }catch (Exception e) {
//           e.printStackTrace();
//           System.out.println(e);
//         }
//        return response;
//	}
	
	public List<String> queueTweets() {
		String line = null;
		List<String> twitteList = new ArrayList<>();
		BigInteger count = BigInteger.ZERO;
		try (BufferedReader reader = new BufferedReader(new InputStreamReader(this.sampleStream()))) {
	        while ((line = reader.readLine()) != null) {
	        	count = count.add(BigInteger.ONE);
	        	if (count.compareTo(new BigInteger("1000")) >= 0) {
	        		break;
	        	}
	        	System.out.print(count);
	            System.out.println(line);
	            twitteList.add(line);
	        }
	        
		} catch (ApiException e) {
			System.out.println(e);
		} catch(InterruptedIOException e) {
			
		} catch(Exception e) {
			
		}
		return twitteList;
	}
	
}

■/twitter-api-example/src/main/java/com/example/demo/controller/TwitterController.java

package com.example.demo.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.example.demo.service.TwitterServiceImpl;

@RestController
@RequestMapping("twitter")
public class TwitterController {

	@Autowired
	private TwitterServiceImpl twitterServiceImpl;
	
	@GetMapping("search")
	public List<String> searchTwitter() {
		return twitterServiceImpl.queueTweets();
	}
	
}
    

⇧ で保存して、実行。

Twitterの投稿が取得できています。

ただ、バグなのか分からないのですが、Twitter API v2 SDKJavaについては、メソッドで機能しないのがあるんかな、少なくとも、searchStreamについては、

github.com

⇧ 公式のexample通りコーディングしてもエラーになるし、

github.com

⇧ 上記サイト様を参考に、プロジェクトのルート直下にsdk.propertiesというファイルを作成しても、別のエラーが出てしまう状態でした。

まぁ、Twitter API v2 SDKJavaについては、本番環境の使用に耐えうるものじゃないということなんでしょうかね、Twitter API v2 SDKを推奨してる割には、整備がなっていない気がして致し方ない...

毎度モヤモヤ感が半端ない...

今回はこのへんで。