如何在macOS中通过Swift从网页及Safari页面提取指定文本?
macOS下Swift获取网页文本及Safari页面特定字符串提取方案
针对你提出的两个问题,结合你遇到的webView.webFrame.frameElement.innerText赋值label无效的问题,我整理了基于现代WebKit框架(WKWebView)的可行解决方案——毕竟旧的NSWebView已经被官方弃用,兼容性和稳定性都远不如WKWebView。
1. 在macOS中通过Swift获取网页文本
核心思路
用WKWebView(WebKit的现代组件)加载网页,等页面完全加载后,通过evaluateJavaScript执行JS代码抓取网页文本,最后必须在主线程更新UI控件——这很可能是你之前赋值无效的关键原因。
完整代码示例
import Cocoa import WebKit class ViewController: NSViewController, WKNavigationDelegate { var webView: WKWebView! @IBOutlet weak var pageContentLabel: NSTextField! // 用于显示网页文本的Label override func viewDidLoad() { super.viewDidLoad() // 初始化WKWebView并添加到视图 let webConfig = WKWebViewConfiguration() webView = WKWebView(frame: view.bounds, configuration: webConfig) webView.navigationDelegate = self // 设置代理监听加载状态 view.addSubview(webView) // 加载目标网页(这里以example.com为例,也可以加载本地HTML文件) guard let targetUrl = URL(string: "https://example.com") else { print("无效的URL") return } webView.load(URLRequest(url: targetUrl)) } // 网页加载完成后触发的代理方法 func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { // 执行JS获取整个网页的文本内容 webView.evaluateJavaScript("document.documentElement.innerText") { [weak self] (result, error) in guard let self = self, let pageText = result as? String, error == nil else { print("获取网页文本失败: \(error?.localizedDescription ?? "未知错误")") return } // 必须在主线程更新UI,否则Label不会显示内容 DispatchQueue.main.async { self.pageContentLabel.stringValue = pageText } } } }
2. 在Safari页面(或任意网页)中提取特定字符串(如"Simple Text Example...")
两种提取方式
方式一:通过DOM元素定位提取(精准)
如果目标字符串在固定的DOM元素中(比如某个class或id的标签里),可以直接通过JS定位该元素并获取文本。假设你的HTML结构如下:
<!DOCTYPE html> <html> <head> <title>Test Page</title> </head> <body> <div class="target-section">Simple Text Example... This is the content we need.</div> <p>Other irrelevant content</p> </body> </html>
对应的Swift代码(放在webView(_:didFinish:)方法中):
webView.evaluateJavaScript("document.querySelector('.target-section').innerText") { [weak self] (result, error) in guard let self = self, let targetText = result as? String, error == nil else { print("提取目标文本失败: \(error?.localizedDescription ?? "未知错误")") return } DispatchQueue.main.async { // 更新Label显示提取到的内容 self.pageContentLabel.stringValue = targetText } }
方式二:通过正则表达式全局匹配(灵活)
如果目标字符串没有固定的DOM容器,可以先获取整个网页文本,再用正则表达式匹配提取:
// 放在webView(_:didFinish:)方法中 webView.evaluateJavaScript("document.documentElement.innerText") { [weak self] (result, error) in guard let self = self, let pageText = result as? String, error == nil else { print("获取网页文本失败") return } // 正则匹配以"Simple Text Example..."开头的内容 let regexPattern = #"Simple Text Example.*"# guard let regex = try? NSRegularExpression(pattern: regexPattern, options: .dotMatchesLineSeparators) else { print("正则表达式创建失败") return } let textRange = NSRange(pageText.startIndex..., in: pageText) if let matchResult = regex.firstMatch(in: pageText, options: [], range: textRange) { let extractedText = String(pageText[Range(matchResult.range, in: pageText)!]) DispatchQueue.main.async { self.pageContentLabel.stringValue = extractedText } } else { print("未找到目标字符串") } }
关于你之前代码无效的原因分析
你使用的webView.webFrame.frameElement.innerText是旧NSWebView的API,现在已经被官方弃用,出现无效问题通常是这几个原因:
- 网页未完全加载:你可能在页面还没加载完成时就调用了该方法,导致获取到空值;
- 未在主线程更新UI:UI控件的更新必须在主线程执行,直接赋值不会生效;
- API兼容性问题:旧的NSWebView在新版本macOS中存在兼容性bug,官方推荐使用WKWebView替代。
内容的提问来源于stack exchange,提问作者dàhóngpáo
相关产品推荐
相关产品推荐

