如何使用 Github Actions 自動抓取每日必應桌布?

未讀程式碼發表於2021-03-03

如何白嫖 Github 伺服器自動抓取必應搜尋的每日桌布呢?

如果你訪問過必應搜尋網站,那麼你一定會被搜尋頁面的桌布吸引,必應搜尋的桌布每日不同,自動更換,十分精美。這篇文章會介紹如何一步步分析出必應搜尋桌布 API ,如何結合 Github Actions自動抓取每日必應桌布到 Github 倉庫。

元宵節當天具有中國元素的必應搜尋。

必應搜尋主頁

平常一天的必應搜尋。

必應首頁

分析必應桌布 API

既然是網站上的背景,又是每天更換,很大概率是通過某個 API 請求返回桌布資訊的,事實真是如此嗎?直接開啟瀏覽器 network 控制檯監控網路請求資訊。

分析必應桌布API

篩選 XHR 非同步請求,排除 js 檔案載入請求後,在一個路徑為 HPImageArchive.aspx 的請求中,發現響應的資訊似乎和背景圖片有關,直接複製出請求的 URL ,得到了一個似乎是桌布 API 的介面。

https://cn.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1&nc=1614319565639&pid=hp&FORM=BEHPTB&uhd=1&uhdwidth=3840&uhdheight=2160

這個介面返回的資訊到底是不是頁面上的圖片資訊呢?還需要進一步測試,單獨請求分析這個介面,分析其中的響應資訊。

➜  ~ curl https://cn.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1&nc=1614319565639&pid=hp&FORM=BEHPTB&uhd=1&uhdwidth=3840&uhdheight=2160
{
  "images": [
    {
      "startdate": "20210225",
      "fullstartdate": "202102251600",
      "enddate": "20210226",
      "url": "/th?id=OHR.JinliStreet_ZH-CN3020276206_UHD.jpg&rf=LaDigue_UHD.jpg&pid=hp&w=3840&h=2160&rs=1&c=4",
      "urlbase": "/th?id=OHR.JinliStreet_ZH-CN3020276206",
      "copyright": "掛在錦裡街上的紅燈籠,中國成都 (© Philippe LEJEANVRE/Getty Images)",
      "copyrightlink": "/search?q=%e9%94%a6%e9%87%8c%e8%a1%97&form=hpcapt&mkt=zh-cn",
      "title": "",
      "quiz": "/search?q=Bing+homepage+quiz&filters=WQOskey:%22HPQuiz_20210225_JinliStreet%22&FORM=HPQUIZ",
      "wp": true,
      "hsh": "e9b5fb1ad61034342e8d459bff8fc5c5",
      "drk": 1,
      "top": 1,
      "bot": 1,
      "hs": []
    }
  ],
  "tooltips": {
    "loading": "正在載入...",
    "previous": "上一個影像",
    "next": "下一個影像",
    "walle": "此圖片不能下載用作桌布。",
    "walls": "下載今日美圖。僅限用作桌面桌布。"
  }
}
➜  ~

可以看到返回的結果中有 URL 資訊,拼接到必應網址訪問測試(其實通過響應資訊裡的圖片描述 ”掛在錦裡街上的紅燈籠,中國成都“ 就已經猜到大概率是了,今日元宵節)。

https://bing.com/th?id=OHR.JinliStreet_ZH-CN3020276206_UHD.jpg&rf=LaDigue_UHD.jpg&pid=hp&w=3840&h=2160&rs=1&c=4

訪問後發現就是必應搜尋網站的當日桌布(元宵節必應放了一張紅色燈籠桌布)。

元宵節

到這裡,我們已經找到了必應搜尋桌布的 API 介面和響應資訊中的圖片地址。如果再看圖片的 URL 地址,其中攜帶了不少引數,這些引數是什麼意思呢?可以大膽猜測,其中的引數 w=3840&h=2160 應該是指圖片的寬和高,確實是這樣,調整這兩個引數可以返回不同解析度的圖片,如果沒有這兩個引數就可以返回超清原圖。

必應桌布爬蟲

上面分析出了必應桌布的 API ,那麼就不難寫一個自動爬取當天必應桌布的自動化程式。

  1. 請求必應桌布 API。
  2. JSON 解析出圖片 URL。

