「数据采集」每日必应壁纸数据自动采集与上传Github仓库实现教程

前言

  大学的时候有做过类似的采集程序,当时还不知道有必应每日一图API这种东西,所以当时的实现逻辑是通过正则从网页源码中爬取到相应的图片url并进行下载。而中途由于各种原因,闭站了很长一段时间,于是丢失了很多必应每日一图的精美图片。今天突然心血来潮,又根据必应每日一图的API来实现数据采集功能,相比之前写的采集程序,这一次多了一个上传Github仓库的操作,实现起来还是很有意思的。

必应每日一图API

必应每日一图API

  打开Bing官网,通过F12打开控制台,并查看network标签,可以看到页面请求了必应每日一图API这个地址。

https://cn.bing.com/HPImageArchive.aspx?format=hp&idx=0&n=1&nc=1568909543637&pid=hp&FORM=BEHPTB&ensearch=1&quiz=1&og=1&uhd=1&uhdwidth=2880&uhdheight=1620&IG=2D3A28F668884DFE833A987CBC7C8B19&IID=SERP.1050&setmkt=en-us&setlang=en-us

其中

param description
format 返回的数据格式。hp为html格式;js为json格式;其他值为xml格式。
idx 获取特定时间点的数据。如idx=1表示前一天(昨天),依此类推。经过测试最大值为7。
n 获取数据的条数。经测试,配合上idx最大可以获取到13天前的数据,即idx=7&n=7。
nc 请求的时间戳。不知道会有什么影响。
pid 未知。pid为hp时,copyrightlink返回的是相对地址。pid不为hp时,没有看到og信息。
FORM 未知。
ensearch 指定获取必应【国际版/国内版】的每日一图。当ensearch=1时,获取到的是必应国际版的每日一图数据。默认情况和其他值情况下,获取到的是必应国内版的每日一图数据。
quiz 当quiz=1时,返回必应小测验所需的相关数据。
og 水印图相关的信息。包含了title、img、desc和hash等信息。
uhd 当uhd=1时,可以自定义图片的宽高。当uhd=0时,返回的是固定宽高的图片数据。
uhdwidth 图片宽度。当uhd=1时生效。最大值为3840,超过这个值当作3840处理。
uhdheight 图片高度。当uhd=1时生效。最大值为2592,超过这个值当作2592处理。
IG 未知。
IID 未知。
setmkt 指定图片相关的区域信息。如图片名中包含的EN-CN、EN-US或者ZH-CN等。当域名为global.bing.com时才会有相应变化。值的格式:en-us、zh-cn等。
setlang 指定返回数据所使用的语言。值的格式:en-us、zh-cn等。

  各个参数之间可能会有相互影响。
  当域名为global.bing.com时:
    当ensearch=0:
      当setmkt=en-us: EN-US
      当setmkt=zh-cn: ZH-CN
    当ensearch=1:
      当setmkt=en-us: EN-US
      当setmkt=zh-cn: EN-CN
  当域名为cn.bing.com时:
    当ensearch=0:
      当setmkt=en-us: ZH-CN
      当setmkt=zh-cn: ZH-CN
    当ensearch=1:
      当setmkt=en-us: EN-CN
      当setmkt=zh-cn: EN-CN

  表格中列举的不够全面,可以根据实际开发所需尝试。

代码实现 Photo Collections

  必应每日一图采集相关代码地址:https://github.com/facefruit/daily-bing-wallpaper

  可以通过github获取到最新版本的代码。

