65

I log into a website using WKWebView and now i would like to parse the html of the website. How can I access the websites html in swift? I know how it works for a UIWebView but not for WKWebView.

Thanks for your help!

MotoxX
  • 917
  • 1
  • 7
  • 13

4 Answers4

123

If you wait until the page has loaded you can use:

webView.evaluateJavaScript("document.documentElement.outerHTML.toString()") {
    print(html)
}

You could also inject some javascript that returns you back the HTML.

let script = WKUserScript(source: javascriptString, injectionTime: injectionTime, forMainFrameOnly: true)
userContentController.addUserScript(script)
self.webView.configuration.userContentController.addScriptMessageHandler(self, name: "didGetHTML")

…

func userContentController(userContentController: WKUserContentController,
        didReceiveScriptMessage message: WKScriptMessage) {
     
    guard message.name == "didGetHTML", 
        let html = message.body as? String else { 
        return 
    }

    print(html)
}

The javascript you could inject looks something like:

webkit.messageHandlers.didGetHTML.postMessage(document.documentElement.outerHTML.toString());
Onato
  • 9,916
  • 5
  • 46
  • 54
  • after modified cssRule inside internal- – Kyle KIM Jun 21 '16 at 19:27
  • @Onato How to load back that grabbed html? – onCompletion Dec 12 '16 at 11:53
  • My interpretation of this question is: How can i get the HTML from a web page, such that i can reload it and have it function EXACTLY the same. This accepted answer does NOT answer this question. At least in my app, the testing reveals no clickable links despite the page *showing* properly. I currently have no lead about how to save the HTML and reload it such that the page is as it was. Perhaps using String(contentsOf: url) to get teh HTML and trying it that way rather than loading via wkWebView itself? – drew.. May 17 '18 at 01:53
  • 1
    I would suggest posting a new question including more details of the goal you are trying to achieve. Feel free to link it here. – Onato May 30 '18 at 05:57
  • 1
    Hmm.. I'm getting: () printed even though there is a full webpage. – ScottyBlades Jan 04 '22 at 04:00
12

Swift <-> WKWebView

get HTML from WKWebView

wkWebView.evaluateJavaScript("document.body.innerHTML", completionHandler: { (value: Any!, error: Error!) -> Void in
    if error != nil {
        //Error logic
        return
    }

    //let result = value as? String
    //Main logic
})

set HTML into WKWebView

//Do not forget to extend a class from `WKNavigationDelegate`

func someFunction() {
    let wkWebView = WKWebView()
    
    wkWebView.loadHTMLString("<html><body></body></html>", baseURL: nil)
    wkWebView.navigationDelegate = self as? WKNavigationDelegate
}

func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
    //ready to be processed
}

[Swift <-> UIWebView]

yoAlex5
  • 29,217
  • 8
  • 193
  • 205
1

I was here to try to get clues about getting result after asking token form DROPBOX new APIS. (I am implementing their flow WITHOUT all the stuff of their SDK) Hope can help someone.

Now Dropbox uses a web page as login, and calls back YOUR url where You can process token.

import WebKit
import SwiftUI

// some code from:
// https://benoitpasquier.com/create-webview-in-swiftui/
// THX pasquier!

let APP_KEY = "YOUR APP KEY"
let REDIRECT_URI = "<YOUR SITE>.dropbox_auth.php"
let DB_URL = "https://www.dropbox.com/1/oauth2/authorize?client_id=APP_KEY&token_access_type=offline&response_type=code&redirect_uri=REDIRECT_URI"

class MyWKDelegate: NSObject, WKNavigationDelegate{
    
    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        print("End loading")
        webView.evaluateJavaScript("document.body.innerHTML", completionHandler: { result, error in
            
            if let html = result as? String {
                    print(html)
                }
            })
    }
}

struct WebView: UIViewRepresentable {
        
    typealias UIViewType = WKWebView

    let webView: WKWebView
    
    func makeUIView(context: Context) -> WKWebView {
        return webView
    }
    
    func updateUIView(_ uiView: WKWebView, context: Context) { }
}


class WebViewModel: ObservableObject {
    let webView: WKWebView
    let url: URL!
    let delegate = MyWKDelegate()
    
    init() {
        webView = WKWebView(frame: .zero)
        webView.navigationDelegate = delegate

        let urlStr = DB_URL.replacingOccurrences(of: "APP_KEY", with: APP_KEY).replacingOccurrences(of: "REDIRECT_URI", with: REDIRECT_URI)
        print(urlStr)
        url = URL(string: urlStr)

        loadUrl()
    }
    
    func loadUrl() {
        webView.load(URLRequest(url: url))
    }
}
ingconti
  • 10,876
  • 3
  • 61
  • 48
0

Combining answers 1 and 3 did the trick for me:

func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
   print("End loading")        
   webView.evaluateJavaScript("document.documentElement.outerHTML", completionHandler: { result, error in         
      if let datHtml = result as? String {
         print(datHtml)
         // parse datHtml here
         }
      } )
    }
Markv07
  • 196
  • 1
  • 8