如何使用 Github Actions 自动抓取每日必应壁纸?

点赞再看,动力无限。Hello world : ) 微信搜「 程序猿阿朗 」。

本文 Github.com/niumoo/JavaNotes未读代码博客 已经收录,有很多知识点和系列文章。

如何白嫖 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

订阅

<完>

Hello world : ) 我是阿朗,一线技术工具人,认认真真写文章。

点赞的个个都是人才,不仅长得帅气好看,说话还好听。


文章持续更新,可以关注公众号「 程序猿阿朗 」或访问「未读代码博客 」。

回复【资料】有我准备的各系列知识点和必看书籍。

本文 Github.com/niumoo/JavaNotes 已经收录,有很多知识点和系列文章,欢迎Star。

等你好久

原文地址:https://www.cnblogs.com/niumoo/p/14472691.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘要,谢谢! 目录 连接 连接池产生原因 连接池实现原理 小结 TEMPERANCE:Eat not to dullness;drink not to elevation.节制
摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘要,谢谢! 一个优秀的工程师和一个普通的工程师的区别,不是满天飞的架构图,他的功底体现在所写的每一行代码上。-- 毕玄 1. 命名风格 【书摘】类名用 UpperCamelC
今天犯了个错:“接口变动,伤筋动骨,除非你确定只有你一个人在用”。哪怕只是throw了一个新的Exception。哈哈,这是我犯的错误。一、接口和抽象类类,即一个对象。先抽象类,就是抽象出类的基础部分,即抽象基类(抽象类)。官方定义让人费解,但是记忆方法是也不错的 —包含抽象方法的类叫做抽象类。接口
Writer :BYSocket(泥沙砖瓦浆木匠)微 博:BYSocket豆 瓣:BYSocketFaceBook:BYSocketTwitter :BYSocket一、引子文件,作为常见的数据源。关于操作文件的字节流就是 —FileInputStream&amp;FileOutputStream。
作者:泥沙砖瓦浆木匠网站:http://blog.csdn.net/jeffli1993个人签名:打算起手不凡写出鸿篇巨作的人,往往坚持不了完成第一章节。交流QQ群:【编程之美 365234583】http://qm.qq.com/cgi-bin/qm/qr?k=FhFAoaWwjP29_Aonqz
本文目录 线程与多线程 线程的运行与创建 线程的状态 1 线程与多线程 线程是什么? 线程(Thread)是一个对象(Object)。用来干什么?Java 线程(也称 JVM 线程)是 Java 进程内允许多个同时进行的任务。该进程内并发的任务成为线程(Thread),一个进程里至少一个线程。 Ja
Writer :BYSocket(泥沙砖瓦浆木匠)微 博:BYSocket豆 瓣:BYSocketFaceBook:BYSocketTwitter :BYSocket在面向对象编程中,编程人员应该在意“资源”。比如?1String hello = &quot;hello&quot;; 在代码中,我们
摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘要,谢谢! 这是泥瓦匠的第103篇原创 《程序兵法:Java String 源码的排序算法(一)》 文章工程:* JDK 1.8* 工程名:algorithm-core-le
摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘要,谢谢! 目录 一、父子类变量名相同会咋样? 有个小故事,今天群里面有个人问下面如图输出什么? 我回答:60。但这是错的,答案结果是 40 。我知错能改,然后说了下父子类变
作者:泥瓦匠 出处:https://www.bysocket.com/2021-10-26/mac-create-files-from-the-root-directory.html Mac 操作系统挺适合开发者进行写代码,最近碰到了一个问题,问题是如何在 macOS 根目录创建文件夹。不同的 ma
作者:李强强上一篇,泥瓦匠基础地讲了下Java I/O : Bit Operation 位运算。这一讲,泥瓦匠带你走进Java中的进制详解。一、引子在Java世界里,99%的工作都是处理这高层。那么二进制,字节码这些会在哪里用到呢?自问自答:在跨平台的时候,就凸显神功了。比如说文件读写,数据通信,还
1 线程中断 1.1 什么是线程中断? 线程中断是线程的标志位属性。而不是真正终止线程,和线程的状态无关。线程中断过程表示一个运行中的线程,通过其他线程调用了该线程的 方法,使得该线程中断标志位属性改变。 深入思考下,线程中断不是去中断了线程,恰恰是用来通知该线程应该被中断了。具体是一个标志位属性,
Writer:BYSocket(泥沙砖瓦浆木匠)微博:BYSocket豆瓣:BYSocketReprint it anywhere u want需求 项目在设计表的时候,要处理并发多的一些数据,类似订单号不能重复,要保持唯一。原本以为来个时间戳,精确到毫秒应该不错了。后来觉得是错了,测试环境下很多一
纯技术交流群 每日推荐 - 技术干货推送 跟着泥瓦匠,一起问答交流 扫一扫,我邀请你入群 纯技术交流群 每日推荐 - 技术干货推送 跟着泥瓦匠,一起问答交流 扫一扫,我邀请你入群 加微信:bysocket01
Writer:BYSocket(泥沙砖瓦浆木匠)微博:BYSocket豆瓣:BYSocketReprint it anywhere u want.文章Points:1、介绍RESTful架构风格2、Spring配置CXF3、三层初设计,实现WebService接口层4、撰写HTTPClient 客户
Writer :BYSocket(泥沙砖瓦浆木匠)什么是回调?今天傻傻地截了张图问了下,然后被陈大牛回答道“就一个回调…”。此时千万个草泥马飞奔而过(逃哈哈,看着源码,享受着这种回调在代码上的作用,真是美哉。不妨总结总结。一、什么是回调回调,回调。要先有调用,才有调用者和被调用者之间的回调。所以在百
Writer :BYSocket(泥沙砖瓦浆木匠)一、什么大小端?大小端在计算机业界,Endian表示数据在存储器中的存放顺序。百度百科如下叙述之:大端模式,是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加
What is a programming language? Before introducing compilation and decompilation, let&#39;s briefly introduce the Programming Language. Programming la
Writer :BYSocket(泥沙砖瓦浆木匠)微 博:BYSocket豆 瓣:BYSocketFaceBook:BYSocketTwitter :BYSocket泥瓦匠喜欢Java,文章总是扯扯Java。 I/O 基础,就是二进制,也就是Bit。一、Bit与二进制什么是Bit(位)呢?位是CPU
Writer:BYSocket(泥沙砖瓦浆木匠)微博:BYSocket豆瓣:BYSocket一、前言 泥瓦匠最近被项目搞的天昏地暗。发现有些要给自己一些目标,关于技术的目标:专注很重要。专注Java 基础 + H5(学习) 其他操作系统,算法,数据结构当成课外书博览。有时候,就是那样你越是专注方面越