可编码或JSONSerialization-需要从网页上获取一些JavaScript包装的文本

时间:2018-08-30 20:48:06

标签: ios swift

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

当我查看网页的查看源-http://www.sikhnet.com/hukam时-这是我看到的一大段javascript代码,其中需要标记的内容用橙色突出显示:

enter image description here

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

我在此网页上也有一个

标记,我想将其打印为textviewcontroller的标题。 Codable / JSONSerialization还可以帮助我做到这一点吗?

1 个答案:

答案 0 :(得分:1)

您正在进入网络抓取工具的领域,这些人以作者未曾想到的方式从网页中提取信息。

您的问题是shabad_lines是JSON对象的属性,该对象是嵌入HTML文档中的一行Javascript代码内。看看您必须跳多少圈才能获得它? Codable在这里没有帮助。如果您认为“让我们使用regex做到这一点”,那么您自己会遇到另一个问题!

让我们分析一下Javascript代码:

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

这意味着页面正在向Drupal.setings对象添加属性。从那个物体取回来怎么样?在Safari或Chrome中打开调试控制台,然后输入以下内容:

Drupal.settings.hukam.shabad_lines.gurmukhi

我们将获得全部8行shabad!加上WKWebView允许您从网页执行Javascript的事实,并且您的想法应该浮现在脑海。


解决方案

从概念上讲很简单:加载页面,运行一行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)
        }
    }
}