點贊再看,動力無限。Hello world : ) 微信搜「 程序猿阿朗 」。
本文 Github.com/niumoo/JavaNotes 和 未讀代碼博客 已經收錄,有很多知識點和系列文章。
如何白嫖 Github 服務器自動抓取必應搜索的每日壁紙呢?
如果你訪問過必應搜索網站,那么你一定會被搜索頁面的壁紙吸引,必應搜索的壁紙每日不同,自動更換,十分精美。這篇文章會介紹如何一步步分析出必應搜索壁紙 API ,如何結合 Github Actions自動抓取每日必應壁紙到 Github 倉庫。
元宵節當天具有中國元素的必應搜索。
平常一天的必應搜索。
分析必應壁紙 API
既然是網站上的背景,又是每天更換,很大概率是通過某個 API 請求返回壁紙信息的,事實真是如此嗎?直接打開瀏覽器 network 控制台監控網絡請求信息。
篩選 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 ,那么就不難寫一個自動爬取當天必應壁紙的自動化程序。
- 請求必應壁紙 API。
- 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 可以執行多種常見環境的程序,而且可以定時觸發,免費好用,實在是妙,心中默默的也為微軟豎起了大拇指。
下面會簡單介紹一下 Github Actions 的使用,更多的關於 Github Actions 的概念和使用的場景就不介紹了,我們只要知道利用 Github Actions 功能,可以讓我們在指定的事件觸發(代碼提交事件或者定時或者其他)時,可以運行指定的程序就好了。
如果想了解更多的相關資料,可以直接參考 Github Actions 官方文檔,也可以參考其他的相關中文教程,鏈接這里已經放在文章末尾了。
Github Actions 體驗
在 Github 倉庫頁面的 Actions 頁簽下可以創建 Github Actions 配置,這里創建一個官方提供的簡單示例進行演示。
創建后可以得到一個官方編寫好的 Actions Demo,功能就是輸出幾個字符串。
簡單介紹一下圖中 Actions 配置文件中的的一些概念。
on
指定此 Actions 的觸發機制,這里的push
和pull_request
說明在代碼提交和代碼合並時會觸發。jobs
代表一個任務,一個 Actions workflows 可以有多個jobs
構成。runs-on
指定運行 Actions 的系統環境,這里是ubuntu
.steps
代表當前jobs
任務的執行步驟。示例里先檢出了倉庫,然后echo
了幾個字符串。
保存提交這個文件到倉庫,因為配置里配置了觸發機制有 push
,所以這時也會觸發這個任務。
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
可以看到執行步驟。
- 檢出代碼。
- 設置 Java 環境為 JDK 1.8.
- maven 編譯打包。
- 運行打包后的 Java 程序(程序中把獲取到的壁紙寫入到了 README.md 文件)。
- 提交文件到 Github 倉庫。
配置中最后還使用了一個參數 {{ secrets.MY_GIT_TOKEN }}
,這是一個用於識別是否有提交 Github權限的密文,這個密文可以在 Github 網站 -> 點擊頭像 -> Settings -> Developer settings -> Personal access tokens 這里創建,或者直接訪問 https://github.com/settings/tokens/new 創建,創建時勾選 repo
權限。保存后可以得到你的密文。
復制這串密文,配置到自己創建 Actions 的倉庫。
至此,倉庫和配置都已經完成,每天自動抓取必應首頁壁紙寫入到 README.md 文件,下圖是抓取的效果。
Github 倉庫地址:https://github.com/niumoo/bing-wallpaper 。
參考
[1] https://docs.github.com/en/actions/quickstart
[2] https://github.com/niumoo/bing-wallpaper
訂閱
<完>
Hello world : ) 我是阿朗,一線技術工具人,認認真真寫文章。
點贊的個個都是人才,不僅長得帥氣好看,說話還好聽。
文章持續更新,可以關注公眾號「 程序猿阿朗 」或訪問「未讀代碼博客 」。
回復【資料】有我准備的各系列知識點和必看書籍。
本文 Github.com/niumoo/JavaNotes 已經收錄,有很多知識點和系列文章,歡迎Star。