首页 > 解决方案 > Codable 或 JSONSerialization - 需要从网页中获取一些 javascript 包装的文本

问题描述

初学者在这里-我试图找出谷歌的教程来帮助我做到这一点:我需要从一个网页中的 json 脚本中获取一些文本并将其打印到一个 textview 中。

当我查看网页的视图源时 - http://www.sikhnet.com/hukam - 这是我看到的一大块 javascript,其中我需要以橙色突出显示的标记:

在此处输入图像描述

我读过一些帖子,说从 Swift4 开始,json 解析现在通过 Codable 原生于 Swift。我还阅读了有关 JSONSerialization 的信息。但我不知道哪个更适合实现我的最终目标 - 将此标签中的文本打印到 textview ?我应该在这里使用哪一个?

我在这个网页上也有一个 <p> 标签,我想将它打印为我的 textviewcontroller 的标题。Codable/JSONSerialization 也可以帮助我做到这一点吗?

标签: iosswift

解决方案


您正在进入网络爬虫的领域,这些人以作者没有想到的方式从网页中提取信息。

您的问题是,它shabad_lines是嵌入在 HTML 文档中的一行 Javascript 代码中的 JSON 对象的一个​​属性。看看你必须跳过多少圈才能得到它?Codable在这里没有帮助。如果您认为“让我们用正则表达式来做”,那么您又为自己添加了另一个问题!

让我们分析一下Javascript代码:

jQuery.extend(Drupal.settings, { ... })

这意味着页面正在向Drupal.setings对象添加属性。从那个对象中取回它怎么样?在 Safari 或 Chrome 中打开调试控制台并输入:

Drupal.settings.hukam.shabad_lines.gurmukhi

我们得到了所有 8 行 shabad!再加上允许您从网页执行 Javascript的事实,WKWebView一些想法应该在您的脑海中浮现。


解决方案

它在概念上很简单:加载页面,运行一行 Javascript,将结果发送回 Swift。如果您不熟悉WKWebView事物之间的关系以及它们之间的关系,它可能看起来像个谜。嵌套是这样的:

  • WKWebView一个WKWebViewConfiguration,有一个WKUserContentController,有一个WKUserScript
  • 使用WKWebView加载网页
  • 使用WkUserScript执行 Javascript 并将消息发送回 Swift
  • 使用WKUserContentController定义消息处理程序,即 Javascript 与 Swift 通信的通道。

把所有东西放在一起:

class ViewController: UIViewController {
    private var webView: WKWebView!

    override func viewDidLoad() {
        super.viewDidLoad()

        // Create a request to load the page
        let request = URLRequest(url: URL(string: "http://www.sikhnet.com/hukam")!)

        // Create the webview and load the URL
        webView = createWebView()
        webView.load(request)
    }

    func createWebView() -> WKWebView {
        // This is the Javascript to execute you receive back `shabad_lines`
        // property of `Drupal.settings`.
        //
        // Note the `window.webkit.messageHandlers.shabad.postMessage(...)` call:
        // this is how you send a message from Javascript back to Swift. `shabad`
        // is a custom message handler that we will define below. Later, when we
        // get the message back, we will check that it did come from the `shabad`
        // handler and treat it accordingly. You can have as many message handlers
        // as you want but you should name them differently so you know where
        // each message came from.
        let jsSource = "window.webkit.messageHandlers.shabad.postMessage(Drupal.settings.hukam.shabad_lines.gurmukhi)"

        // Inject the script, to be executed after the page finishes loading
        let script = WKUserScript(source: jsSource, injectionTime: .atDocumentEnd, forMainFrameOnly: true)

        // 
        let contentController = WKUserContentController()

        // Define the `shabad` message handler
        contentController.add(self, name: "shabad")

        // Add the script to the `WKWebView`. The script will executed every time
        // you load a webpage, even if it's not sikhnet.com
        contentController.addUserScript(script)

        // Finally, we can build a web view with the everything we want
        let config = WKWebViewConfiguration()
        config.userContentController = contentController
        return WKWebView(frame: .zero, configuration: config)
    }
}

extension ViewController: WKScriptMessageHandler {  
    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        // We received a message from Javascript! Check its name and process the
        // message's body
        if message.name == "shabad", let lines = message.body as? [String] {
            // Now you have your 8 lines of shabad
            print(lines)
        }
    }
}

推荐阅读