<?php
//根据测试发现必应每日一图api中会根据请求头中的cookie来判断是返回国内版还是国际版每日一图
$ensearchs = array(
    'cn' => 0, //国内版
    'en' => 1 //国际版
);
//遍历数组
foreach ($ensearchs as $ensearch_key => $ensearch_value) {
    //定义存储api数据的文件夹名称
    $bing_json_dir  = 'json/' . date('Y') . '/' . date('m');
    //获取目录路径(如"./en/json")
    $bing_json_path = $ensearch_key . '/' . $bing_json_dir;
    //判断文件是否存在,如果不存在则创建目录
    if (!file_exists($bing_json_path)) {
        mkdir($bing_json_path, 777, true);
        echo 'json文件夹不存在,已创建成功!
';
    }
    //拼接api数据的文件路径
    $file_path = $bing_json_path . '/' . date('Y-m-d') . '.json';
    echo '文件名称:' . $file_path . '
';
    $bing_json_url = '"https://cn.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1&pid=hp&ensearch=' . $ensearch_value . '&quiz=1&og=1&uhd=0"';
    //请求网络获取api数据
    echo '正在下载今日bing数据...
';
	//拼接下载命令
	$download_cmd = 'wget -O ' . $file_path . ' ' . $bing_json_url;
	echo $download_cmd . '
';
	//执行文件下载
	exec($download_cmd);
	//不知道为什么用下面的方法会报异常
	////PHP Warning:
	////		file_get_contents("https://cn.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1"):
	////		failed to open stream: No such file or directory in /root/photo-collections/bing-sprider.php on line 36
	////Warning: 
	////      file_get_contents("https://cn.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1"):
	////		failed to open stream: No such file or directory in /root/photo-collections/bing-sprider.php on line 36
	//$request_array = array(
	//    'http' => array(
	//       'header' => 'cookie:ENSEARCH=BENVER=' . $ensearch_value,
	//        'authority' => 'www.bing.com',
	//        'method' => 'GET',
	//        'path' => '/HPImageArchive.aspx?format=js&idx=0&n=1',
	//        'scheme' => 'http'
	//    )
	//);
	//var_dump($request_array);
	//$request_context = stream_context_create($request_array);
	//$json_content = file_get_contents($bing_json_url, false, $request_context);
	//$json_content = fopen($bing_json_url, 'r', false, $request_context);
	echo '今日bing数据下载成功!
';
	
    //file_put_contents($file_path, $json_content);
    //从本地读取下载好的api数据
    $file_open    = fopen($file_path, 'r');
    $json_content = fread($file_open, filesize($file_path));
    //转换成json对象
    //$json_obj = json_decode($json_content, true);
    $json_obj     = json_decode($json_content, false);
    
    //var_dump($json_obj);
    //var_dump($json_obj->images);
    //取出images数组,由于调用api时n=1,所以数字的length=1
    $images = $json_obj->images;
	
	//更新Git账号信息为爬虫账号信息并同步更新仓库最新代码
	exec('git config --local user.name "Sprider"');
	exec('git config --local user.email "sprider@klavor"');
	exec('git pull devlang bing-daily-picture');
	
	foreach($images as $image) {
		//取出图片对象
		//$image  = $images[0];
		//var_dump($image);
		
		//取出变量
		$title         = $image->title;
		$caption       = $image->caption;
		$desc          = $image->desc;
		$copyrightonly = $image->copyrightonly;
		$copyright     = $image->copyright;
		$copyrightlink = $image->copyrightlink;
		$url           = $image->url;
		$urlbase       = $image->urlbase;
		$startdate     = $image->startdate;
		$fullstartdate = $image->fullstartdate;
		$enddate       = $image->enddate;
		$quiz          = $image->quiz;
		$hsh           = $image->hsh;
		$image_og      = $image->og;
		$og_title      = $image_og->title;
		$og_desc       = $image_og->desc;
		$og_img        = $image_og->img;
		$og_hash       = $image_og->hash;
		
		if (empty($title)) {
			$title = strstr($copyright, '(', true);
		}
		if (empty($caption)) {
			$caption = $title;
		}
		if (empty($copyrightonly)) {
			$copyrightonly = substr(strrchr($copyright, '('), 1, -1);
		}
		
		$file_name = substr(strrchr($urlbase, '='), 1);
		
		$image_count = 0;
		
		//修改json文件名称
		//exec('mv ' . $file_path . ' ' . $bing_json_path . '/' . $file_name . '.json');
		
		//$json_content = file_get_contents($bing_json_url);
		//$json_obj = json_decode($json_content, true);
		$bing_site      = 'https://cn.bing.com';
		//拼接域名获取到完整的图片地址
		$bing_image_url = $bing_site . $url;
		$sub_image_dir = $startdate;
		$sub_image_dir = substr_replace($sub_image_dir, '/', 6,0);
		$sub_image_dir = substr_replace($sub_image_dir, '/', 4,0);
		//拼接图片存储文件夹路径
		$image_dir      = $ensearch_key . '/' . $sub_image_dir;
		if (!file_exists($image_dir)) {
			mkdir($image_dir, 777, true);
		}
		//生成图片文件名
		$image_name = $file_name . '.jpg';
		//拼接图片文件路径
		$image_path = $image_dir . '/' . $image_name;
		//判断图片是否存在,不存在则下载图片
		if (!file_exists($image_path)) {
			$image_count++;
			//拼接下载图片命令
			$image_download_cmd = 'wget -O ' . $image_path . ' "' . $bing_image_url . '"';
			echo $image_download_cmd . '
';
			//执行图片下载命令
			exec($image_download_cmd);
			echo 'bing每日一图下载完成!
';
		} else {
			echo '图片已存在!
';
		}
		
		//水印图片下载
		$og_image_name = substr(strrchr($og_img, '='), 1);
		$og_image_path = $image_dir . '/' . $og_image_name;
		if (!file_exists($og_image_path)) {
			$image_count++;
			exec('wget -O ' . $og_image_path . ' "' . $og_img . '"');
			echo 'bing水印图片下载完成!
';
		} else {
			echo 'bing水印图片已存在!
';
		}
		
		if ($image_count == 0) {
			//没有下载任何图片,则将仓库重置
			$reset_cmd = 'git add --all .;';
			$reset_cmd .= 'git reset --hard HEAD';
			exec($reset_cmd);
			continue;
		}
		
		//拼接git提交所需要的comment信息
		$comment = 'Title: ' . $title . '
';
		$comment .= 'Caption: ' . $caption . '
';
		$comment .= 'Desc: ' . $desc . '
';
		$comment .= 'Copyrightonly: ' . $copyrightonly . '
';
		$comment .= 'Copyright: ' . $copyright . '
';
		$comment .= 'Copyrightlink: ' . $copyrightlink . '
';
		$comment .= 'Url: ' . $url . '
';
		$comment .= 'Urlbase: ' . $urlbase . '
';
		$comment .= 'Startdate: ' . $startdate . '
';
		$comment .= 'Fullstartdate: ' . $fullstartdate . '
';
		$comment .= 'Enddate: ' . $enddate . '
';
		$comment .= 'Quiz: ' . $quiz . '
';
		$comment .= 'Hsh: ' . $hsh . '
';
		$comment .= 'Og Title: ' . $og_title . '
';
		$comment .= 'Og Desc: ' . $og_desc . '
';
		$comment .= 'Og Img: ' . $og_img . '
';
		$comment .= 'Og Hash: ' . $og_hash . '
';
		
		//拼接git提交的shell脚本
		//$git_cmd = 'git config --local user.name "Sprider";';
		//$git_cmd .= 'git config --local user.email "sprider@klavor";';
		//$git_cmd .= 'git pull devlang bing-daily-picture;';
		//$git_cmd .= 'git add --all .;';
		//$git_cmd .= 'git commit -m "' . $comment . '";';
		//$git_cmd .= 'git push devlang bing-daily-picture;';
		//$git_cmd .= 'git config --local user.name "Klavor Lee";';
		//$git_cmd .= 'git config --local user.email "lee@klavor.com";';
		
		//将shell脚本输出到本地,需要注意的是需要可执行权限。否则不能执行shell脚本,从而导致提交代码失败。
		//$shell_path = 'git.sh';
		//file_put_contents($shell_path, $git_cmd);
		//chmod($shell_path, 777);
		//执行shell脚本
		//exec('./git.sh');
		
		//下面的方式不能够正常运行,因此替换成了shell脚本的方式
		////报错信息:
		////Vim:Warning:Output is not to a terminal
		//exec('git config --local user.name "Sprider"');
		//exec('git config --local user.email "sprider@klavor"');
		//exec('git pull devlang bing-daily-picture');
		exec('git add --all .');
		exec('git commit -m "'.$comment.'";');
		exec('git push devlang bing-daily-picture');
		//exec('git config --local user.name "Klavor Lee"');
		//exec('git config --local user.email "lee@klavor.com"');
	}
	//还原Git账号信息
	exec('git config --local user.name "Klavor Lee"');
	exec('git config --local user.email "lee@klavor.com"');
}

  代码写的比较LOW,不过功能是齐全的。在编写的过程中百度了很多知识点,毕竟对我来说,虽然自学过php,但是不常用,还是很陌生的。写代码的这期间,也遇到了很多问题,不过换了思路换了解决办法之后还是顺利的完成了这个功能的开发。

