用Arduino玩轉掌控板(ESP32):B 站粉絲計數器

眾所周知,掌控板在創客教育中用的非常廣泛,它是一塊基於 ESP32 的學習開發板。大家對掌控板編程,用的比較多的都是圖形化編程的方式,比如 mPython、Mind+ 等。但是,既然掌控板是基於 ESP32 芯片的,所以我們也可以用 Arduino 軟件對其編程。所以,有時間的話,我準備給大家分享一系列用 Arduino 代碼對掌控板(ESP32)編程的教程:**用 Arduino 玩轉掌控板(ESP32)系列**

本期給大家帶來的是:B 粉計數器(B站粉絲計數器)。

用Arduino玩轉掌控板(ESP32):B 站粉絲計數器

前言

如果大家有在玩一些自媒體平臺的話,比如微信公眾號、B站、知乎、抖音等,那麼相信大家對自己的粉絲數、閱讀數或者播放量等相關的數據會比較關注,但是每次手動去查看又比較麻煩。

那麼有沒有簡單一些的方法呢?在創客技術宅眼裡,萬物皆可自動化!

今天就以 B 站為例,手把手教大家做一個桌面 B 站粉絲計數器!為什麼是 B 站呢?~~因為 B 站做起來最簡單啊……(哭……)~~

先來看一下效果,我用 Arduino 軟件分別將程序上傳至掌控板(ESP32)和 NodeMCU(ESP8266),看到的效果基本是一樣的。本來還想做個外殼的,無奈被疫情隔離在家,設備不多,只能做個簡易版了,大家將就看看吧。

用Arduino玩轉掌控板(ESP32):B 站粉絲計數器

用Arduino玩轉掌控板(ESP32):B 站粉絲計數器

納尼!粉絲數竟然那麼少!丟臉丟臉,還不趕緊三連支持一下嘍~

~~幹啥啥不行,騙粉第一名!~~

下面開始正式教程。

獲取 B 站 API

首先用**谷歌瀏覽器(推薦)**打開 B 站個人主頁,如下圖所示,重點關注我圈出來的幾個地方,分別是:關注數、粉絲數、點贊數、播放分數,這幾個數據的含義,大家一看就明白了,就不解釋了。另外還要關注右下角的 UID,這是一串數字,在 B 站中就是你的唯一 ID,這個數字很重要,後面會用到。

用Arduino玩轉掌控板(ESP32):B 站粉絲計數器

然後在鍵盤上按下 `F12` 或者 `Ctrl+Shift+I` 進入瀏覽器調試模式,刷新一下 B 站個人主頁,然後就會在 Network(網絡)標籤頁下看到一堆返回的數據,從中我們可以看到數據請求的方法(比如 GET),以及對應的 Domain(網址域名)。這裡我們要重點關注幾行數據,那就是 Domain 為 `api.bilibili.com` 的幾行,下圖中我已經圈出來了。

用Arduino玩轉掌控板(ESP32):B 站粉絲計數器

我們逐一點進去排查,切換到 Response 標籤頁,在這裡我們看到了 2 個熟悉的數據:following(102)和 follower(133),這不正是我們在 B 站個人主頁看到的我的關注數(102)和粉絲數(133)麼?

用Arduino玩轉掌控板(ESP32):B 站粉絲計數器

我們在切換到 Headers 標籤頁,看到請求的網址(Request URL)如下,請求方法為 GET。

用Arduino玩轉掌控板(ESP32):B 站粉絲計數器

我們將這個網址複製出來觀察一下:

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 格式的。

用Arduino玩轉掌控板(ESP32):B 站粉絲計數器

我們將這些數據格式化一下,方便我們查看。這裡使用了 VS Code,或者你也可以使用網上其他的 JSON 在線格式化工具,這裡不展開了。

用Arduino玩轉掌控板(ESP32):B 站粉絲計數器

同樣的方法,我們去查一下播放數和獲贊數在哪裡可以查到。

相信你很快就找到了,如下圖所示,先找到數據位置:

用Arduino玩轉掌控板(ESP32):B 站粉絲計數器

再查看相應的 API 網址:

https://api.bilibili.com/x/space/upstat?mid=224425204&jsonp=jsonp&callback=__jp5

用Arduino玩轉掌控板(ESP32):B 站粉絲計數器

將末尾無關參數刪除後:

https://api.bilibili.com/x/space/upstat?mid=224425204

然後再將這個網址在瀏覽器中打開,我們就看到了熟悉的播放數(view:9047)和獲贊數(likes:57)。

用Arduino玩轉掌控板(ESP32):B 站粉絲計數器

在 VS Code 中將數據格式化,方便查看。

用Arduino玩轉掌控板(ESP32):B 站粉絲計數器

代碼編寫

### 聯網設置

要去獲取 B 站的數據,當然要聯網啦。我們在程序的最開頭,引入一堆聯網相關的頭文件。這裡有一個比較特殊的地方,就是我們同時引入了 ESP32 和 ESP8266 對應的頭文件,這樣在編譯程序的時候,就會根據所選擇的的開發板,自動編譯對應部分,而不會報錯,做到了一套程序兼容兩種開發板(ESP32 和 ESP8266)的目的。

