独立开发日记 01:鞭策AI,几个小时搞定获取网站图标项目

2026-02-02
独立开发日记 01:鞭策AI,几个小时搞定获取网站图标项目 关注 作者 关注 作者 关注 作者 关注 作者 2025/09/27 20:49

有一个用户在群里面反馈,说我的网站书签获取的图标,有获取ico展示失败的,显示的都是默认的logo图还有图片裂开的情况。 爱壹帆在线

这个获取站点图标项目是我2年前网上找的一个开源的PHP项目,然后作者也非常久没维护了,我拉下来改改,直接就是部署一波,有一些小问题,不是很影响,后面想着再优化优化,大家懂的一般说后面再做的事情......。期间也是优化了几次,因为不 会PHP没敢大改动,都是一些站点小兼容。现在有AI了,有啥会不会的,直接鞭策AI不就好了吗 🤔 !!!也是好起来了,对PHP一点不会,使用AI花了几个小时深度优化了一波。项目原核心逻辑根据网站的url 获取网页的源码,然后使用正则获取源码里面的可能是icon的link标签,最后获取link标签的href路径 ,存为文件,缓存30天。原逻辑是从html中获取 link标签 约炮

if (@preg_match('/((<link[^>]+rel=.(icon|shortcut icon|alternate icon|apple-touch-icon)[^>]+>))/i', $html['data'], $match_tag)) {

ps:有的朋友可能是直接暴力获取 www.baidu.com/favicon.ico,但是有的网站根本没有这个 小宝影院 楼凤信息

使用正则获取link标签并不是很规范 rel可能在href后面 有点在前面 还有引号的问题,导致无法匹配

目前遇到的一些ico的格式有 各种各样的 通过url/favicon.ico 只能获取小部分的icon问题

用户反馈比如: iyf 小宝影院在线视频 外围

Kimi的 icon是个cdn图地址,还不是一个站点url下的 xxxvideo 电影小宝影院 xxxxx 爱壹帆免费版 寻芳网

<link rel="shortcut icon" href=//statics.moonshot.cn/kimi-web-seo/favicon.ico>

doubao的 爱壹帆 aiyifan 海外华人视频网

<link rel="icon" href="//lf-flow-web-cdn.doubao.com/obj/flow-doubao/doubao/web/logo-icon.png">

金山文档的 base64和远程cdn图标 小宝影院

<link rel="shortcut icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAACH1BMVEUAAAA9kP8mpv9Fv/8QT94TXeQAfv8trP0xr/0VUdoAcv8LgPs1sf4AgP4QUuURTuEVl/ksq/wAg/84tf4NUt80sf0bnPsPUuAAYfsAgP4UTtYAY/8GXPQRkv1Jxv8AZP86tv9Bvv9Gv/9Atv8KiPUOVesAZ+wbS8wUl/kjo/sAYv8PVekjovxBu/8AY/8trPxCu/8AW/AAcvAxsP0npvsYTdElo/oQT9o+uP8AYv8KVOIHdugAYfwAfPwbfe49uf4XmfkcdOopo/oAYv86tf4AYf8TT9cZaeYVTdUJVOUcnvsAYv8Agv9Iwv8AYv9Jwf8bSs0gofoAY/8Ag/9Gv/8en/oAYf9Fv/8AWuQZS80AdO5BvP8AYv9DvP8Umfo9uv8LVOUAgf8amfk/uf8AY/8Ag/8Ahf8TUdgVT9UNWOknov8trPwxr/wmpvspqfs1sv0io/s5tf0AgP8bnfoMV+4AYPoAYv8AYf4AYfwAe/sen/oAd/gAXvYAff0LW/MLWfEOUN0PT9oSTtZAu/49uP0qqfweoPoXmvkAdPUAXPIAcfEKUuIWTNIXS88KXPYAWusOVeoPVOkPUuYQUeQQT+IMUeAUTdMZSs09uP4Aa+kAWOgAaeQIVOQIU+QAV+MRTd8STd0RTtgSl/kAW+8NWO8Abu0AbuwBZNsAg/8AYPwAc/MIVecAZuEAVeAAWt8AZN0JgvAIfOsJV+sTVuIAU9qil9AQAAAAa3RSTlMAAwb++A3+bkkkGxL8+Pf36tnTubCYjol4dmVjRjEvLysZFA7+/Pv6+fj39/b19fPw8O/u7Ovq6Ofn5+Xj4uDa2trZ1dPS0s/Ny7+9vLi4trapoqGgoJ2XkI+KgoJycGRhX1BNS0pHQj06IcCB3jkAAAIBSURBVDjLdZCHctpAFEWfCMU1ce8tTu+99957770nJFGwkE1sgyMTAginYbkAIQSD494+0G+ltTAacWZnNLt7dO/Og3Tqzl2og8wsvroAudEI+iy5s+6LzMZ7Bp1r5sFOQegRenAJwoEnoCXr6Mc0ihvSrhuK32vJK21Mva00760OWyz0KZYNbzJQmKXUF1o7rZ24rGngweETIGOwbH2nw/ZDUaM6grJVHzSs3R+NoqDy+lKLuwWX2618r03/QRalhNzbewo+qZyuZX4TVMFQubm3f3xy5VeZg49xsL8IC+mUH+1zeLyJ3pHkRCwWK7hvIGc/CYrwvIhtbXZ4hgYwJLm0LFf56QdhDRAq8wdZMypD3kT/SBJo6nfCMmWTc2WQlUO8GDIn2GSAUnuWGERJpIS4LR4HlWdFNITua9pl5s3h5vJ81tzscAAhuyTc3kZQ51CxqasvMmDGENyZyo1BX2iqLRAI0L7qvU2fv6Ex5mVbgana4XIGfb7QsI0KNcc4O4/Gv67I6Jjn5cmOvy4nGuFwaFipqFjN2YlBQkZn/N0dxAhiSfjUKzqHyxwq/0lIX0T0d6OAGb7dD0Gl/gzH8UqN6JcNp7HcBPN5esTO8U2oSCIpcZVkgwamepedxxpJROP4C9DBdHc9vlWSxG1VDOiTc53jpRW3TJCZ+vMXNeWzDz4DoNZyqecAAAAASUVORK5CYII=">

<link rel="apple-touch-icon" href="https://qn.cache.wpscdn.cn/kdocs/mobile/touch/apple-120.png">

等等格式都是非标准的 文件 爱一帆 xnxx

AI干活 xxx

给AI一个大致的方向,然后直接鞭策AI,叫AI给我们写,我就直接可以抽空玩我的手游去了 爱壹帆国际版 小宝影院在线视频

给出干活的指令: 免费在线影院

获取源码后  aiyifan电影 xxxxxx 小宝影院电影

先提取所有的link标签 小寶影院 小宝影院电影

然后获取可能是ico的link标签,设置权重, 小寶影院电影

获取href 然后补全href图标路径 ifun 爱壹帆影视

然后再加一点点细节,设置重定向,伪造随机的User-Agent,ssl认证校验,href的相对路径和完整路径处理等
  aiyifan电影

核心代码 电影aiyifan 小宝影院

if ($html && $html['status'] == 'OK') {
         
            // 对取到的HTML内容进行删除换行符的处理,避免link信息折行导致的正则匹配失败
           
            $html = str_replace(array("\n", "\r"), '', $html);
            //匹配完整的LINK标签,再从LINK标签中获取HREF的值
            // 优化的两步匹配策略:先匹配所有link标签,再筛选favicon相关的标签

            // 第一步:匹配所有link标签
            $all_links = [];
            if (preg_match_all('/<link[^>]*>/i', $html['data'], $link_matches)) {
                $all_links = $link_matches[0];
            }

            $this->_log_message("【LINK匹配】找到 " . count($all_links) . " 个link标签");

            // 定义favicon相关的rel类型及其优先级(数字越小优先级越高)
            $favicon_types = [
                'icon' => 1,
                'shortcut icon' => 2,
                'apple-touch-icon' => 3,
                'apple-touch-icon-precomposed' => 4,
                'mask-icon' => 5,
                'alternate icon' => 6
            ];

            $found_icons = [];

            // 第二步:从所有link标签中筛选favicon相关的标签
            foreach ($all_links as $link_tag) {
                $this->_log_message("【LINK分析】处理标签: " . htmlspecialchars($link_tag));

                // 提取rel属性值
                $rel_value = '';
                if (preg_match('/rel\s*=\s*["\']([^"\']*)["\']|rel\s*=\s*([^\s>]+)/i', $link_tag, $rel_matches)) {
                    $rel_value = trim($rel_matches[1] ?? $rel_matches[2] ?? '');
                }

                // 检查是否为favicon相关的rel类型
                $matched_type = null;
                $priority = 999;

                foreach ($favicon_types as $type => $type_priority) {
                     // 使用更精确的匹配,避免部分匹配导致的错误识别
                     if ($type === 'icon' && preg_match('/^icon$/i', trim($rel_value))) {
                         if ($type_priority < $priority) {
                             $matched_type = $type;
                             $priority = $type_priority;
                         }
                     } elseif ($type === 'shortcut icon' && preg_match('/^shortcut\s+icon$/i', trim($rel_value))) {
                         if ($type_priority < $priority) {
                             $matched_type = $type;
                             $priority = $type_priority;
                         }
                     } elseif ($type === 'apple-touch-icon' && preg_match('/^apple-touch-icon/i', trim($rel_value))) {
                         if ($type_priority < $priority) {
                             $matched_type = $type;
                             $priority = $type_priority;
                         }
                     } elseif ($type === 'apple-touch-icon-precomposed' && preg_match('/^apple-touch-icon-precomposed/i', trim($rel_value))) {
                         if ($type_priority < $priority) {
                             $matched_type = $type;
                             $priority = $type_priority;
                         }
                     } elseif ($type === 'mask-icon' && preg_match('/^mask-icon$/i', trim($rel_value))) {
                         if ($type_priority < $priority) {
                             $matched_type = $type;
                             $priority = $type_priority;
                         }
                     } elseif ($type === 'alternate icon' && preg_match('/^alternate\s+icon$/i', trim($rel_value))) {
                         if ($type_priority < $priority) {
                             $matched_type = $type;
                             $priority = $type_priority;
                         }
                     }
                 }

                if ($matched_type) {
                    $this->_log_message("【LINK分析】匹配到favicon类型: {$matched_type}, rel值: {$rel_value}");

                    // 提取href属性值
                    $href_value = '';
                    if (preg_match('/href\s*=\s*["\']([^"\']*)["\']|href\s*=\s*([^\s>]+)/i', $link_tag, $href_matches)) {
                        $href_value = trim($href_matches[1] ?? $href_matches[2] ?? '');
                    }

                    if (!empty($href_value)) {
                        $this->_log_message("【LINK分析】提取到href: {$href_value}");

                        // 处理URL路径
                        if (preg_match('/^data:image\/[^;]+;base64,/', $href_value)) {
                            $full_icon_url = $href_value;
                        } elseif (preg_match('/^https?:\/\//', $href_value)) {
                            $full_icon_url = $href_value;
                        } else {
                            $full_icon_url = $this->filterRelativeUrl($href_value, $this->params['origin_url']);
                        }

                        // 避免重复添加相同的URL
                        $icon_key = md5($full_icon_url);
                        if (!isset($found_icons[$icon_key])) {
                            $found_icons[$icon_key] = [
                                'url' => $full_icon_url,
                                'type' => $matched_type,
                                'priority' => $priority,
                                'original_rel' => $rel_value
                            ];
                        }
                    } else {
                        $this->_log_message("【LINK分析】未找到href属性");
                    }
                } else {
                    $this->_log_message("【LINK分析】非favicon标签,rel值: {$rel_value}");
                }
            }
            // 按优先级排序图标
            uasort($found_icons, function($a, $b) {
                return $a['priority'] - $b['priority'];
            });
            // 打印所有找到的ICO路径
            $this->_log_message("【ICO路径】找到 " . count($found_icons) . " 个favicon链接:");
            foreach ($found_icons as $key => $icon_info) {
                $this->_log_message("【ICO路径】类型: {$icon_info['type']}, 优先级: {$icon_info['priority']}, 原始rel: {$icon_info['original_rel']}, URL: {$icon_info['url']}");
            }
            // 尝试获取找到的favicon,按优先级顺序
            foreach ($found_icons as $icon_info) {
                $icon_url = $icon_info['url'];
                $this->_log_message("Trying favicon URL ({$icon_info['type']}): {$icon_url}");

                // 检查是否为 base64 data URI
                if (preg_match('/^data:image\/[^;]+;base64,(.+)$/i', $icon_url, $matches)) {
                    $this->_log_message("Found base64 data URI favicon");
                    $base64_data = $matches[1];

                    // 解码 base64 数据
                    $decoded_data = base64_decode($base64_data);

                    if ($decoded_data !== false && strlen($decoded_data) > 0) {
                        $this->_log_message("Successfully decoded base64 favicon data, size: " . strlen($decoded_data) . " bytes");
                        $this->data = $decoded_data;
                        return $this->data; // 成功获取到 base64 favicon,直接返回
                    } else {
                        $this->_log_message("Failed to decode base64 favicon data");
                    }
                } else {
                    // 普通的 HTTP/HTTPS URL,使用原有的 getFile 方法
                    $icon = $this->getFile($icon_url, true);
                    if ($icon && $icon['status'] == 'OK') {
                        $this->_log_message("Success get icon from {$this->params['origin_url']}, icon url is {$icon_url}");
                        $this->data = $icon['data'];
                        break; // 找到第一个可用的就停止
                    } else {
                        $this->_log_message("Failed to get icon from: {$icon_url}");
                    }
                }
            }
        }

直接叫AI改写核心的逻辑,到这一步已经大幅度的提升了获取icon的成功概率 电影爱壹帆

进阶优化 爱壹帆电影

到这一步已经解决了兼容绝大部分的站点,但是还有有一些特殊的展示无法兼容,这个时候就需要继续鞭策AI新增一个备用方案,支持手动映射站点和文件图标,解决剩下的无法获取图标的站点。

PHP我也没咋用过,直接叫AI自己出方案自己实现,新增可手动映射列表管理后台,并且可导出导入备份功能,简易后台维护系统 。

最终AI的技术栈选的SqLite+本地文件的形式做数据存储,非常的方便,也不需要依赖其他中间件了。

通过API自动识别+后台手动配置的方式,至此绝大部分站点都可以轻松的获取到图标。如果后续还遇到不兼容的站点,直接去管理后台配置一下就好了。 爱壹帆 华人影视

结束

AI越来越强悍了,全程花了几个小时,我一行代码没写,AI全程帮我完成了,我完全不会的PHP项目改造。自己写我可能就直接考虑换成自己熟悉的语言重写了,比如NodeJs代替。 爱一帆电影 xxxx


  伴游

10目录 0
    讨论 我来说一句 发布发表评论 发布1等 1 人为本文章充电 一手造工具,一手写测评,专注帮你测评笔记软件与知识管理工具,让阅读变轻松,笔记变好用。 关注