java 通过Twitter API v2 提取收藏列表视频数据

我有个好朋友,喜欢听音乐,在twitter上收藏了很多音乐博主,想要每天定时拉取音乐MV视频,问我能不能做,我当然很热心的帮助他.

 一. 创建twitter app 拿到Bearer Token

地址:https://developer.twitter.com/en/portal/projects-and-apps

具体怎么创建网上很多文章有说明,但大多数是过时的,创建应用无非是验证邮箱,然后填一些个人信息,创建应用原因等等,自己慢慢摸索,最需要注意:

twitter帐号关联的邮箱地址不要用国内的,不然收不到验证码

我改成gmail邮箱,才成功收到验证码

二.查看api 找到获取列表推文接口

https://developer.twitter.com/en/docs/twitter-api/v1/accounts-and-users/create-manage-lists/api-reference/get-lists-statuseshttps://developer.twitter.com/en/docs/twitter-api/v1/accounts-and-users/create-manage-lists/api-reference/get-lists-statusesapi接口:https://api.twitter.com/1.1/lists/statuses.json

参数:

list_id:列表ID(自己去twitter列表F12去看自己的列表ID)

since_id:最小推文id

count:推文数量

三.通过接口获取数据解析并下载视频

  • 获取列表的推文内容
/**
     * 获取推特列表内容
     *
     * @param listId      列表ID
     * @param startListId 最小推文ID
     * @param count       推文数量
     * @return
     */
    public static List<Tweet> getListTweets(String listId, String startListId, Integer count) {
        try {
            if (StringUtils.isEmpty(listId)) return null;
            trustEveryone();
            System.setProperty("https.protocols", "TLSv1,TLSv1.1,TLSv1.2,SSLv3");
            String baseUrl = listApi + "?list_id=" + listId;
            if (StringUtils.isNotEmpty(startListId)) {
                baseUrl += "&since_id=" + startListId;
            }
            if (count != null && count > 0) {
                baseUrl += "&count" + count;
            }
            URL url = new URL(baseUrl);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            conn.setRequestProperty("Authorization", "Bearer " + token);
            conn.setRequestProperty("Content-Type", "application/json;charset=UTF-8");
            conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36");
            conn.setRequestProperty("Accept", "*/*");
            conn.setRequestProperty("Connection", "keep-alive");
            conn.setUseCaches(false);
            conn.setConnectTimeout(20000);
            conn.setReadTimeout(20000);
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.connect();

            InputStream is = null;
            if (conn.getResponseCode() == 200) {
                is = conn.getInputStream();
            } else if (conn.getResponseCode() == 400) {
                is = conn.getErrorStream();
            }
            if (is == null) return null;
            BufferedReader in = new BufferedReader(new InputStreamReader(is, "UTF-8"));
            StringBuilder sb = new StringBuilder();
            String line;
            while ((line = in.readLine()) != null) {
                sb.append(line);
                sb.append("\n");
            }
            JSONArray array = JSONArray.parseArray(sb.toString());
            if (array != null && array.size() > 0) {
                List<Tweet> list = new ArrayList<>();
                for (Object obj : array) {
                    JSONObject json = (JSONObject) obj;
                    Tweet tweet = formaterTweet(json);
                    if (tweet != null) {
                        list.add(tweet);
                    }
                }
                return list;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

注意:请求https可能会报错:Remote host closed connection during handshake

解决办法参考:https://blog.csdn.net/qq_30831935/article/details/94299220


  • 解析推文
    /**
     * 推文内容解析
     * json.id : tweetId
     * json.text: (unicode) tweetText;
     * json.created_at: 创建时间(new Date("Wed Nov 17 14:39:51 +0000 2021"))
     * json.{extended_entities}.[media].id : 视频ID
     * json.{extended_entities}.[media].media_url : 视频缩略图
     * json.{extended_entities}.[media].{video_info}.[variants] : (list[{bitrate:"分辨率",content_type:"video/mp4",url:"视频地址"}]) 视频集合,取分辨率最高的一个
     * json.user.id: 发布用户ID
     * json.user.name: 发布用户名称
     *
     * @param json
     * @return
     */
    private static Tweet formaterTweet(JSONObject json) {
        try {
            if (json == null || !json.containsKey("extended_entities")) return null;
            Tweet tweet = new Tweet();
            tweet.setTwId(json.getString("id"));
            tweet.setTwText(UnicodeUtil.toString(json.getString("text")));
            tweet.setTwTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(json.getString("created_at"))));
            tweet.setMediaId(json.getJSONObject("extended_entities").getJSONArray("media").getJSONObject(0).getString("id"));
            tweet.setMediaPic(json.getJSONObject("extended_entities").getJSONArray("media").getJSONObject(0).getString("media_url"));
            if (json.getJSONObject("extended_entities").getJSONArray("media").size() > 1 || !json.getJSONObject("extended_entities").getJSONArray("media").getJSONObject(0).containsKey("video_info"))
                return null;
            //获取分辨率最高的视频地址
            List<JSONObject> mediaz = json.getJSONObject("extended_entities").getJSONArray("media").getJSONObject(0).getJSONObject("video_info").getJSONArray("variants").toJavaList(JSONObject.class);
            List<JSONObject> medias = mediaz.stream().filter(t -> t.getString("content_type").equals("video/mp4")).sorted((t1, t2) -> {
                return t2.getInteger("bitrate") - t1.getInteger("bitrate");
            }).collect(Collectors.toList());
            tweet.setMediaUrl(medias.get(0).getString("url"));
            tweet.setUserId(json.getJSONObject("user").getString("id"));
            tweet.setUserName(json.getJSONObject("user").getString("name"));
            return tweet;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

Tweet 实体:

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Tweet {
    private String twId; //推文ID
    private String twText;  //推文内容
    private String twTime;  //发推时间
    private String mediaId;  //视频ID
    private String mediaPic; //视频缩略图
    private String mediaUrl; //视频地址
    private String userId;   //发推用户ID
    private String userName; //发推用户名

    @Override
    public String toString() {
        return JSONObject.toJSONString(this);
    }
}


  • 下载内容
    /**
     * 下载推文文字,视频和缩略图
     *
     * @param tweet
     */
    private static void downloadMedia(Tweet tweet) {
        try {
            String tweetFile = localSource + "/" + tweet.getTwId() + "/" + tweet.getTwId();
            //保存缩略图
            if (!FileUtil.exist(tweetFile + ".jpg")) {
                saveToFile(tweet.getMediaPic(), tweetFile + ".jpg");
            }
            //保存视频
            if (!FileUtil.exist(tweetFile + ".mp4")) {
                saveToFile(tweet.getMediaUrl(), tweetFile + ".mp4");
            }
            //保存推文内容
            if (!FileUtil.exist(tweetFile + ".txt")) {
                FileUtil.writeString(tweet.getTwText(), tweetFile + ".txt", Charset.forName("utf-8"));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

效果:

代码完整内容查看:https://download.csdn.net/download/D_lady/44794742

github:https://github.com/doodt/TwitterUtil/blob/main/TwitterUtil.java

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值