<code>#if defined(ESP32)

#include <wifi.h>

#include <httpclient.h>

#elif defined(ESP8266)

#include <esp8266wifi.h>

#include <esp8266httpclient.h>

#else

#error "Please check your mode setting,it must be esp8266 or esp32."

#endif

#include <wire.h>

// Wi-Fi

const 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()

{

}/<wire.h>/<esp8266httpclient.h>/<esp8266wifi.h>/<httpclient.h>/<wifi.h>/<code>

既然要聯網,就需要定義你的網絡名稱和密碼,對應修改就行:

<code>const char *ssid = "wifi_name";
const char *password = "wifi_password";/<code>

上面連接 Wi-Fi 的程序,就不展開了,基本是標準寫法,在 `WiFi` 這個庫裡,找一下例程複製一下就行。

### 獲取粉絲數

連接上網絡之後,就可以去獲取粉絲數了,除了上面已經引入的頭文件 `HTTPClient`,這個庫文件可以用來獲取網站上的數據。我們還需要用到的 `ArduinoJson` 這個 JSON 解析庫,可以用來解析網站返回的 JSON 數據,並且初始化一個 JSON 解析對象 jsonBuffer。

> ArduinoJson 目前比較流行的有兩個版本:V5 和 V6,V5 比較經典和穩定,V6 比較新。兩個版本使用起來稍有差異,博主這裡使用的是 V5 版本。

<code>#include <arduinojson.h>
DynamicJsonBuffer jsonBuffer(256); // ArduinoJson V5/<arduinojson.h>/<code>

另外,我們還需要定義 API 的網址、以及初始化粉絲數,單獨拎出來是方便大家修改。注意,這裡我們網址的訪問方式為 http,而不是 https,因為 https 的話,代碼會複雜一些。

<code>// bilibili api: follower, view, likes
String UID = "224425204";
String followerUrl = "http://api.bilibili.com/x/relation/stat?vmid=" + UID; // 粉絲數
long follower = 0; // 粉絲數/<code>

然後再寫一個獲取粉絲數的函數 getFollower(String url),只要傳入對應的 API 網址,就能利用 HTTPClient 中的 GET 方法,獲取相應的數據,然後再用 ArduinoJson 庫進行解析。

<code>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();

}/<code>

最後再在 setup() 中調用一下,看看效果:

<code>void setup()

{

// other setup codes ...

getFollower(followerUrl);

}/<code>

打開 Arduino 串口監視器,返回數據正常,說明成功了。

用Arduino玩轉掌控板(ESP32):B 站粉絲計數器

### 獲取播放數與獲贊數

這個與獲取粉絲數的原理一樣,不再贅述,直接看代碼:

<code>// bilibili api: follower, view, likes

String 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();

}/<code>

打開 Arduino 串口監視器,返回數據正常,說明成功了。

用Arduino玩轉掌控板(ESP32):B 站粉絲計數器

### OLED屏:數據顯示

獲取到數據之後,我們總不能一直在串口監視器裡面查看吧,所以我們利用一個 OLED 12864 屏幕,將數據顯示到屏幕上。代碼如下:

```cpp

#include <u8g2lib.h>

// 1.3' OLED12864

U8G2_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() 中調用,看看顯示效果。

![掌控板顯示效果](images/掌控板顯示效果.jpg)

### 定時器:定時獲取數據

有了前面的步驟,我們已經可以正常獲取數據並且顯示數據了,但是你們可能會問:為什麼前面調試時把獲取數據的函數放在 setup() 中呢?而不是 loop() 中呢?這樣每次程序開機只能讀取一次,豈不是太麻煩了?放在 loop() 不就可以不斷讀取並且更新了麼?

不是這樣的,如果我們放在 loop() 中,不做其他干預,不斷去讀取的話,就會由於訪問頻率太高,觸發 B 站的保護機制。不信你就不斷刷新 B 站的某個 API 地址試試,相信你一定會看到如下“該頁面無法訪問”的頁面。

![無法訪問](images/無法訪問.png)

所以呢,我們就需要定時器,隔一段時間去獲取一次數據,而且我們也不是大 V,數據變化不會很快,所以每隔 10 分鐘去獲取一次數據就綽綽有餘了。直接看代碼:

```cpp

#include <ticker.h>

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站粉絲計數器就製作完成了,最終效果,大家可以在文章開頭看一看。

## 附:掌控板 mPython 圖形化程序

![mPython圖形化程序](images/mPython圖形化程序.png)

## 代碼下載

關注本公眾號“鐵熊玩創客”,回覆“B站”獲取完整代碼,三連支持一下嘍。

![公眾號二維碼](https://ironpanda-1259781115.cos.ap-shanghai.myqcloud.com/2020-02-07/gong-zhong-hao-er-wei-ma.jpg)


分享到:


相關文章: