如何使用 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 ,那么就不难写一个自动爬取当天必应壁纸的自动化程序。
- 请求必应壁纸 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?i