当前位置 博文首页 > 头发是我最后的倔强:每天定时获取必应每日一图并保存做壁纸

    头发是我最后的倔强:每天定时获取必应每日一图并保存做壁纸

    作者:头发是我最后的倔强 时间:2021-01-30 16:03

    每天定时获取必应每日一图并保存做壁纸

    ? 必应每天会更新每日一图,这些图片都是特别好看,适合做封面壁纸等等。我做了一个自动脚本,让它每天定时获取每日一图,然后设置为个人主页博客的封面,封面和背景一共九张图片,每天更新后以队列的顺序替换。

    ? 这里是成品:个人搭建的博客主页

    获取每日一图的链接

    从接口获取链接

    必应提供了一个获取每日一图的接口,https://cn.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1,访问此接口会返回一个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/或者http://s.cn.bing.net,两者选其一,比如今天的图片完整链接为https://www.bing.com//th?id=OHR.MischwaldFuessen_ZH-CN0005213724_1920x1080.jpg&rf=LaDigue_1920x1080.jpg&pid=hp,下载的图片格式为jpeg。

    使用Java得到链接

    知道了图片的链接获取方法,就写一个Java程序来获取它。我们将页面的json数据一行一行读取,存入一个字符串并返回。

    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文件中加入下面的依赖:

    <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.73</version>
    </dependency>
    

    利用这个工具将String类型的json数据封装成一个JSONObject,通过调用get(key)或者getString(key)获取到key对应的value,因为这个json数据里面有级联属性,所以先获取images对应的value。

    //通过该链接先获取到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字符串就是

    [
        {
            "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

    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

    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

    点击OK->Apply->关闭。这时候就在src下生成了一个.MF文件

    点击Build->Build Artifacts

    这时候就在项目目录下的out目录里生成了可执行jar包,执行java -jar xxx.jar命令即可运行此程序,即在link中写入当日每日一图的链接地址。但是实际运行的时候发现报了一个错误GetPic.jar中没有主清单属性

    用Ark(一个压缩工具)打开jar包,然后打开里面的META-INF/MANIFEST.MF,查看是否有Main-Class项,估计是没有,然后加入一行Main-Class: GetPic其中GetPic为主类名。注意Main-Class:和GetPic之间有一个空格。

    这样运行jar包就可以成功了,成功将当日每日一图的地址写入link文件中。

    下载图片到指定位置

    使用下面的命令可以将link中的链接取出来作为wget的下载链接,使用-O选项给图片指定地址并命名,命名为当天的日期。

    wget `cat link` -O ./pic/$(date "+%Y%m%d").jpeg
    

    所以完整的shell脚本如下:

    #!/bin/bash
    java -jar GetPic.jar
    wget `cat link` -O ./pic/$(date "+%Y%m%d").jpeg
    

    手动执行脚本完成对图片的下载。

    启动定时任务

    既然是每日一图,那就应该每天定时去获取这个图片,利用linux的crontab工具可以实现这一需求。

    先检查crond服务是否正常启动:

    service cron status
    

    然后将这个脚本加入到定时计划中,这个是指定每天早上6点下载一次

    0 6 * * * sh ~/zhangqi/getPic/getPic.sh
    

    然后就开始等待第二天的6点,结果执行失败。

    分析原因&解决问题

    我们手动执行这个脚本成功下载到了文件,但加到定时任务里执行失败,分析有以下几个可能的原因:

    1. 定时任务没有成功启动
    2. shell里面某个任务没有成功启动

    为了排除第一个可能的错误,写了一个每分钟输出hello world到日志文件的命令后,发现定时任务成功启动,这样就排除了第一种可能。这样一来就说明shell里面某些任务没有启动。

    先试着测试第一个执行jar包的命令,发现执行失败,然后将执行这个jar包换成了一个Hello Word的程序,发现还是失败。推测可能是Java程序执行出错,但手动确实正常执行。去网上查到一个帖子说crontab不会知道你脚本里需要用到的所有环境变量,突然就明白是没有指明环境变量,脚本中直接使用Java命令失败导致的错误。在脚本中输出$JAVA_HOME果然没有结果。

    找到问题后就明确方向了,在脚本开头引入环境变量

    #!/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命令。

    #!/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。然后根据自己想要的用途来使用这些精美图片即可。

    #!/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
        exit
    fi
    
    下一篇:没有了