ios - Codable 或 JSONSerialization - 需要从网页中获取一些 javascript 包装的文本
问题描述
初学者在这里-我试图找出谷歌的教程来帮助我做到这一点:我需要从一个网页中的 json 脚本中获取一些文本并将其打印到一个 textview 中。
当我查看网页的视图源时 - http://www.sikhnet.com/hukam - 这是我看到的一大块 javascript,其中我需要以橙色突出显示的标记:
我读过一些帖子,说从 Swift4 开始,json 解析现在通过 Codable 原生于 Swift。我还阅读了有关 JSONSerialization 的信息。但我不知道哪个更适合实现我的最终目标 - 将此标签中的文本打印到 textview ?我应该在这里使用哪一个?
我在这个网页上也有一个 <p> 标签,我想将它打印为我的 textviewcontroller 的标题。Codable/JSONSerialization 也可以帮助我做到这一点吗?
解决方案
您正在进入网络爬虫的领域,这些人以作者没有想到的方式从网页中提取信息。
您的问题是,它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)
}
}
}
推荐阅读
- excel - 当另一列中的值为YES时,是否有一个excel公式可以计算一个ID出现在该列中的次数?
- python - Python 图像库无法读取 HDFS 路径
- c++ - 如何以编程方式获取 gRPC / protobuf 版本?
- html - 如何在 Blogger 的主页上制作水平部分?
- sql - 编写返回层次结构所有成员的查询
- javascript - 对 Zebra TLP 2824 Plus 进行编程以在并排标签上打印条形码
- sql - 使用参数从左连接表返回所有、匹配或不匹配的行
- docusignapi - DocuSign API - 信封选项卡显示签名日期的日期和月份
- html - 如何在 Css 类中设置优先级?
- javascript - 在 jquery 数据表中选择单个复选框