【问题标题】:Get HTML content after it is loaded加载后获取 HTML 内容
【发布时间】:2020-04-28 21:12:20
【问题描述】:

我有一个Share Extension,我在其中得到HTML,如下所示:

@objc func actionButtonTapped(){

        var html: String?

        if let item = extensionContext?.inputItems.first as? NSExtensionItem,
            let itemProvider = item.attachments?.first,
            itemProvider.hasItemConformingToTypeIdentifier("public.url") {
            itemProvider.loadItem(forTypeIdentifier: "public.url", options: nil) { (url, error) in
                if (url as? URL) != nil {

                    html = (self.getHTMLfromURL(url: url as? URL))

                    self.doStuff(html: html)
                }
            }
        }
}

问题:

我得到了 HTML,但没有得到完整的内容。如何获得网站的完整HTML-content

更新:

原因是我想抓取任何产品的price,但有些网站没有在第一个HTML-get 上加载price ...

link 就是一个很好的例子。如果您单击价格并检查它,您可以看到它在classcurrent-price 中。但是,如果我使用上述方法检索HTML,则不会显示此class

【问题讨论】:

  • 您是否考虑过使用带有 URLSession 的 URLRequest? session.dataTask 返回的数据元素应该可以转换为字符串表示,然后您可以对其进行解析。
  • @binaryPilot84 抱歉,我没有完全关注你。从未将 urlrequest 与 urlsession 一起使用。你能详细说明一下吗?:)
  • 你可以使用 async-await 函数调用
  • 不加载 WKWebView 就无法在 iOS 中抓取网页。

标签: javascript html ios swift


【解决方案1】:

这个函数会从后台线程的url字符串中找到HTML(以免锁定你的UI),然后在处理之后你可以在主线程上更新你的UI:

func getHtml(_ urlString: String, completion: @escaping (String?, Error?) -> Void) {
    DispatchQueue.global(qos: .userInitiated).async(execute: {
        guard let url = URL(string: urlString) else {
            print("URLError: \(urlString) doesn't seem to be a valid URL")
            return completion(nil, URLError.init(URLError.Code.badURL))
        }

        do {
            let html = try String(contentsOf: url, encoding: .ascii)
            print("HTML: \(html)")
            return completion(html, nil)
        } catch let error {
            print("Error: \(error)")
            return completion(nil, error)
        }
    })
}

用法:

getHtml("https://www.google.com", completion: { html, error in
    if let e = error {
        print(e)
        // handle your error
        return
    }
    print(html as Any)
    DispatchQueue.main.async {
        //update your UI on the main thread
    }
})

更新:

您真的应该在服务器端抓取网页内容。如果不提供 WKWebView,iOS 不会让你这样做。

在 iOS 中,如果您想要 Chrome 的“检查”功能等数据,则需要在 WKWebView 的 didFinish 函数中加载 javascript:

func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
    let doc = webView.evaluateJavaScript("document.documentElement.outerHTML", completionHandler: { html, error in
        print(html)
    })
}

【讨论】:

  • 这并不能真正解决我的问题。我更新了我的问题,也许现在更清楚了。
  • @Chris,我已经更新了我的答案,但是如果不显示 WKWebView,你就无法在 iOS 中真正做到这一点。您应该在服务器端进行抓取,然后将该数据返回到您的应用程序。
  • 问题是我在 Share Extension 中使用它,所以我可以从 Safari 访问我的应用程序,并从该扩展程序向我的应用程序添加内容。我不想有一个WKWebView insdie 我的ShareExtension,因为那真的没有意义。你明白我吗?
  • 嘿@Chris,我完全明白你想做的事,但不幸的是你需要在服务器端做。目前,您无法在 iOS 中执行此操作。可能是因为 Apple 认为这可能会导致加载页面和解析页面的用户体验变慢。
  • 我知道的解决方法是在 WKWebView 中加载页面并加载 Javascript。也许有一种方法可以在不显示的情况下加载 WKWebView。
【解决方案2】:

据我所知,加载客户端 Javascript 时存在问题,如果您使用 Promise 会有所帮助。

P.S.-看看这是否有用Client-side web access

【讨论】:

  • 感谢您的回答。我以前从未使用过Javascript。有没有办法在 Swift 中完成这项工作?
【解决方案3】:

这是一个使用 URLSession 和 URLRequest 的示例:

func retrieveHTML(from url: URL, completion: @escaping (String) -> Void) {
    let request = URLRequest(url: url)
    let session = URLSession(configuration: .ephemeral)
    let task = session.dataTask(with: request) { (data, response, error) in
        guard let data = data, error == nil else {
            print("Data not found, error encountered: \(error!)")
            return
        }

        if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 {
            let code = httpStatus.statusCode

            if code >= 400 {
                // You can do more here with these codes, but for sake of this example, we'll return
                print("Received error code from HTTP Response. Code: \(code)")
                return
            }

            if code == 301 || code == 302 {
                // You should update the incoming URL as it is moving, but early return not needed
                print("You could log this error here if desired")
            }
        }

        if let responseString = String(data: data, encoding: .utf8) {
            print("Data found, encoded as string")
            completion(responseString)
        }
    }
    task.resume()
}

您可能仍会遇到页面未完全加载的错误,具体取决于页面中 JavaScript 的呈现方式。这至少应该让你指向正确的方向。

【讨论】:

  • 我试了一下并打印了data我不认为它工作正常吗?如果您尝试使用此链接,例如:asos.com/de/adidas-performance/…
  • 价格在class=current-price,但如果我直接查找current-price 甚至199,95,我无法在您的函数中的retrieved data 中找到它?我在这里错过了什么吗?
  • 其实我认为我用你的代码得到的数据就是我用我的函数在问题中得到的确切数据......
  • 从中检索到的 HTML 可能不是您想要的。话虽如此,其中的 javascript 确实包含您需要的内容。该流具有您随后需要查询的 API URL,它返回一个相对简单的 JSON 流。它提供的链接是: /api/product/catalogue/v3/stockprice?productIds=12373010&store=DE&currency=EUR&keyStoreDataversion=j42uv2x-26 您可以将其附加到基本网址以制作 asos.com/api/product/catalogue/v3/ stockprice?productIds=12373010&store=DE&currency=EUR&keyStoreDataversion=j42uv2x-26 我会遍历生成的 JSON 来获取数据。
  • 那么我如何从示例网站获得价格?
猜你喜欢
  • 2019-06-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-06
相关资源
最近更新 更多