
衆所周知,掌控闆在創客教育中用的非常廣泛,它是一塊基于 ESP32 的學習開發闆。大家對掌控闆程式設計,用的比較多的都是圖形化程式設計的方式,比如 mPython、Mind+ 等。但是,既然掌控闆是基于 ESP32 晶片的,是以我們也可以用 Arduino 軟體對其程式設計。是以,有時間的話,我準備給大家分享一系列用 Arduino 代碼對掌控闆(ESP32)程式設計的教程:用 Arduino 玩轉掌控版(ESP32)系列
本期給大家帶來的是:B 粉計數器(B站粉絲計數器)。
# 前言
如果大家有在玩一些自媒體平台的話,比如微信公衆号、B站、知乎、抖音等,那麼相信大家對自己的粉絲數、閱讀數或者播放量等相關的資料會比較關注,但是每次手動去檢視又比較麻煩。
那麼有沒有簡單一些的方法呢?在創客技術宅眼裡,萬物皆可自動化!
今天就以 B 站為例,手把手教大家做一個桌面 B 站粉絲計數器!為什麼是 B 站呢?因為 B 站做起來最簡單啊……(哭……)
先來看一下效果,我用 Arduino 軟體分别将程式上傳至掌控闆(ESP32)和 NodeMCU(ESP8266),看到的效果基本是一樣的。本來還想做個外殼的,無奈被疫情隔離在家,裝置不多,隻能做個簡易版了,大家将就看看吧。
掌控闆(ESP32)顯示效果
NodeMCU(ESP8266)顯示效果
納尼!粉絲數竟然那麼少!丢臉丢臉,還不趕緊三連支援一下喽~
幹啥啥不行,騙粉第一名!
下面開始正式教程。
# 擷取 B 站 API
首先用谷歌浏覽器(推薦)打開 B 站個人首頁,如下圖所示,重點關注我圈出來的幾個地方,分别是:關注數、粉絲數、點贊數、播放分數,這幾個資料的含義,大家一看就明白了,就不解釋了。另外還要關注右下角的 UID,這是一串數字,在 B 站中就是你的唯一 ID,這個數字很重要,後面會用到。
然後在鍵盤上按下
F12
或者
Ctrl+Shift+I
進入浏覽器調試模式,重新整理一下 B 站個人首頁,然後就會在 Network(網絡)标簽頁下看到一堆傳回的資料,從中我們可以看到資料請求的方法(比如 GET),以及對應的 Domain(網址域名)。這裡我們要重點關注幾行資料,那就是 Domain 為
api.bilibili.com
的幾行,下圖中我已經圈出來了。
我們逐一點進去排查,切換到 Response 标簽頁,在這裡我們看到了 2 個熟悉的資料:following(102)和 follower(133),這不正是我們在 B 站個人首頁看到的我的關注數(102)和粉絲數(133)麼?
我們在切換到 Headers 标簽頁,看到請求的網址(Request URL)如下,請求方法為 GET。
我們将這個網址複制出來觀察一下:
https://api.bilibili.com/x/relation/stat?vmid=224425204&jsonp=jsonp&callback=__jp4
其中有一段
vmid=224425204
,這後面的數字,不正是我們前面提到的 UID 麼?後面的 jsonp、callback 應該是對應的一些回調函數,我們将這些删除,隻保留前面部分:
https://api.bilibili.com/x/relation/stat?vmid=224425204
并将它複制到浏覽器位址欄去通路一下,看到什麼了?是不是隻留下一堆最簡單的資料,裡面包含了我們的關注數與粉絲數?而且這對資料是 JSON 格式的。
我們将這些資料格式化一下,友善我們檢視。這裡使用了 VS Code,或者你也可以使用網上其他的 JSON 線上格式化工具,這裡不展開了。
同樣的方法,我們去查一下播放數和獲贊數在哪裡可以查到。
相信你很快就找到了,如下圖所示,先找到資料位置:
再檢視相應的 API 網址:
https://api.bilibili.com/x/space/upstat?mid=224425204&jsonp=jsonp&callback=__jp5
将末尾無關參數删除後:
https://api.bilibili.com/x/space/upstat?mid=224425204
然後再将這個網址在浏覽器中打開,我們就看到了熟悉的播放數(view:9047)和獲贊數(likes:57)。
在 VS Code 中将資料格式化,友善檢視。
# 代碼編寫
## 聯網設定
要去擷取 B 站的資料,當然要聯網啦。我們在程式的最開頭,引入一堆聯網相關的頭檔案。這裡有一個比較特殊的地方,就是我們同時引入了 ESP32 和 ESP8266 對應的頭檔案,這樣在編譯程式的時候,就會根據所選擇的的開發闆,自動編譯對應部分,而不會報錯,做到了一套程式相容兩種開發闆(ESP32 和 ESP8266)的目的。
#if defined(ESP32) #include #include #elif defined(ESP8266) #include #include #else #error "Please check your mode setting,it must be esp8266 or esp32."#endif#include // Wi-Ficonst char *ssid = "wifi_name";const char *password = "wifi_password";void setup(){ Serial.begin(115200); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); Serial.println("WiFi connected");}void loop(){}
既然要聯網,就需要定義你的網絡名稱和密碼,對應修改就行:
const char *ssid = "wifi_name";const char *password = "wifi_password";
上面連接配接 Wi-Fi 的程式,就不展開了,基本是标準寫法,在
WiFi
這個庫裡,找一下例程複制一下就行。
## 擷取粉絲數
連接配接上網絡之後,就可以去擷取粉絲數了,除了上面已經引入的頭檔案
HTTPClient
,這個庫檔案可以用來擷取網站上的資料。我們還需要用到的
ArduinoJson
這個 JSON 解析庫,可以用來解析網站傳回的 JSON 資料,并且初始化一個 JSON 解析對象 jsonBuffer。
ArduinoJson 目前比較流行的有兩個版本:V5 和 V6,V5 比較經典和穩定,V6 比較新。兩個版本使用起來稍有差異,部落客這裡使用的是 V5 版本。
#include DynamicJsonBuffer jsonBuffer(256); // ArduinoJson V5
另外,我們還需要定義 API 的網址、以及初始化粉絲數,單獨拎出來是友善大家修改。注意,這裡我們網址的通路方式為 http,而不是 https,因為 https 的話,代碼會複雜一些。
// bilibili api: follower, view, likesString UID = "224425204";String followerUrl = "http://api.bilibili.com/x/relation/stat?vmid=" + UID; // 粉絲數long follower = 0; // 粉絲數
然後再寫一個擷取粉絲數的函數 getFollower(String url),隻要傳入對應的 API 網址,就能利用 HTTPClient 中的 GET 方法,擷取相應的資料,然後再用 ArduinoJson 庫進行解析。
void getFollower(String url){ HTTPClient http; http.begin(url); int httpCode = http.GET(); Serial.printf("[HTTP] GET... code: %d\n", httpCode); if (httpCode == 200) { Serial.println("Get OK"); String resBuff = http.getString(); // ---------- ArduinoJson V5 ---------- JsonObject &root = jsonBuffer.parseObject(resBuff); if (!root.success()) { Serial.println("parseObject() failed"); return; } follower = root["data"]["follower"]; Serial.print("Fans: "); Serial.println(follower); } else { Serial.printf("[HTTP] GET... failed, error: %d\n", httpCode); } http.end();}
最後再在 setup() 中調用一下,看看效果:
void setup(){ // other setup codes ... getFollower(followerUrl);}
打開 Arduino 序列槽螢幕,傳回資料正常,說明成功了。
## 擷取播放數與獲贊數
這個與擷取粉絲數的原理一樣,不再贅述,直接看代碼:
// bilibili api: follower, view, likesString UID = "224425204";String followerUrl = "http://api.bilibili.com/x/relation/stat?vmid=" + UID; // 粉絲數String viewAndLikesUrl = "http://api.bilibili.com/x/space/upstat?mid=" + UID; // 播放數、點贊數long follower = 0; // 粉絲數long view = 0; // 播放數long likes = 0; // 獲贊數void setup(){ // other setup codes ... getFollower(followerUrl); getViewAndLikes(viewAndLikesUrl);}void getViewAndLikes(String url){ HTTPClient http; http.begin(url); int httpCode = http.GET(); Serial.printf("[HTTP] GET... code: %d\n", httpCode); if (httpCode == 200) { Serial.println("Get OK"); String resBuff = http.getString(); // ---------- ArduinoJson V5 ---------- JsonObject &root = jsonBuffer.parseObject(resBuff); if (!root.success()) { Serial.println("parseObject() failed"); return; } likes = root["data"]["likes"]; view = root["data"]["archive"]["view"]; Serial.print("Likes: "); Serial.println(likes); Serial.print("View: "); Serial.println(view); } else { Serial.printf("[HTTP] GET... failed, error: %d\n", httpCode); } http.end();}
打開 Arduino 序列槽螢幕,傳回資料正常,說明成功了。
## OLED屏:資料顯示
擷取到資料之後,我們總不能一直在序列槽螢幕裡面檢視吧,是以我們利用一個 OLED 12864 螢幕,将資料顯示到螢幕上。代碼如下:
#include // 1.3' OLED12864U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE);// 0.96' OLED12864//U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE);void setup(){ // other setup codes ... u8g2.begin(); u8g2.enableUTF8Print(); u8g2.setFont(u8g2_font_wqy12_t_gb2312b); u8g2.setFontPosTop(); u8g2.clearDisplay();}void loop(){ u8g2.firstPage(); do { display(follower, likes, view); } while (u8g2.nextPage());}void display(long follower, long likes, long view){ u8g2.clearDisplay(); u8g2.setCursor(5, 2); u8g2.print("B站粉絲計數器"); u8g2.setCursor(5, 20); u8g2.print("粉絲數:" + String(follower)); u8g2.setCursor(5, 36); u8g2.print("獲贊數:" + String(likes)); u8g2.setCursor(5, 52); u8g2.print("播放數:" + String(view));}
這裡我們用到了 u8g2 庫,它是專門用來控制各種顯示屏的。在 setup() 中設定了相應的顯示參數,定義了一個顯示函數 display(long follower, long likes, long view),可以同時傳入相應的資料,并顯示出來。然後在 loop() 中調用,看看顯示效果。
## 定時器:定時擷取資料
有了前面的步驟,我們已經可以正常擷取資料并且顯示資料了,但是你們可能會問:為什麼前面調試時把擷取資料的函數放在 setup() 中呢?而不是 loop() 中呢?這樣每次程式開機隻能讀取一次,豈不是太麻煩了?放在 loop() 不就可以不斷讀取并且更新了麼?
不是這樣的,如果我們放在 loop() 中,不做其他幹預,不斷去讀取的話,就會由于通路頻率太高,觸發 B 站的保護機制。不信你就不斷重新整理 B 站的某個 API 位址試試,相信你一定會看到如下“該頁面無法通路”的頁面。
無法通路
是以呢,我們就需要定時器,隔一段時間去擷取一次資料,而且我們也不是大 V,資料變化不會很快,是以每隔 10 分鐘去擷取一次資料就綽綽有餘了。直接看代碼:
#include Ticker timer;int count = 0;boolean flag = true;void setup(){ // other setup codes ... timer.attach(600, timerCallback); // 每隔10min}void loop(){ while (flag) { if (count == 0) { // display data Serial.println("count = 0, display data"); u8g2.firstPage(); do { display(follower, likes, view); } while (u8g2.nextPage()); flag = false; } else if (count == 1) { // get follower Serial.println("count = 1, get follower"); getFollower(followerUrl); flag = false; } else if (count == 2) { // get view and likes Serial.println("count = 2, get view and likes"); getViewAndLikes(viewAndLikesUrl); flag = false; } }}void timerCallback(){ count++; if (count == 3) { count = 0; } flag = true;}
我們使用了 ESP32 和 ESP8266 自帶的定時器庫 Ticker。設定一個 count 變量,根據 count = 0、1、2 分别做不同的工作:顯示屏重新整理資料、讀取粉絲數、讀取播放數和獲贊數。用 flag 變量去标記是否執行相應的功能。這兩個參數在定時器回調函數 timerCallback() 每隔 10 分鐘就會改變一次,然後就會在 loop() 中觸發相應的功能。
至此,B站粉絲計數器就制作完成了,最終效果,大家可以在文章開頭看一看。
# 附:掌控闆圖形程式
# 代碼下載下傳
關注本公衆号“鐵熊玩創客”,回複“B站”擷取完整代碼,三連支援一下喽。
# 相關推薦
## 51maker 微信公衆号
51maker 是由一群教師團隊維護的微信公衆号,他們來自全國五湖四海,緻力于 Scratch 程式設計及創客入門課程開發,為一線教師提供微視訊、課件、教學設計等相關資源,為普及程式設計 & 創客教育盡一份力量。
## 知識星球能量站
激活課程制作分享,實作知識變現!能量站是一個付費知識社群,聚集了一大批優秀的老師,幾乎每天都有優質的創客教育内容分享。可以掃描下方二維碼付費加入,這是我的推薦碼,你可以獲得一定的優惠,當然我也會有一定的回報。
*歡迎轉發朋友圈。如需轉載,請注明出處和原作者。
掃描二維碼
關注鐵熊吧▼往期精彩内容▼創客項目缺少高顔值電路圖?看這裡就對了小白也能學會的雷射切割創意盒子設計方法還在羨慕大疆 S1?教你自制麥輪戰車萌寵Pando機器人,不但能賣萌,還能跳太空步學生獲獎作品:戒煙帽學生獲獎作品:體感轉向安全帽掌控+Mixly+Blynk,讓你的麥輪戰甲嗨炸全場搞定掌控闆Siri語音控制,隻要半小時
我知道你在看呦