FaviconFinder: Simple Favicon Finding

FaviconFinder

iOS - CI Status macOS - CI Status Linux - CI Status

SPM Compatible Swift 5.10 Swift 6.0 Bluesky

FaviconFinder 是一个小型、纯 Swift 库,专为 iOS、macOS 和 Linux 应用程序设计,可帮助您检测网站使用的网站图标。

为什么不直接下载 https://site.com/favicon.ico 上的文件呢?开发者可以放置网站图标的位置有很多,不仅仅是在根目录下使用特定的文件名 favicon.ico。网站图标的地址可能链接在 HTML 头部标签中,或者可能在 Web 应用程序清单 JSON 文件中,甚至可能是一个具有自定义文件名的文件。

FaviconFinder 为您处理这些繁琐的工作,并遍历所有可能的网站图标位置,一旦找到,就会简单地将图像交付给您。

FaviconFinder 将会

目录

  1. 简介
  2. 用法
  3. 工作原理
  4. 文档
  5. 高级用法
  6. 示例项目
  7. 要求
  8. 安装
  9. 作者
  10. 许可证

用法

FaviconFinder 使用简单的语法,让您可以轻松下载所需的网站图标,并继续您的项目。只需将此代码插入您的项目中即可。

    let favicon = try await FaviconFinder(url: url)
        .fetchFaviconURLs()
        .download()
        .largest()

    self.imageView.image = favicon.image

FaviconFinder 将遍历网站图标可能存在的各种来源,并确保检查每个来源。目前,来源包括

一旦 FaviconFinder 找到特定来源的所有可用网站图标,它将返回一个 FaviconURL 数组。FaviconURL 将包含图像的源 URL,以及从其提取图像的位置存在的其他元数据(即,相关的 HTML 标签等)。

FaviconURL 数组上,您可以调用 download(),它将下载每个 FaviconURL 并将您的数组转换为 Favicon 数组。Favicon 包含图像、其原始数据和 FaviconURL 属性。

Favicon 数组上,您可以调用

FaviconFinder 适用于 UIKit、SwiftUI、AppKit 和 macOS Catalyst。

FaviconFinder 还支持 Linux 平台,并且我重新实现了 FaviconFinder 的部分内容,以确保 Linux 被视为一流平台。重要的是要注意,Linux 上的 Swift 本身不支持任何 Image 格式,因此当您调用 download 时,只会下载 data 本身,而没有图像类型可以将数据转换为该类型。 также из-за этого,largest()smallest() 在 Linux 上无效。

工作原理

FaviconFinder 通过自动搜索网站图标可以定义的各种位置,简化了定位和检索网站图标的过程。由于网站图标可能存在于多个位置,FaviconFinder 会系统地查询每个潜在来源,并遵循您可以自定义的优先级顺序。