自动执行定时任务

  我这里使用的是宝塔提供的控制台,所以就没有自己去写定时任务的命令,直接可视化操作完成了。

添加定时任务

  手动的执行了一次任务后,发现效果还行。

执行定时任务

  执行完成后打开github仓库查看提交记录,发现新添加的图片已经成功提交。

Github提交记录

  截图的时间并不是同一个时间点,所以不要在意时间上的细节。

疑难杂症

  在开发的过程中,难免遇到一些奇奇怪怪的问题,一直没有办法解决。所以在实现过程中使用了些投机取巧的办法。

  • 文件下载

  起初,并不知道直接将参数拼接到url中就可以。因此使用了请求头中添加“cookie:cookie:ENSEARCH=BENVER=1”的形式来请求必应国际版每日一图的数据。
  但是问题来了。代码里构造一个context对象,并通过file_get_contents()和fopen()方法下载数据的时候总是会报错。

PHP Warning: file_get_contents("https://cn.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1"): failed to open stream: No such file or directory in /root/photo-collections/bing-sprider.php on line 36
Warning:  file_get_contents("https://cn.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1"): failed to open stream: No such file or directory in /root/photo-collections/bing-sprider.php on line 36

  不是很清楚是什么原因导致这个问题,于是使用了“wget –header=”cookie:cookie:ENSEARCH=BENVER=1″ -O ./ 文件URL”的方式下载数据,结果还算是比较满意,可以实现国际版和国内版之间的切换。

  • git操作

  起初想着使用exec()函数来执行git的命令,但是当执行“git add .”时,报出了“Vim:Warning:Output is not to a terminal”的提示,到目前为止也没有找到好的解决办法。

  所以就想了一个投机取巧的方法,就是将git命令生成一个shell脚本,然后再通过exec()函数来执行这个shell脚本。事实证明,这是可以行得通的。

  不过后来直接通过exec()函数执行又没有问题了,不知道是做了什么操作导致的,不明觉厉。

写在后面

  感动,热泪盈眶。已经有很多年没有写php的代码了,这一次觉得有意思的点是通过php实现了git的自动提交。但是有一个问题,服务器开启了exec()函数的支持,不知道对安全性有没有什么影响。如果你有什么好的建议可以在下方发表评论留言。

《「数据采集」每日必应壁纸数据自动采集与上传Github仓库实现教程》上有2条评论

发表评论

电子邮件地址不会被公开。 必填项已用*标注