不用再费劲去查源代码啦
正常是从源代码查找:
rel="icon"
rel="shortcut icon"
rel="apple-touch-icon"
等字符,但是有些网站可能并非是写入meta标签中而是动态生成,搜索不到的;
当无favicon图标地址时候直接用此方法就方便啦;
博客友链,导航站,这些用上 省事很多;
调用:
https://favicon.splitbee.io/?url=网页地址
例如:
https://favicon.splitbee.io/?url=https://www.dalao.net/
https://favicon.splitbee.io/?url=https://www.ximi.me/
https://ink.tino.im/api/content/links/fetch-metadata?url=dalao.net
支持
这个不错噢。
tino https://ink.tino.im/api/content/links/fetch-metadata?url=dalao.net 支持
不错,能开源嚒
不错,能开源不
brynn 不错,能开源不
用ai写了一个:
例:
https://i.ximi.me/logo.php?url=google.com
代码:
<?php /** * 仿 Splitbee Favicon 获取器 * 用法: favicon.php?url=https://www.baidu.com */ // 1. 获取并清理传入的 URL $target_url = isset($_GET['url']) ? trim($_GET['url']) : ''; if (empty($target_url)) { header("HTTP/1.1 400 Bad Request"); echo "Missing 'url' parameter."; exit; } // 确保 URL 带有协议头 if (!preg_match("~^https?://~i", $target_url)) { $target_url = "http://" . $target_url; } // 解析出基础域名和 Scheme(用于后续拼接相对路径) $parsed_url = parse_url($target_url); if (!$parsed_url || !isset($parsed_url['host'])) { header("HTTP/1.1 400 Bad Request"); echo "Invalid URL."; exit; } $base_url = $parsed_url['scheme'] . '://' . $parsed_url['host']; // 2. 初始化 cURL 用于请求 function fetch_content($url) { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); // 跟随重定向 curl_setopt($ch, CURLOPT_TIMEOUT, 10); // 设置超时 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 忽略SSL证书错误 curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'); $data = curl_exec($ch); $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); return [$data, $http_code]; } $favicon_url = null; // 3. 步骤一:尝试抓取网页 HTML 并解析 list($html, $code) = fetch_content($target_url); if ($code == 200 && !empty($html)) { // 使用 DOMDocument 解析 HTML,比正则更稳定 $dom = new DOMDocument(); // 禁用错误报错(防止 HTML 结构不规范弹出警告) libxml_use_internal_errors(true); $dom->loadHTML($html); libxml_clear_errors(); $links = $dom->getElementsByTagName('link'); foreach ($links as $link) { $rel = strtolower($link->getAttribute('rel')); // 匹配常见的 icon 关键词 if (in_array($rel, ['icon', 'shortcut icon', 'apple-touch-icon'])) { $href = $link->getAttribute('href'); if (!empty($href)) { $favicon_url = $href; break; // 找到第一个就跳出 } } } } // 4. 步骤二:如果 HTML 中没找到,或者请求失败,尝试降级读取根目录下的 favicon.ico if (empty($favicon_url)) { $favicon_url = $base_url . '/favicon.ico'; } else { // 5. 步骤三:补全相对路径 if (substr($favicon_url, 0, 2) === '//') { $favicon_url = $parsed_url['scheme'] . ':' . $favicon_url; } elseif (substr($favicon_url, 0, 1) === '/') { $favicon_url = $base_url . $favicon_url; } elseif (!preg_match("~^https?://~i", $favicon_url)) { // 针对类似 "images/favicon.ico" 的相对路径 $favicon_url = rtrim($target_url, '/') . '/' . ltrim($favicon_url, '/'); } } // 6. 步骤四:请求真实的图标并输出 list($icon_data, $icon_code) = fetch_content($favicon_url); if ($icon_code == 200 && !empty($icon_data)) { // 简单判断并设置图片响应头(也可以根据实际后缀或 mime 动态设置) if (strpos($favicon_url, '.png') !== false) { header('Content-Type: image/png'); } elseif (strpos($favicon_url, '.svg') !== false) { header('Content-Type: image/svg+xml'); } else { header('Content-Type: image/x-icon'); } echo $icon_data; } else { // 如果连默认的也获取不到,可以返回一个你本地准备好的兜底透明图或默认图 header('Content-Type: image/png'); // 这里输出一个 1x1 的透明 PNG 或者是本地默认图标 echo base64_decode('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII='); }
你这个与我用ai写的这个算法上好像有点点区别,可能是获取优先级不一样;
获取的图标不一样;
https://i.ximi.me/logo.php?url=www.ximi.me
https://ink.tino.im/api/content/links/fetch-metadata?url=www.ximi.me
记得之前坛里也有佬整过一个 favicon.im
希米 不错,能开源嚒
可以让ai转写成php的
@Slf4j public class LinkUtils { private static final int TIMEOUT = 5000; private static final SSLSocketFactory TRUST_ALL_SSL_SOCKET_FACTORY = createTrustAllSslSocketFactory(); private LinkUtils() { } public static LinkInfoDTO fetchLinkInfo(String url) throws IOException { if (!StringUtils.hasText(url)) { return new LinkInfoDTO(); } String bareUrl = url.replaceFirst("^(?i)https?://", ""); try { return doFetchLinkInfo("https://" + bareUrl); } catch (IOException e) { return doFetchLinkInfo("http://" + bareUrl); } } private static LinkInfoDTO doFetchLinkInfo(String url) throws IOException { LinkInfoDTO linkInfo = new LinkInfoDTO(); linkInfo.setUrl(url); Connection conn = Jsoup.connect(url) .timeout(TIMEOUT) .maxBodySize(0) .userAgent( "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)" + " Chrome/120.0.0.0 Safari/537.36") .sslSocketFactory(TRUST_ALL_SSL_SOCKET_FACTORY) .ignoreContentType(true) .ignoreHttpErrors(true) .followRedirects(true); Connection.Response response = conn.execute(); String contentType = response.contentType(); if (contentType != null && !contentType.contains("text/html") && !contentType.contains("xhtml") && !contentType.contains("xml")) { return linkInfo; } Document doc = response.parse(); String name = doc.title().trim(); if (!StringUtils.hasText(name)) { name = getMetaContent(doc, "meta[property=og:title]", "meta[name=twitter:title]"); } linkInfo.setName(name); String logo = getLinkHref(doc, "link[rel~=(?i)apple-touch-icon]", "link[rel~=(?i)icon]"); if (!StringUtils.hasText(logo)) { logo = getMetaUrl(doc, "meta[property=og:image]", "meta[name=twitter:image]"); } if (!StringUtils.hasText(logo)) { try { java.net.URI uri = new java.net.URI(url); logo = uri.getScheme() + "://" + uri.getHost() + "/favicon.ico"; } catch (Exception ignored) { // Ignore URI errors for fallback } } linkInfo.setLogo(logo); String description = getMetaContent(doc, "meta[name=description]", "meta[property=og:description]", "meta[name=twitter:description]"); linkInfo.setDescription(description); linkInfo.setCharset(response.charset()); return linkInfo; } private static String getMetaUrl(Document doc, String... selectors) { for (String selector : selectors) { Element element = doc.selectFirst(selector); if (element != null) { String url = element.attr("abs:content").trim(); if (StringUtils.hasText(url) && (url.startsWith("http") || url.startsWith("data:"))) { return url; } } } return ""; } private static String getMetaContent(Document doc, String... selectors) { for (String selector : selectors) { Element element = doc.selectFirst(selector); if (element != null) { String content = element.attr("content").trim(); if (StringUtils.hasText(content) && !content.startsWith("data:")) { return content; } } } return ""; } private static String getLinkHref(Document doc, String... selectors) { for (String selector : selectors) { Element element = doc.selectFirst(selector); if (element != null) { String href = element.attr("abs:href").trim(); if (StringUtils.hasText(href) && (href.startsWith("http") || href.startsWith("data:"))) { return href; } } } return ""; } private static SSLSocketFactory createTrustAllSslSocketFactory() { try { TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() { @Override public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } @Override public void checkClientTrusted(X509Certificate[] certs, String authType) { } @Override public void checkServerTrusted(X509Certificate[] certs, String authType) { } } }; SSLContext sc = SSLContext.getInstance("TLS"); sc.init(null, trustAllCerts, new SecureRandom()); return sc.getSocketFactory(); } catch (Exception e) { log.error("Failed to create trust-all SSLSocketFactory", e); return (SSLSocketFactory) SSLSocketFactory.getDefault(); } } }
佳茗 记得之前坛里也有佬整过一个 favicon.im
功能不错,但是广告太多太离谱了
希米 你这个与我用ai写的这个算法上好像有点点区别,可能是获取优先级不一样; 获取的图标不一样; https://i.ximi.me/logo.php?url=www.ximi.me https://ink ...
对的,我的优先级是 apple-touch-icon > icon > og:image > twitter:image > favicon.ico(兜底)
tino 可以让ai转写成php的 @Slf4j public class LinkUtils { private static final int TIMEOUT = 5000; private static ...
根据你提供的代码转化好了
logo:
json:
https://i.ximi.me/json.php?url=www.ximi.me
代码如下:
<?php // 1. 设置响应头为 JSON 格式 header('Content-Type: application/json; charset=utf-8'); // 2. 获取并清理 URL $target_url = isset($_GET['url']) ? trim($_GET['url']) : ''; if (empty($target_url)) { echo json_encode([ "status" => 400, "message" => "Bad Request", "devMessage" => "Missing 'url' parameter.", "data" => null ], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); exit; } // 补全协议头 if (!preg_match("~^https?://~i", $target_url)) { $target_url = "https://" . $target_url; } // 解析域名基础路径 $parsed_url = parse_url($target_url); if (!$parsed_url || !isset($parsed_url['host'])) { echo json_encode([ "status" => 400, "message" => "Bad Request", "devMessage" => "Invalid URL.", "data" => null ], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); exit; } $base_url = $parsed_url['scheme'] . '://' . $parsed_url['host']; // 3. 构造纯原生的请求环境(模拟浏览器) $context = stream_context_create([ 'http' => [ 'method' => 'GET', 'header' => "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36\r\n", 'timeout' => 5, 'follow_location' => 1, 'ignore_errors' => true ], 'ssl' => [ 'verify_peer' => false, 'verify_peer_name' => false, ] ]); // 4. 抓取网页 HTML $html = @file_get_contents($target_url, false, $context); // 初始化返回的 Data 结构 (对应你的 LinkInfoDTO) $data = [ "url" => $target_url, "name" => "", "logo" => "", "description" => "", "charset" => "UTF-8" // 默认给 UTF-8 ]; if ($html) { // 5. 尝试从 Response Header 中或 HTML 中提取 Charset // 这里简单通过正则从 HTML 匹配 charset if (preg_match('/<meta[^>]+charset=["\']?([\w-]+)/i', $html, $matches)) { $data['charset'] = strtoupper($matches[1]); } // 6. 提取网站标题 Name (优先找 <title>,找不到找 og:title) if (preg_match('/<title>(.*?)<\/title>/is', $html, $matches)) { $data['name'] = trim($matches[1]); } if (empty($data['name'])) { if (preg_match('/<meta[^>]+(?:property|name)=["\'](?:og|twitter):title["\'][^>]+content=["\']([^"\']+)["\']/i', $html, $matches)) { $data['name'] = trim($matches[1]); } } // 7. 用正则匹配 <link> 标签中的 icon / logo $favicon_url = ''; if (preg_match('/<link[^>]+rel=["\'](?:shortcut )?icon["\'][^>]+href=["\']([^"\']+)["\']/i', $html, $matches)) { $favicon_url = $matches[1]; } else { // 尝试匹配苹果设备高清图标 if (preg_match('/<link[^>]+rel=["\']apple-touch-icon[^"\']*["\'][^>]+href=["\']([^"\']+)["\']/i', $html, $matches)) { $favicon_url = $matches[1]; } } // 如果 HTML 没找到 logo,尝试找 og:image if (empty($favicon_url)) { if (preg_match('/<meta[^>]+(?:property|name)=["\'](?:og|twitter):image["\'][^>]+content=["\']([^"\']+)["\']/i', $html, $matches)) { $favicon_url = $matches[1]; } } // 8. 路径补全逻辑 if (empty($favicon_url)) { $favicon_url = $base_url . '/favicon.ico'; } else { if (substr($favicon_url, 0, 2) === '//') { $favicon_url = $parsed_url['scheme'] . ':' . $favicon_url; } elseif (substr($favicon_url, 0, 1) === '/') { $favicon_url = $base_url . $favicon_url; } elseif (!preg_match("~^https?://~i", $favicon_url)) { $favicon_url = rtrim($target_url, '/') . '/' . ltrim($favicon_url, '/'); } } $data['logo'] = $favicon_url; // 9. 提取网站描述 Description if (preg_match('/<meta[^>]+(?:name|property)=["\'](?:description|og:description|twitter:description)["\'][^>]+content=["\']([^"\']+)["\']/i', $html, $matches)) { $data['description'] = trim($matches[1]); } } // 10. 组装最终的目标 JSON 格式 $result = [ "status" => 200, "message" => "OK", "devMessage" => null, "data" => $data ]; // 输出 JSON echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
希米出品,必属精品。
期待开源
cjwlove 希米出品,必属精品。 期待开源
代码就在楼上
希米 根据你提供的代码转化好了 logo: https://i.ximi.me/logo.php?url=www.ximi.me json: https://i.ximi.me/json.php?url=w ...
学习
不错!
https://api.mrwang.com/ico.php?url=https://www.google.com/