分享免费的编程资源和教程

网站首页 > 技术教程 正文

给你代码:网站图标favicon自动抓取

goqiw 2024-09-25 20:25:10 技术教程 31 ℃ 0 评论

最近的一个项目有关网站图标爬取,所以将一些经验点及解决办法分享出来。

favicon图标介绍

favicon.ico一般用于网站logo标志,它显示在浏览器的地址栏、浏览器标签上或者在收藏夹上,是展示网站个性的缩略logo标志。

浏览器是怎么得到网站图标的?

浏览器首先会分析请求的网址源代码的head部分,找到带有rel="icon"属性的link元素,其中href属性就是图标地址,但是并不是所有网站都会设置这一项,有些网站喜欢直接将favicon.ico放在根目录下,便于SEO优化。因为搜索引擎爬虫会在网站根目录尝试请求favicon.ico,久而久之,潜移默化就变成了行业规范。了解了网站图标的获取源后,抓取思路就有了。

暴力请求

不管你网站根目录有没有favicon.ico,我就是要抓,至于能不能抓到,碰碰运气再说(毕竟这个运气概率还是非常高的)。以我们官网(https://www.kunquer.com)为例,PHP抓取代码如下:

$url = 'https://www.kunquer.com';
$content = file_get_contents($url.'/favicon.ico');

请原谅我不把代码一次性放出来,毕竟要讲得详细才够味(还有凑凑文章字数好交差)。怎么判断抓取回来的内容就是图标呢?也许只是一个404页面?保存内容到本地文件后,通过getimagesize()函数就能判断出来:

$file = tmpfile();
$path = stream_get_meta_data($file)['uri'];
file_put_contents($path, file_get_contents($Pea->url.'/favicon.ico'));
var_dump(getimagesize($path));

顺利的话,将会打印出如下内容:

array(6) { [0]=> int(48) [1]=> int(48) [2]=> int(17) [3]=> string(22) "width="48" height="48"" ["bits"]=> int(32) ["mime"]=> string(24) "image/vnd.microsoft.icon" }

以上例子不可能不顺利,因为我们官网根目录下是有这个文件的哈哈哈嗝。为了后续表演(不对是另一种情况)能演示下去,我们以虾米网为例,访问xiami.com/favicon.ico,得到以下回馈:

很好!我们可以开始下一步了。

分析网页源码

当暴力请求无果后,只好通过抓取页面,分析其中源码来获取图标了,因为图标是放在head部分的link中,通过设置rel="icon"或者 rel="shortcut icon" 来让浏览器识别,我们也只需要找出这个部分的href,分析匹配代码如下:

$base = 'http://xiami.com';
preg_match('/<head>(.*?)<\/head>/is', file_get_contents($base), $head);
if(isset($head[1])) {
 preg_match_all('/<link[^>]+>/is', $head[1], $links);
 if(isset($links[0]) && is_array($links[0])) {
 foreach($links[0] as $link) {
 // 查找rel中包含icon标识的图片路径
 if(preg_match('/rel=("|\')?(icon\w?|\w+\s+icon)("|\')?/i', $link)) {
 var_dump($link);
 }
 }
 } 
}

以上,为了寻找真相,通过一步步缩小查找范围,我们得到结果:

string(102) "<link rel="icon" type="image/png" href="//img.alicdn.com/tfs/TB1qP4zgY5YBuNjSspoXXbeNFXa-550-550.png">"

没错,其中的href部分就是我们要的图标:

preg_match('/([^"\s><]*\.(ico|png|jpg))/i', $link, $url);
echo $url[1];

运行结果:

//img.alicdn.com/tfs/TB1qP4zgY5YBuNjSspoXXbeNFXa-550-550.png

最后一步我们只需要再次发起对上面结果地址的请求,就可以保存到本地了,但在这之前,我们需要对结果地址稍微做些补全调整:

if(preg_match('/^http(s):\/\//', $url[1])) { // 完整路径
 $url = $url[1];
} elseif(preg_match('/^\/{2}\w+/', $url[1])) { // 双//打头
 $url = 'http:'.$url[1];
} else { // 相对路径
 $url = $base.'/'.ltrim($url[1], '/');
}

最后放上完整代码:

<?php
$url = 'http://xiami.com';
$file = tmpfile(); // 创建一个临时文件,用来保存图标
$path = stream_get_meta_data($file)['uri'];
$extension = 'ico'; // 图标后缀
$context = stream_context_create(['http' => ['timeout' => 15]]);
file_put_contents($path, file_get_contents($url.'/favicon.ico', null, $context));
if(!getimagesize($path)) { // 根目录下没有favicon.ico
 preg_match('/<head>(.*?)<\/head>/is', file_get_contents($Pea->url, null, $context), $head);
 if(!isset($head[1])) { // 非标准格式页面
 $path = false;
 } else {
 $Fulfill = function($base, $url) {
 if(preg_match('/^http(s):\/\//', $url)) { // 完整路径
 return $url;
 } elseif(preg_match('/^\/{2}\w+/', $url)) { // 双//打头://s1.music.126.net/style/favicon.ico
 return 'http:'.$url;
 } else { // 相对路径
 return $base.'/'.ltrim($url, '/');
 }
 };
 $found = false; // 是否查找到
 preg_match_all('/<link[^>]+>/is', $head[1], $links);
 if(isset($links[0]) && is_array($links[0])) {
 foreach($links[0] as $link) {
 // 查找rel中包含icon标识的图片路径
 if(preg_match('/rel=("|\')?(icon\w?|\w+\s+icon)("|\')?/i', $link)) {
 preg_match('/([^"\s><]*\.(ico|png|jpg))/i', $link, $url);
 if(isset($url[1])) {
 file_put_contents($path, file_get_contents($Fulfill($url, $url[1]), null, $context));
 if(getimagesize($path)) {
 $found = true;
 $extension = $url[2];
 }
 }
 }
 }
 }
 if(!$found) $path = false;
 }
}
if($path) {
 // @todo 将文件转移到服务器存储目录等
}

祝大家节日快乐,以上。

给你代码往期回顾:

给你代码:如何压制MySQL主键值非连续增长

给你代码:自建外贸站之PayPal支付集成

给你代码:网站微信登录接入

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表