SwiftWebCrawler 是一个功能强大且可扩展的 Swift 库,旨在帮助开发者在 iOS 和 macOS 应用中轻松实现网页爬取功能。该库支持代理配置、并发控制、robots.txt 遵守以及详细的错误处理和日志记录。
- 跨平台支持:兼容 iOS 和 macOS,覆盖了大部分 Apple 生态系统设备。
- 模块化设计:独立的库,易于维护和扩展。
- 丰富的配置选项:通过
CrawlerConfiguration提供代理支持、并发控制等配置。 - 错误处理与日志记录:详细的错误分类和内置日志记录机制,便于调试和监控。
- 高效并发控制:使用
AsyncSemaphore和ResultsActor,确保在异步上下文中安全高效地处理并发任务。 - robots.txt 遵守:可选配置,确保爬虫行为符合网站规范。
- 代理支持:支持 HTTP、HTTPS 和 SOCKS 代理,包含可选的认证信息。
SwiftWebCrawler 通过 Swift Package Manager 提供,您可以轻松将其集成到您的项目中。
- 打开您的项目 在 Xcode 中。
- 添加包依赖:
- 在 Xcode 的菜单栏中,选择
File>Add Packages...。 - 在弹出的对话框中,输入您的包仓库地址,例如:
https://github.com/yourusername/SwiftWebCrawler.git - 点击
Add Package。
- 在 Xcode 的菜单栏中,选择
- 选择版本:
- 选择
Up to Next Major,并确保选择的是最新的稳定版本(例如,1.0.0)。
- 选择
- 完成安装:
- 点击
Add Package完成安装。现在,您可以在项目中导入并使用SwiftWebCrawler库。
- 点击
以下示例展示了如何在您的应用中爬取单个 URL 并获取其文本内容。
import SwiftWebCrawler
// 创建日志记录器
let logger = ConsoleLogger()
// 创建爬虫配置
let config = CrawlerConfiguration(
obeyRobotsTxt: true, // 启用 robots.txt 遵守
userAgent: "MyAppCrawler/1.0", // 自定义 User-Agent
minRequestInterval: 1.0, // 每个主机的最小请求间隔(秒)
proxy: nil, // 设置代理(可选)
maxConcurrentTasks: 3 // 最大并发任务数
)
// 初始化爬虫
let crawler = WebCrawler(configuration: config, logger: logger)
// 爬取单个 URL
Task {
let url = "https://www.example.com"
let result = await crawler.crawl(urlString: url)
switch result {
case .success(let text):
print("Crawling succeeded for \(url). Text length: \(text.count)")
case .failure(let error):
print("Crawling failed for \(url). Error: \(error.description)")
}
}以下示例展示了如何同时爬取多个 URL,并获取每个 URL 的爬取结果。
import SwiftWebCrawler
// 创建日志记录器
let logger = ConsoleLogger()
// 创建爬虫配置
let config = CrawlerConfiguration(
obeyRobotsTxt: true, // 启用 robots.txt 遵守
userAgent: "MyAppCrawler/1.0", // 自定义 User-Agent
minRequestInterval: 1.0, // 每个主机的最小请求间隔(秒)
proxy: nil, // 设置代理(可选)
maxConcurrentTasks: 3 // 最大并发任务数
)
// 初始化爬虫
let crawler = WebCrawler(configuration: config, logger: logger)
// 爬取多个 URL
Task {
let urls = [
"https://www.apple.com",
"https://www.google.com",
"https://www.invalidurltest12345.com", // 无效 URL 示例
"https://www.wikipedia.org"
]
let results = await crawler.crawlBatch(urls: urls)
for (url, result) in results {
switch result {
case .success(let text):
print("Crawling succeeded for \(url). Text length: \(text.count)")
case .failure(let error):
print("Crawling failed for \(url). Error: \(error.description)")
}
}
}CrawlerConfiguration 结构体允许您自定义爬虫的行为。以下是可配置的参数:
public struct CrawlerConfiguration {
/// 是否遵守 robots.txt 规则
public var obeyRobotsTxt: Bool
/// HTTP 请求中使用的 User-Agent 字符串
public var userAgent: String
/// 对同一主机的最小请求间隔(秒)
public var minRequestInterval: TimeInterval
/// 可选的代理配置
public var proxy: ProxyConfiguration?
/// 最大并发爬取任务数
public var maxConcurrentTasks: Int
/// 初始化 CrawlerConfiguration
public init(
obeyRobotsTxt: Bool = true,
userAgent: String = "SwiftWebCrawler/1.0",
minRequestInterval: TimeInterval = 2.0,
proxy: ProxyConfiguration? = nil,
maxConcurrentTasks: Int = 5
) {
self.obeyRobotsTxt = obeyRobotsTxt
self.userAgent = userAgent
self.minRequestInterval = minRequestInterval
self.proxy = proxy
self.maxConcurrentTasks = maxConcurrentTasks
}
}ProxyConfiguration 结构体允许您配置爬虫使用的代理服务器,包括代理类型、主机、端口以及可选的认证信息。
public enum ProxyType {
case http
case https
case socks
}
public struct ProxyConfiguration {
public var type: ProxyType
public var host: String
public var port: Int
public var username: String?
public var password: String?
/// 初始化 ProxyConfiguration
public init(
type: ProxyType = .http,
host: String,
port: Int,
username: String? = nil,
password: String? = nil
) {
self.type = type
self.host = host
self.port = port
self.username = username
self.password = password
}
}示例:
let proxyConfig = ProxyConfiguration(
type: .http,
host: "127.0.0.1",
port: 8080,
username: "proxyUser",
password: "proxyPass"
)
let config = CrawlerConfiguration(
obeyRobotsTxt: true,
userAgent: "MyAppCrawler/1.0",
minRequestInterval: 1.0,
proxy: proxyConfig,
maxConcurrentTasks: 3
)SwiftWebCrawler 提供了一个简单的日志记录机制,帮助您监控爬虫的运行状态。默认情况下,使用 ConsoleLogger 将日志输出到控制台。
您可以创建自己的日志记录器,遵循 Logger 协议:
public protocol Logger {
func log(_ message: String)
}
public class ConsoleLogger: Logger {
public init() {}
public func log(_ message: String) {
print("[SwiftWebCrawler] \(message)")
}
}
// 示例:创建自定义日志记录器
public class FileLogger: Logger {
private let fileURL: URL
public init(fileURL: URL) {
self.fileURL = fileURL
}
public func log(_ message: String) {
let logMessage = "[SwiftWebCrawler] \(message)\n"
if let data = logMessage.data(using: .utf8) {
if FileManager.default.fileExists(atPath: fileURL.path) {
if let handle = try? FileHandle(forWritingTo: fileURL) {
handle.seekToEndOfFile()
handle.write(data)
handle.closeFile()
}
} else {
try? data.write(to: fileURL)
}
}
}
}SwiftWebCrawler 使用 Result 类型返回爬取结果,包含成功的文本内容或详细的错误信息。以下是 WebCrawlerError 枚举,描述了可能发生的错误类型:
public enum WebCrawlerError: Error, CustomStringConvertible, Equatable {
case invalidURL
case requestFailed(statusCode: Int)
case decodingFailed
case parsingFailed
case robotsTxtDisallowed
case robotsTxtFetchFailed
case robotsTxtParsingFailed
case unsupportedURLScheme
public var description: String {
switch self {
case .invalidURL:
return "Invalid URL."
case .requestFailed(let statusCode):
return "Request failed with status code: \(statusCode)."
case .decodingFailed:
return "Failed to decode data."
case .parsingFailed:
return "Failed to parse HTML."
case .robotsTxtDisallowed:
return "Crawling disallowed by robots.txt."
case .robotsTxtFetchFailed:
return "Failed to fetch robots.txt."
case .robotsTxtParsingFailed:
return "Failed to parse robots.txt."
case .unsupportedURLScheme:
return "Unsupported URL scheme."
}
}
}使用示例:
let result = await crawler.crawl(urlString: url)
switch result {
case .success(let text):
print("Crawling succeeded. Text length: \(text.count)")
case .failure(let error):
print("Crawling failed. Error: \(error.description)")
}以下示例展示了如何在 macOS 和 iOS 应用中集成和使用 SwiftWebCrawler 库。
import SwiftWebCrawler
// 创建代理配置(可选)
let proxyConfig = ProxyConfiguration(
type: .http,
host: "127.0.0.1",
port: 8080,
username: "proxyUser",
password: "proxyPass"
)
// 创建日志记录器
let logger = ConsoleLogger()
// 创建爬虫配置
let config = CrawlerConfiguration(
obeyRobotsTxt: true, // 启用 robots.txt 遵守
userAgent: "MyMacAppCrawler/1.0", // 自定义 User-Agent
minRequestInterval: 1.0, // 每个主机的最小请求间隔(秒)
proxy: proxyConfig, // 设置代理(可选)
maxConcurrentTasks: 3 // 最大并发任务数
)
// 初始化爬虫
let crawler = WebCrawler(configuration: config, logger: logger)
// 爬取单个 URL
Task {
let url = "https://www.example.com"
let result = await crawler.crawl(urlString: url)
switch result {
case .success(let text):
print("Crawling succeeded for \(url). Text length: \(text.count)")
case .failure(let error):
print("Crawling failed for \(url). Error: \(error.description)")
}
}
// 爬取多个 URL
Task {
let urls = [
"https://www.apple.com",
"https://www.google.com",
"https://www.invalidurltest12345.com", // 无效 URL 示例
"https://www.wikipedia.org"
]
let results = await crawler.crawlBatch(urls: urls)
for (url, result) in results {
switch result {
case .success(let text):
print("Crawling succeeded for \(url). Text length: \(text.count)")
case .failure(let error):
print("Crawling failed for \(url). Error: \(error.description)")
}
}
}import SwiftWebCrawler
// 创建代理配置(可选)
let proxyConfig = ProxyConfiguration(
type: .http,
host: "127.0.0.1",
port: 8080,
username: "proxyUser",
password: "proxyPass"
)
// 创建日志记录器
let logger = ConsoleLogger()
// 创建爬虫配置
let config = CrawlerConfiguration(
obeyRobotsTxt: true, // 启用 robots.txt 遵守
userAgent: "MyiOSAppCrawler/1.0", // 自定义 User-Agent
minRequestInterval: 1.0, // 每个主机的最小请求间隔(秒)
proxy: proxyConfig, // 设置代理(可选)
maxConcurrentTasks: 3 // 最大并发任务数
)
// 初始化爬虫
let crawler = WebCrawler(configuration: config, logger: logger)
// 爬取单个 URL
Task {
let url = "https://www.example.com"
let result = await crawler.crawl(urlString: url)
switch result {
case .success(let text):
print("Crawling succeeded for \(url). Text length: \(text.count)")
case .failure(let error):
print("Crawling failed for \(url). Error: \(error.description)")
}
}
// 爬取多个 URL
Task {
let urls = [
"https://www.apple.com",
"https://www.google.com",
"https://www.invalidurltest12345.com", // 无效 URL 示例
"https://www.wikipedia.org"
]
let results = await crawler.crawlBatch(urls: urls)
for (url, result) in results {
switch result {
case .success(let text):
print("Crawling succeeded for \(url). Text length: \(text.count)")
case .failure(let error):
print("Crawling failed for \(url). Error: \(error.description)")
}
}
}注意事项:
- 异步任务:在 iOS 应用中,请确保在适当的生命周期方法中启动异步任务,例如在视图控制器的
viewDidLoad中。 - 后台模式:如果需要在应用进入后台时继续爬取,可以考虑配置后台任务,但这需要额外的处理。
SwiftWebCrawler 提供了全面的单元测试,确保库的稳定性和可靠性。您可以运行以下命令来执行测试:
swift test- 单个 URL 爬取成功:确保爬取有效 URL 能够成功获取文本内容。
- 单个 URL 爬取失败:确保爬取无效 URL 能够正确返回错误。
- 批量 URL 爬取:测试同时爬取多个 URL,包含有效和无效的 URL,验证结果的正确性。
- 代理配置:测试使用代理进行爬取,确保代理配置能够正确应用。
欢迎贡献代码、报告问题或提出改进建议!请遵循以下步骤:
- Fork 仓库。
- 创建新分支:
git checkout -b feature/YourFeatureName。 - 提交更改:
git commit -m 'Add some feature'。 - 推送到分支:
git push origin feature/YourFeatureName。 - 创建 Pull Request。
请确保您的代码符合项目的编码规范,并通过所有测试。
SwiftWebCrawler 采用 MIT 许可证。
如有任何问题或建议,请通过以下方式与我们联系:
- GitHub Issues: https://github.com/yourusername/SwiftWebCrawler/issues
- 电子邮件: [email protected]
感谢您使用 SwiftWebCrawler!我们致力于不断改进和优化,为您的开发工作提供支持。