主要步骤

  1. HTML 标头查询和解析
    FaviconFinder 首先查询您提供的 URL。然后,它检查网页的 HTML,并在下载的 HTML 文件的标头中查找 <link><meta> 标签中的任何网站图标声明。这可以包括指定为标准图标的网站图标 (<link rel="icon">)、Apple touch 图标 (<link rel="apple-touch-icon">) 或在 Open Graph 元数据中定义的其他图标。

  2. 回退到网站图标文件
    如果在 HTML 中未找到网站图标,FaviconFinder 将检查域根目录中的传统网站图标位置 (https://site.com/favicon.ico)。这是许多网站放置其网站图标的默认位置,因此此检查是一种快速有效的回退方法。如果在此处找不到,FaviconFinder 将检查提供的 URL 是否为子域(即 https://example.site.com),如果是,将查询根域(即 https://site.com)。

  3. 回退到 Web 应用程序清单文件
    对于使用 Web 应用程序清单 (manifest.json) 的站点,FaviconFinder 会解析 JSON 文件,以查找专门为渐进式 Web 应用程序定义的任何图标。这些图标通常在移动优化的网站或应用程序中找到,并提供更高分辨率的网站图标。

  4. Meta-Refresh 重定向(可选)
    某些网站可能使用 meta-refresh 重定向而不是服务器端 HTTP 重定向。如果在配置中启用,FaviconFinder 将检查 HTML 中是否存在这些 meta-refresh 重定向,并跟随它们以从重定向的 URL 检索网站图标。

  5. 网站图标大小排序
    FaviconFinder 从 HTML 或 Web 应用程序清单中提取大小元数据,以按尺寸(例如,120x120、32x32)对网站图标进行排序。这使您可以轻松确定最大或最小的网站图标,而无需下载每个图像,从而节省带宽并提高性能。

  6. 自定义和偏好设置
    FaviconFinder 允许您自定义其搜索网站图标的方式。您可以优先考虑某些网站图标类型(例如,Apple touch 图标、.ico 文件),甚至可以为身份验证提供预取 HTML 或自定义 HTTP 标头,从而使您可以完全控制库与站点的交互方式。

  7. 跨平台兼容性
    FaviconFinder 旨在跨 macOS、iOS 和 Linux 工作。它会根据平台调整其方法,因此无论您是在 SwiftUI、UIKit 还是 AppKit 中工作,都可以无缝使用它。在 Linux 上,即使平台缺少本机图像处理功能,FaviconFinder 也能确保兼容性,而是使用数据驱动的方法。

文档

虽然此自述文件提供了 FaviconFinder 的基本概述、如何使用它以及它可以做什么,但更全面的文档可以在这里找到

https://will-lumley.github.io/FaviconFinder/documentation/faviconfinder/

高级用法和配置

优先下载

如果您想要精细控制要查找的网站图标类型,FaviconFinder 可以让您轻松指定您的偏好。您可以选择您希望首先查询哪个网站图标来源 - 无论是 HTML、实际文件还是 Web 应用程序清单文件 - 甚至可以为每个来源指定您想要的网站图标类型。

例如,您可能更喜欢在 HTML 标头中声明的网站图标,并且特别想要 appleTouchIcon 类型。FaviconFinder 将在 HTML 中搜索该特定标签,但如果未找到,它将自动搜索其他 HTML 网站图标类型。

如果指定的下载类型(例如,HTML 或 .ico)不可用,FaviconFinder 将自动尝试其他可用方法,如果找不到任何方法,它将返回错误。

您还可以请求 FaviconFinder 检查 HTML 中的 meta-refresh 重定向,使其能够跟随任何重定向并查询正确的 URL。

以下是如何配置您的偏好的示例

    let favicon = try await FaviconFinder(
        url: url,
        configuration: .init(
            preferredSource: .html,
            preferences: [
                .html: FaviconFormatType.appleTouchIcon.rawValue,
                .ico: "favicon.ico",
                .webApplicationManifestFile: FaviconFormatType.launcherIcon4x.rawValue
            ]
        )
    )
        .fetchFaviconURLs()
        .download()
        .largest()

    self.imageView.image = favicon.image

这允许您控制

如果您的首选下载类型在 URL 上不可用(例如,没有文件或没有 HTML 标签指定网站图标),FaviconFinder 将尝试其他来源,直到找到有效的网站图标或返回错误。

Meta-Refresh 重定向

当站点从 oldsite.com 移动到 newsite.com 时,常见的做法是让 oldsite.com 响应 HTTP 301 重定向,以及要重定向到的 URL。在此示例中,URLSession(以及扩展的大多数获取网站图标的库)将在收到 HTTP 301 重定向后,本机重新请求 newsite.com。

然而,还有一种不太常用(坦率地说较差)的重定向方法 - 它称为 meta-refresh 重定向。

这类似于 HTTP 301 重定向,只是它发生在前端,并且浏览器应该读取和解析 HTML,并以这种方式将用户发送到新的 URL。当 URLSession 遇到指向包含 meta-refresh 重定向的 HTML 文件的 HTTP 请求时,什么也不会发生。

但是,使用 FaviconFinder,您很幸运。如果您在配置中将其设置为这样做,FaviconFinder 将扫描您提供给它的 URL 中的 HTML,以查找任何 meta-refresh 重定向,以确保如果遇到 meta-refresh 重定向,您不必担心它。

但重要的是要注意,解析和检查此项可能会花费额外的计算时间,因此默认情况下它设置为关闭。

以下是如何使用它。

    let favicon = try await FaviconFinder(
        url: url,
        configuration: .init(
            preferredSource: .html,
            preferences: [
                .html: FaviconFormatType.appleTouchIcon.rawValue,
                .ico: "favicon.ico",
                .webApplicationManifestFile: FaviconFormatType.launcherIcon4x.rawValue
            ],
            checkForMetaRefreshRedirect: true
        )
    )
        .fetchFaviconURLs()
        .download()
        .largest()

    self.imageView.image = favicon.image

预取 HTML

FaviconFinder 允许您传递预取的 HTML 文档,以避免多次下载 HTML,或者如果您已经从其他来源获得 HTML 内容。您可以使用配置中的 prefetchedHTML 属性来传递此文档。

我们使用 SwiftSoup 的 Document 类型,因为它具有出色的 HTML 存储和解析功能,可以轻松地操作和遍历文档树。

此功能在以下情况下很有用

以下是如何使用它

import SwiftSoup

// Assuming you have already fetched and parsed the HTML
let htmlString = "<html><head>...</head></html>"
let document = try SwiftSoup.parse(htmlString)

let favicon = try await FaviconFinder(
    url: url,
    configuration: .init(prefetchedHTML: document)
)
    .fetchFaviconURLs()
    .download()
    .largest()

self.imageView.image = favicon.image

查询需要身份验证的网站图标

在某些情况下,网站图标可能存储在身份验证层之后,或者需要自定义 HTTP 标头才能访问,例如 API 令牌或用户会话的 Cookie。FaviconFinder 支持使用自定义 HTTP 标头查询网站图标,即使它们需要身份验证,您也可以获取网站图标。

要指定自定义 HTTP 标头,您可以在初始化 FaviconFinder 时在 Configuration 对象中传递它们。这些标头将与 FaviconFinder 发出的每个 HTTP 请求一起发送,从而确保即使网站图标位于身份验证层之后也可以访问。

以下是如何设置使用自定义 HTTP 标头来访问需要身份验证的网站图标的请求的示例(例如,使用 bearer 令牌)

let headers = [
    "Authorization": "Bearer your_token_here",
    "Cookie": "session_id=your_session_id_here"
]

let favicon = try await FaviconFinder(
    url: url,
    configuration: .init(
        httpHeaders: headers
    )
)
    .fetchFaviconURLs()
    .download()
    .largest()

self.imageView.image = favicon.image

通过提供自定义 HTTP 标头,您可以处理更高级的场景,其中网站图标受到限制或受安全层保护,从而确保 FaviconFinder 在各种环境中保持灵活性和功能性。

无需下载即可按大小对网站图标 URL 进行排序

FaviconFinder 包含允许您确定可用最大或最小网站图标的功能,而无需首先下载所有图像。当您只需要基于大小元数据的最大或最小图像时,这对于优化性能非常有用。

通过检查 HTML 或 Web 应用程序清单文件中提供的大小标签,FaviconFinder 可以对可用的网站图标 URL 进行排序,并选择尺寸最大或最小的 URL。

要在不下载图像的情况下找到最大或最小的网站图标 URL

let faviconURL = try await FaviconFinder(url: url)
    .fetchFaviconURLs()
    .largest()  // or .smallest()

print("Largest Favicon URL: \(faviconURL.source)")

这将根据大小标签中的元数据返回最大或最小的网站图标。

一旦您确定了最大或最小的网站图标 URL,您就可以继续下载实际图像

let largestFavicon = try await FaviconFinder(url: url)
    .fetchFaviconURLs()
    .largest()
    .download()

self.imageView.image = largestFavicon.image

使用此方法有优点和缺点。

优点

局限性

此功能使您可以有效地按大小对网站图标 URL 进行排序,并仅下载您需要的网站图标,使其成为以优化方式处理网站图标的强大工具。

标头和 Hero 图像

有时您可能想要从 URL 获取标头或 Hero 图像。您可以使用配置中的 acceptHeaderImage 参数告知 FaviconFinder 您希望它执行此操作。默认值设置为 false,此参数是可选参数。

您可以像这样使用它

let favicon = try await FaviconFinder(
    url: url,
    configuration: .init(acceptHeaderImage: true)
)
    .fetchFaviconURLs()
    .download()
    .largest()

示例项目

要运行示例项目,请克隆 repo,然后在 iOSFaviconFinderExamplemacOSFaviconFinderExample 中打开示例 Xcode 项目,具体取决于您的构建目标。

或者,如果您将其用于 Linux 项目,则可以打开位于 LinuxFaviconFinderExample 中的示例 Swift 项目。

要求

FaviconFinder 现在使用 Swift 6.0 编写。这意味着我们可以使用 Swift Testing 而不是 XCTest,但更重要的是,这意味着 FaviconFinder 现在是数据竞争安全的,并遵守严格的并发性。

Swift 6.0 从 5.1.0 及更高版本开始支持。如果您需要在 Swift 5.9 及更低版本中使用 FaviconFinder,请使用版本 5.0.4

FaviconFinder 现在支持 await/async 并发,如下面的示例所示。因此,最新版本的 FaviconFinder 需要 iOS 15.0 和 macOS 12.0。如果您需要支持旧版本的 iOS 或 macOS,FaviconFinder 的版本 3.3.0 使用闭包来回调成功/失败,而不是 await/async 并发。

安装

Swift Package Manager

FaviconFinder 可通过 Swift Package Manager 获得。要安装它,只需将依赖项添加到您的 Package.Swift 文件中

...
dependencies: [
    .package(url: "https://github.com/will-lumley/FaviconFinder.git", from: "5.1.4"),
],
targets: [
    .target( name: "YourTarget", dependencies: ["FaviconFinder"]),
]
...

Cocoapods 和 Carthage

FaviconFinder 以前可以通过 CocoaPods 和 Carthage 获得,但是使该库可用于所有三个平台(Cocoapods、Carthage 和 SPM)并在这三个平台上都能正常工作变得很麻烦。再加上 SPM 的采用率和功能显着提升,这导致我取消了对 CocoaPods 和 Carthage 的支持。

作者

William Lumley, will@lumley.io

许可证

FaviconFinder 在 MIT 许可证下可用。有关更多信息,请参阅 LICENSE 文件。