1. 程式人生 > >每天定時獲取必應每日一圖並儲存做桌布

每天定時獲取必應每日一圖並儲存做桌布

# 每天定時獲取必應每日一圖並儲存做桌布 ​ 必應每天會更新每日一圖,這些圖片都是特別好看,適合做封面桌布等等。我做了一個自動指令碼,讓它每天定時獲取每日一圖,然後設定為個人主頁部落格的封面,封面和背景一共九張圖片,每天更新後以佇列的順序替換。 ​ 這裡是成品:[個人搭建的部落格主頁](http://vfdxvffd.cn) ## 獲取每日一圖的連結 ### 從介面獲取連結 必應提供了一個獲取每日一圖的介面,[https://cn.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1](https://cn.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1),訪問此介面會返回一個json資料,資料如下: ```json { "images": [ { "startdate":"20201116", "fullstartdate":"202011161600", "enddate":"20201117", "url":"/th?id=OHR.MischwaldFuessen_ZH-CN0005213724_1920x1080.jpg&rf=LaDigue_1920x1080.jpg&pid=hp", "urlbase":"/th?id=OHR.MischwaldFuessen_ZH-CN0005213724", "copyright":"混交林,菲森,巴伐利亞,德國 (© Erich Kuchling/DEEPOL by plainpicture)", "copyrightlink":"https://www.bing.com/search?q=%E6%B7%B7%E4%BA%A4%E6%9E%97&form=hpcapt&mkt=zh-cn", "title":"", "quiz":"/search?q=Bing+homepage+quiz&filters=WQOskey:%22HPQuiz_20201116_MischwaldFuessen%22&FORM=HPQUIZ", "wp":true, "hsh":"8df6576dae2e935290a0f48ff9ab10bb", "drk":1, "top":1, "bot":1, "hs":[] } ], "tooltips":{ "loading":"正在載入...", "previous":"上一個影象", "next":"下一個影象", "walle":"此圖片不能下載用作桌布。", "walls":"下載今日美圖。僅限用作桌面桌布。" } } ``` 上面的json資料中的images中url的value就是當天圖片的地址的一半,還需要新增一個字首[https://www.bing.com/](https://www.bing.com/)或者[http://s.cn.bing.net](http://s.cn.bing.net),兩者選其一,比如今天的圖片完整連結為[https://www.bing.com//th?id=OHR.MischwaldFuessen_ZH-CN0005213724_1920x1080.jpg&rf=LaDigue_1920x1080.jpg&pid=hp](https://www.bing.com//th?id=OHR.MischwaldFuessen_ZH-CN0005213724_1920x1080.jpg&rf=LaDigue_1920x1080.jpg&pid=hp),下載的圖片格式為jpeg。 ![](https://gitee.com/vfdxvffd/blogimage/raw/master/2020-11-17_11-09.png) ### 使用Java得到連結 知道了圖片的連結獲取方法,就寫一個Java程式來獲取它。我們將頁面的json資料一行一行讀取,存入一個字串並返回。 ```java public static String getURLContent(String urlStr) { //請求的url URL url = null; //建立的http連結 HttpURLConnection httpConn = null; //請求的輸入流 BufferedReader in = null; //輸入流的緩衝 StringBuffer sb = new StringBuffer(); try{ url = new URL(urlStr); in = new BufferedReader(new InputStreamReader(url.openStream(),"UTF-8") ); String str = null; //一行一行進行讀入 while((str = in.readLine()) != null) { sb.append( str ); } } catch (Exception ex) { ex.printStackTrace(); } finally{ try{ if(in!=null) { in.close(); //關閉流 } }catch(IOException ex) { ex.printStackTrace(); } } String result =sb.toString(); return result; } ``` 返回值就是上述的json資料的字串形式,然後我們使用阿里的一個處理json資料的庫來簡化操作,在pom.xml檔案中加入下面的依賴: ```xml ``` 利用這個工具將String型別的json資料封裝成一個```JSONObject```,通過呼叫```get(key)```或者```getString(key)```獲取到key對應的value,因為這個json資料裡面有級聯屬性,所以先獲取images對應的value。 ```java //通過該連結先獲取到json資料的字串形式 String urlContent = getURLContent("https://cn.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1"); //將json資料封裝成json物件 JSONObject jsonObject = JSONObject.parseObject(urlContent); // 獲取到key為images的值 String r = jsonObject.getString("images"); ``` 這時候的r字串就是 ```json [ { "startdate":"20201116", "fullstartdate":"202011161600", "enddate":"20201117", "url":"/th?id=OHR.MischwaldFuessen_ZH-CN0005213724_1920x1080.jpg&rf=LaDigue_1920x1080.jpg&pid=hp", "urlbase":"/th?id=OHR.MischwaldFuessen_ZH-CN0005213724", "copyright":"混交林,菲森,巴伐利亞,德國 (© Erich Kuchling/DEEPOL by plainpicture)", "copyrightlink":"https://www.bing.com/search?q=%E6%B7%B7%E4%BA%A4%E6%9E%97&form=hpcapt&mkt=zh-cn", "title":"", "quiz":"/search?q=Bing+homepage+quiz&filters=WQOskey:%22HPQuiz_20201116_MischwaldFuessen%22&FORM=HPQUIZ", "wp":true, "hsh":"8df6576dae2e935290a0f48ff9ab10bb", "drk":1, "top":1, "bot":1, "hs":[] } ] ``` 為了方便起見,直接擷取字串的```1到r.length()-1```的內容,繼續將其封裝為json物件,然後進而獲取它url對應的value ```java r = r.substring(1,r.length()-1); jsonObject = JSONObject.parseObject(r); String url = jsonObject.getString("url"); ``` 這時候拿到的value就是我們要的連結的字尾```/th?id=OHR.MischwaldFuessen_ZH-CN0005213724_1920x1080.jpg&rf=LaDigue_1920x1080.jpg&pid=hp```,只需要將其和字首拼接在一起即可作為圖片的地址。我們先將地址儲存在一個檔案裡面,檔案起名叫```link``` ```java String result = "https://www.bing.com/" + url; File file = new File("./link"); if (!file.exists()) { file.createNewFile(); } FileOutputStream fos = new FileOutputStream(file); fos.write(result.getBytes()); ``` 到此,Java程式完成,執行此程式即可將當日的每日一圖的地址存入link這個檔案裡。 ### 使用shell指令碼將圖片下載到制定位置 思路很簡單,使用shell指令碼呼叫Java程式,然後去link檔案中拿到連結即可使用wget命令進行下載。 #### 將Java程式打包成一個jar包 由於我們這個專案加入了阿里巴巴處理json的以來,所以需要帶著依賴打包。 點選File->Project Structure->Artifacts->Jar->From modules with dependencies ![](https://gitee.com/vfdxvffd/blogimage/raw/master/2020-11-17_11-44.png) ![](https://gitee.com/vfdxvffd/blogimage/raw/master/2020-11-17_11-48.png) 點選OK->Apply->關閉。這時候就在src下生成了一個.MF檔案 ![](https://gitee.com/vfdxvffd/blogimage/raw/master/2020-11-17_11-51.png) 點選Build->Build Artifacts ![](https://gitee.com/vfdxvffd/blogimage/raw/master/2020-11-17_11-53.png) 這時候就在專案目錄下的out目錄裡生成了可執行jar包,執行```java -jar xxx.jar```命令即可執行此程式,即在link中寫入當日每日一圖的連結地址。但是實際執行的時候發現報了一個錯誤```GetPic.jar中沒有主清單屬性``` ![](https://gitee.com/vfdxvffd/blogimage/raw/master/2020-11-17_11-56.png) 用Ark(一個壓縮工具)開啟jar包,然後開啟裡面的META-INF/MANIFEST.MF,檢視是否有```Main-Class```項,估計是沒有,然後加入一行`Main-Class: GetPic`其中GetPic為主類名。==注意Main-Class:和GetPic之間有一個空格。== ![](https://gitee.com/vfdxvffd/blogimage/raw/master/2020-11-17_12-41.png) 這樣執行jar包就可以成功了,成功將當日每日一圖的地址寫入link檔案中。 #### 下載圖片到指定位置 使用下面的命令可以將link中的連結取出來作為wget的下載連結,使用-O選項給圖片指定地址並命名,命名為當天的日期。 ```shell wget `cat link` -O ./pic/$(date "+%Y%m%d").jpeg ``` 所以完整的shell指令碼如下: ```shell #!/bin/bash java -jar GetPic.jar wget `cat link` -O ./pic/$(date "+%Y%m%d").jpeg ``` 手動執行指令碼完成對圖片的下載。 ## 啟動定時任務 既然是每日一圖,那就應該每天定時去獲取這個圖片,利用linux的crontab工具可以實現這一需求。 先檢查crond服務是否正常啟動: ```shell service cron status ``` 然後將這個指令碼加入到定時計劃中,這個是指定每天早上6點下載一次 ```shell 0 6 * * * sh ~/zhangqi/getPic/getPic.sh ``` 然後就開始等待第二天的6點,結果執行失敗。 #### 分析原因&解決問題 我們手動執行這個指令碼成功下載到了檔案,但加到定時任務裡執行失敗,分析有以下幾個可能的原因: 1. 定時任務沒有成功啟動 2. shell裡面某個任務沒有成功啟動 為了排除第一個可能的錯誤,寫了一個每分鐘輸出`hello world`到日誌檔案的命令後,發現定時任務成功啟動,這樣就排除了第一種可能。這樣一來就說明shell裡面某些任務沒有啟動。 先試著測試第一個執行jar包的命令,發現執行失敗,然後將執行這個jar包換成了一個Hello Word的程式,發現還是失敗。推測可能是Java程式執行出錯,但手動確實正常執行。==去網上查到一個帖子說crontab不會知道你腳本里需要用到的所有環境變數,突然就明白是沒有指明環境變數,指令碼中直接使用Java命令失敗導致的錯誤。==在指令碼中輸出`$JAVA_HOME`果然沒有結果。 找到問題後就明確方向了,在指令碼開頭引入環境變數 ```shell #!/bin/bash . /etc/profile java -jar GetPic.jar if [ $? -eq 0 ]; then echo 'success' >> ./log.txt else echo 'jar包執行出錯' >> ./log.txt exit fi wget `cat link` -O ./pic/$(date "+%Y%m%d").jpeg ``` 再次測試發現還是出錯,但這次輸出`$JAVA_HOME`成功,說明並不是環境變數的問題,仔細考慮了下懷疑是路徑的問題,在指令碼中輸出`pwd`到日誌發現確實如此,然後加上一句cd命令。 ```shell #!/bin/bash . /etc/profile cd /home/ubuntu/zhangqi/getPic java -jar GetPic.jar if [ $? -eq 0 ]; then echo 'success' >> ./log.txt else echo $JAVA_HOME >> ./log.txt exit fi wget `cat link` -O ./pic/$(date "+%Y%m%d").jpeg ``` 至此,執行成功。最後加上日誌資訊,方便萬一以後出錯來debug。然後根據自己想要的用途來使用這些精美圖片即可。 ```shell #!/bin/bash . /etc/profile cd /home/ubuntu/zhangqi/getPic java -jar GetPic.jar echo $(date "+%Y-%m-%d-%H-%M-%S") >> ./log.txt if [ $? -eq 0 ]; then echo 'success to getUrl' >> ./log.txt else echo 'jar包執行錯誤,檢查該連結還是否正確https://cn.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1' >> ./log.txt exit fi wget `cat link` -O ./pic/$(date "+%Y%m%d").jpeg if [ $? -eq 0 ]; then echo 'success to download' >> ./log.txt else echo '下載失敗,檢查網路和下載連結' >> ./log.txt cat link >> ./log.txt exi