這裡網路請求使用 Java 原生寫法,JSON 解析使用了 FASTJSON ,程式碼簡單直接放上來了。

/**
 * <p>
 * 網路請求操作工具類
 *
 * @author niujinpeng
 * @link https://github.com/niumoo
 */
public class HttpUtls {

    /**
     * 獲取 HTTP 連線
     *
     * @param url
     * @return
     * @throws IOException
     */
    public static HttpURLConnection getHttpUrlConnection(String url) throws IOException {
        URL httpUrl = new URL(url);
        HttpURLConnection httpConnection = (HttpURLConnection)httpUrl.openConnection();
        httpConnection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36");
        return httpConnection;
    }

    /**
     * 請求指定 URL 的內容
     *
     * @param url
     * @return
     * @throws IOException
     */
    public static String getHttpContent(String url) throws IOException {
        HttpURLConnection httpUrlConnection = getHttpUrlConnection(url);
        StringBuilder stringBuilder = new StringBuilder();
        // 獲得輸入流
        try (InputStream input = httpUrlConnection.getInputStream(); BufferedInputStream bis = new BufferedInputStream(
            input);) {
            byte[] buffer = new byte[1024];
            int len = -1;
            // 讀到檔案末尾則返回-1
            while ((len = bis.read(buffer)) != -1) {
                stringBuilder.append(new String(buffer, 0, len));
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            httpUrlConnection.disconnect();
        }
        return stringBuilder.toString();
    }

}

如果覺得 Java 原生網路請求寫法繁瑣,也可以使用 OkHTTP 進行請求。請求到響應結果之後,使用 FASTJSON 解析響應的結果。

/**
 * @author niujinpeng
 * @link https://github.com/niumoo
 */
public class Wallpaper {

    // BING API
    private static String BING_API = "https://cn.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1&nc=1612409408851&pid=hp&FORM=BEHPTB&uhd=1&uhdwidth=3840&uhdheight=2160";

    private static String BING_URL = "https://cn.bing.com";

