获取B站评论抽奖实现
### 前景提要?
今天逛B站看了一個我喜歡的up主發(fā)的視屏,(音樂區(qū)up主)。然后視屏下面有人評論說要贊助抽些獎品。我就隨手寫了評論。要幫他寫抽獎。
完了之后想了下實現(xiàn)邏輯,億點都不難。只需要獲取到所有的評論信息,然后寫隨機數(shù)就可以了。
### 踩坑日記
然后我忙完手里的工作后用瀏覽器抓包看了下評論信息的URL。并試著用java請求。好吧失敗了。然后瀏覽器多抓了幾次包,分析瀏覽器請求。發(fā)現(xiàn)最后一位是隨機數(shù),仔細看了好像是當前時間的毫秒值。然后我把數(shù)字轉(zhuǎn)成時間。好家伙。果然是當前請求的毫秒數(shù)。然后拼接參數(shù)后繼續(xù)請求。還是失敗。沒辦法只能繼續(xù)看請求了。發(fā)現(xiàn)中間有一段參數(shù)每次請求都會遞增,然后繼續(xù)組裝參數(shù)遞增。還是請求失敗
好吧我在想是不是判斷了我當前請求的客戶端是不是為瀏覽器。然后我設置了請求頭,結果還是失敗。
最后我想,肯定不止我一個人閑的沒事扒B站評論吶,看看別人是怎么扒的。然后我百度了一下。果然還是有很多人扒的,然后我發(fā)現(xiàn),他們的請求居然沒有兩個會變得參數(shù)。然后我刪掉兩個參數(shù)后。what ? 請求到數(shù)據(jù)了。。。。
后面的工作就簡單多了,只需要將json格式的數(shù)據(jù)轉(zhuǎn)成我熟悉的java對象來操作就好了。
然后,B站返回的數(shù)據(jù)實在是太多了,一個身份信息就用了好多個字段,判斷是不是大會員呀之類的。好了我們用不到,那就先忽略吧,隨意拿了一些屬性出來構建實體。
### 代碼實現(xiàn)
import lombok.Data;/*** b 站視頻評論數(shù)據(jù)格式對象*/ @Data public class BiliBili {private Integer code;private String message;private Integer ttl;private BiliBiliData data; } import lombok.Data; import java.util.List;/*** b 站視頻評論數(shù)據(jù)格式Data對象*/ @Data public class BiliBiliData {/*** 分頁信息*/private BiliBiliPage page;/*** 評論信息*/private List<BiliBiliReplies> replies; } import lombok.Data;/*** 分頁數(shù)據(jù)*/ @Data public class BiliBiliPage {private Integer count;private Integer num;private Integer size; } import lombok.Data;import java.util.List;@Data public class BiliBiliReplies {private Integer rpid;private Integer oid;private Integer type;private Integer mid;private Integer root;private Integer parent;private Integer dialog;private Integer count;private Integer rcount;private Integer state;private Integer fansgrade;private Integer attr;private Integer ctime;private String rpid_str;private String root_str;private String parent_str;private Integer like;private Integer action;/*** 用戶信息*/private BiliBiliUser member;/*** 評論內(nèi)容*/private BiliBiliComment content;/*** 下級評論*/private List<BiliBiliReplies> replies;} import lombok.Data;@Data public class BiliBiliUser {private String mid;private String uname;private String sex;private String sign;private String avatar;private String rank; } import lombok.Data;/*** b 站視頻評論內(nèi)容爬取轉(zhuǎn)JSON*/ @Data public class BiliBiliComment {private String message; }構建完這些實體,下面該實現(xiàn)抽獎的功能了
我用了hutool工具來做了json的轉(zhuǎn)換合http請求和集合的判斷
<dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.7.1</version> </dependency>?昨天寫的時候評論比較少,評論沒有分頁今天發(fā)現(xiàn)默認的評論展示是每頁十條,所以添加了分頁的處理。原有基礎上添加了分頁的處理
import cn.hutool.core.collection.IterUtil; import cn.hutool.core.text.StrFormatter; import cn.hutool.http.HttpRequest; import cn.hutool.json.JSONUtil;import java.util.*; import java.util.stream.Collectors;public class BiliBiliCrawler {/*** 抽獎次數(shù)*/private static final Integer COUNT = 3;/*** 是否取消發(fā)布者的中獎資格 true 取消 false 不取消 .默認取消 哈哈*/private static final boolean IS_CANCEL = true;public static void main(String[] args) {String url = "https://api.bilibili.com/x/v2/reply/reply?&jsonp=jsonp&pn=1&type=1&oid=418654756&ps=10&root=4747243408";String str = HttpRequest.get(url).execute().body();// 轉(zhuǎn)java對象BiliBili bilibili = JSONUtil.toBean(str, BiliBili.class);// 獲取分頁信息BiliBiliPage page = bilibili.getData().getPage();// 計算頁數(shù)int total = (page.getCount() + page.getSize() - 1) / page.getSize();if (total == 0) {System.out.println("未獲取到評論信息");return;}// 用戶名集合List<String> list = new ArrayList<>(page.getCount());// 用戶評論集合,一個用戶可能存在多條評論信息Map<String, List<String>> con = new HashMap<>((int) Math.ceil(page.getCount() / 0.75) + 1);// 填充集合,準備抽獎for (int i = 1; i <= total; i++) {// 賦值頁碼,追加到評論之后,方便找到中獎者int a = i;// 第一次請求的數(shù)據(jù)在獲取頁數(shù)的時候就已經(jīng)得到了所以第一次是不需要重新請求的BiliBili bili;if (i != 1) {String sf = StrFormatter.format("https://api.bilibili.com/x/v2/reply/reply?&jsonp=jsonp&pn={}&type=1&oid=418654756&ps=10&root=4747243408", i);String json = HttpRequest.get(sf).execute().body();// 轉(zhuǎn)java對象bili = JSONUtil.toBean(json, BiliBili.class);} else {bili = bilibili;}// 具體評論信息List<BiliBiliReplies> replies = bili.getData().getReplies();replies.forEach(e -> {// 是否取消發(fā)布者的中獎資格,并不了解B站各個字段是否具有對應關系,這里手動寫死if (IS_CANCEL && e.getMid().equals(447485021)) {return;// 跳出本次循環(huán)}String uname = e.getMember().getUname();list.add(uname);List<String> list1 = con.get(uname);if (IterUtil.isEmpty(list1)) {List<String> li = new ArrayList<>();li.add(e.getContent().getMessage() + " (評論所在頁碼:" + a + " )");con.put(uname, li);} else {list1.add(e.getContent().getMessage());}});}// 去除重復,保證每個人只有一次機會中獎,保證中獎幾率對等List<String> collect = list.stream().distinct().collect(Collectors.toList());// 抽獎次數(shù)大于等于評論人數(shù),全部中獎,不需要抽取,人手一個if (COUNT >= collect.size()) {System.out.println("中獎人數(shù)列表: ");for (String userName : collect) {StringBuilder sb = new StringBuilder("中獎用戶名 : ");sb.append(userName);sb.append(" , 評論內(nèi)容為 : [ ");List<String> list1 = con.get(userName);for (int i = 0; i < list1.size(); i++) {sb.append(list1.get(i));// 存在多條評論,用逗號分開if (i != list1.size() - 1) {sb.append(" || ");}}sb.append(" ]");System.out.println(sb.toString());}return;}// 打亂名單,使得中獎相對公平Collections.shuffle(list);// 循環(huán)抽取幸運用戶 ~System.out.println("中獎人數(shù)列表: ");for (int i = 0; i < COUNT; i++) {String userName = collect.remove(new Random().nextInt(collect.size()));StringBuilder sb = new StringBuilder("中獎用戶名 : ");sb.append(userName);sb.append(" , 評論內(nèi)容為 : [ ");List<String> list1 = con.get(userName);for (int j = 0; j < list1.size(); j++) {sb.append(list1.get(j));// 存在多條評論,用 || 分開if (j != list1.size() - 1) {sb.append(" || ");}}sb.append(" ]");System.out.println(sb.toString());// 重新打亂集合Collections.shuffle(collect);}} }### 實現(xiàn)效果(抽取三名)
第一次抽取 :
第二次抽取:
總結
以上是生活随笔為你收集整理的获取B站评论抽奖实现的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 项目-OOP版电子词典
- 下一篇: 【转载】 突破技术瓶颈 GIS从二维到三