Get HTML from WKWebview in Swift
Asked Answered
T

4

68

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!

Thursby answered 12/1, 2016 at 19:7 Comment(0)
F
127

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());
Farahfarand answered 13/1, 2016 at 5:32 Comment(5)
after modified cssRule inside internal-<style>, the webview displays as I modified. but document.documentElement.outerHTML.toString() does not get the new cssRule. any solution do you have?Roundly
@Farahfarand How to load back that grabbed html?Coexecutor
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?Dinner
I would suggest posting a new question including more details of the goal you are trying to achieve. Feel free to link it here.Farahfarand
Hmm.. I'm getting: (<html><head></head><body></body></html>) printed even though there is a full webpage.Womenfolk
M
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]

Mathamathe answered 17/7, 2019 at 19:36 Comment(0)
S
2

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))
    }
}
Schuler answered 5/8, 2021 at 18:5 Comment(0)
G
1

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
         }
      } )
    }
Gyatt answered 15/1, 2022 at 16:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.