    public static void main(String[] args) throws IOException {
        String httpContent = HttpUtls.getHttpContent(BING_API);
        JSONObject jsonObject = JSON.parseObject(httpContent);
        JSONArray jsonArray = jsonObject.getJSONArray("images");

        // 圖片地址
        String url = BING_URL + (String)jsonArray.getJSONObject(0).get("url");
        url = url.substring(0, url.indexOf("&"));

        // 圖片時間
        String enddate = (String)jsonArray.getJSONObject(0).get("enddate");

        // 圖片版權
        String copyright = (String)jsonArray.getJSONObject(0).get("copyright");

        // 格式化為 MD 格式
        String text = String.format("%s | [%s](%s) ", enddate, copyright, url) + System.lineSeparator();
        System.out.println(text);
      
        // 寫入 MD 檔案
        Path path = Paths.get("README.md");
        if (!Files.exists(path)) {
            Files.createFile(path);
        }
        List<String> allLines = Files.readAllLines(path);
        allLines.set(0, text);
        Files.write(path, "## Bing Wallpaper".getBytes());
        Files.write(path, System.lineSeparator().getBytes(), StandardOpenOption.APPEND);
        Files.write(path, allLines, StandardOpenOption.APPEND);
    }
}

執行之後就可以得到必應網站當天的桌布資訊。

20210226 | [掛在錦裡街上的紅燈籠,中國成都 (© Philippe LEJEANVRE/Getty Images)](https://cn.bing.com/th?id=OHR.JinliStreet_ZH-CN3020276206_UHD.jpg) 

Github Actions

如果我們想要收集每天的必應桌布,豈不是每天都要執行一次爬蟲程式?這顯然太麻煩了。如果有個定時任務每天自動執行一次,豈不妙哉?但是掛在伺服器上還需要購買一臺虛擬主機,實在得不償失。

這時機智的我突然想到何不利用 Github Actions 功能呢?Github Actions 可以執行多種常見環境的程式,而且可以定時觸發,免費好用,實在是妙,心中默默的也為微軟豎起了大拇指。

img

下面會簡單介紹一下 Github Actions 的使用,更多的關於 Github Actions 的概念和使用的場景就不介紹了,我們只要知道利用 Github Actions 功能,可以讓我們在指定的事件觸發(程式碼提交事件或者定時或者其他)時,可以執行指定的程式就好了。

如果想了解更多的相關資料,可以直接參考 Github Actions 官方文件,也可以參考其他的相關中文教程,連結這裡已經放在文章末尾了。

Github Actions 體驗

在 Github 倉庫頁面的 Actions 頁簽下可以建立 Github Actions 配置,這裡建立一個官方提供的簡單示例進行演示。

Github Actions

建立後可以得到一個官方編寫好的 Actions Demo,功能就是輸出幾個字串。

GitHub Actions

簡單介紹一下圖中 Actions 配置檔案中的的一些概念。

  1. on 指定此 Actions 的觸發機制,這裡的 pushpull_request 說明在程式碼提交和程式碼合併時會觸發。
  2. jobs 代表一個任務,一個 Actions workflows 可以有多個 jobs 構成。
  3. runs-on 指定執行 Actions 的系統環境,這裡是 ubuntu.
  4. steps 代表當前 jobs 任務的執行步驟。示例裡先檢出了倉庫,然後echo 了幾個字串。

儲存提交這個檔案到倉庫,因為配置裡配置了觸發機制有 push,所以這時也會觸發這個任務。

Github Actions

Github Actions 定時抓取必應桌布

已經簡單體驗了 Github Actions 的使用方式,還記得我們上面編寫了一個簡單的必應桌布 Java 版爬蟲嗎?如果我們把爬蟲程式碼提交到倉庫,然後使用 Github Actions 功能定時檢出倉庫執行 Java 程式碼抓取桌布,再寫入桌布到倉庫,一套下來無伺服器零成本豈不是很好?

先直接附上寫好的 Github 倉庫地址:https://github.com/niumoo/bing-wallpaper ,已經可以每天自動抓取當天必應桌布。

下面是關於 Actions 內容的一些說明。

# This workflow will build a Java project with Maven
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven

name: Java CI with Maven
on:
  schedule:
    # 定時執行,Runs at 17:00 UTC every day
    - cron:  '0 17 * * *'
    
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    - name: Set up JDK 1.8
      uses: actions/setup-java@v1
      with:
        java-version: 1.8
    - name: Build with Maven
      run: mvn -B package --file pom.xml
    - name: Run Java Application
      run: java -jar target/bing-wallpaper-jar-with-dependencies.jar
    - name: Commit files
      run: |
         git config --local user.email "your_github_email@126.com"
         git config --local user.name "your_github_name"
         git add README.md
         git commit -m "update readme.md"
    - name: Push changes
      uses:  ad-m/github-push-action@master
      with:
         github_token: ${{ secrets.MY_GIT_TOKEN }}
         branch: main

配置中定時在每天 UTC 時間 17 點執行一次,從 steps 可以看到執行步驟。

  1. 檢出程式碼。
  2. 設定 Java 環境為 JDK 1.8.
  3. maven 編譯打包。
  4. 執行打包後的 Java 程式(程式中把獲取到的桌布寫入到了 README.md 檔案)。
  5. 提交檔案到 Github 倉庫。

配置中最後還使用了一個引數 {{ secrets.MY_GIT_TOKEN }} ,這是一個用於識別是否有提交 Github許可權的密文,這個密文可以在 Github 網站 -> 點選頭像 -> Settings -> Developer settings -> Personal access tokens 這裡建立,或者直接訪問 https://github.com/settings/tokens/new 建立,建立時勾選 repo 許可權。儲存後可以得到你的密文。

Github personal access tokens

複製這串密文,配置到自己建立 Actions 的倉庫。

Github Actions Secrets

至此,倉庫和配置都已經完成,每天自動抓取必應首頁桌布寫入到 README.md 檔案,下圖是抓取的效果。

bing-wallpaper

Github 倉庫地址:https://github.com/niumoo/bing-wallpaper

參考

[1] https://docs.github.com/en/actions/quickstart

[2] https://github.com/niumoo/bing-wallpaper

訂閱

文章已經收錄到 github.com/niumoo/javaNotes

可以關注未讀程式碼部落格或者微信搜尋「 未讀程式碼 」。

文章會在部落格和公眾號同步更新。

公眾號

相關文章