Swift解析PHP网页失败求助:http://www.ggjh.co.kr/now/menu.php
问题分析与解决方案
首先可以拍板说:.php后缀绝对不是问题——PHP只是后端运行的脚本,最终返回给客户端的还是标准的HTML文本,和静态.html页面没有本质区别。你的解析失败大概率是以下几个常见原因导致的,咱们逐一排查解决:
1. 先排查ATS(App Transport Security)限制
iOS默认禁止HTTP明文请求(只允许HTTPS),而你访问的是http://www.ggjh.co.kr(HTTP协议),这会被ATS直接拦截,这是最常见的触发点!
解决方法:
在Info.plist中添加ATS例外配置:
右键点击Info.plist → 选择Open As → Source Code,插入以下代码:
<key>NSAppTransportSecurity</key> <dict> <!-- 更安全的做法:只允许目标域名的HTTP请求 --> <key>NSExceptionDomains</key> <dict> <key>ggjh.co.kr</key> <dict> <key>NSIncludesSubdomains</key> <true/> <key>NSExceptionAllowsInsecureHTTPLoads</key> <true/> </dict> </dict> <!-- 全局允许HTTP(不推荐,仅用于测试) --> <!-- <key>NSAllowsArbitraryLoads</key> <true/> --> </dict>
优先推荐特定域名例外的配置,比全局允许更安全。
2. 非UTF-8编码导致解析乱码/失败
韩语网站常用EUC-KR编码,而Swift的String(contentsOf:)默认用UTF-8解析,编码不匹配会直接导致内容乱码或者解析失败。
解决方法:手动指定编码解析
fileprivate func parseMenuHtml(){ guard let url = URL(string: "http://www.ggjh.co.kr/now/menu.php") else { print("URL格式错误") return } do { let data = try Data(contentsOf: url) // 优先尝试韩语常用的EUC-KR编码 if let contents = String(data: data, encoding: .eucKR) { print(contents) // 用Kanna解析HTML if let doc = try? HTML(html: contents, encoding: .eucKR) { // 替换成目标页面实际的CSS选择器,比如查找菜单元素 let menuItems = doc.css(".menu-item") for item in menuItems { print(item.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? "") } } } else { // fallback到UTF-8编码 if let contents = String(data: data, encoding: .utf8) { print(contents) } else { print("无法识别页面编码") } } } catch { // 打印具体错误,不要只输出"error"! print("请求/解析错误: \(error.localizedDescription)") } }
3. 服务器需要自定义请求头
部分服务器会检查请求的User-Agent等头信息,String(contentsOf:)的默认请求头过于简单,可能被服务器拒绝返回内容。
解决方法:用URLSession自定义请求头
fileprivate func parseMenuHtml(){ guard let url = URL(string: "http://www.ggjh.co.kr/now/menu.php") else { print("URL格式错误") return } var request = URLRequest(url: url) // 模拟浏览器的User-Agent request.setValue("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36", forHTTPHeaderField: "User-Agent") // 添加Accept头,告诉服务器接收HTML格式 request.setValue("text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", forHTTPHeaderField: "Accept") let task = URLSession.shared.dataTask(with: request) { data, response, error in if let error = error { print("请求错误: \(error.localizedDescription)") return } guard let data = data else { print("服务器未返回数据") return } // 编码处理逻辑同上面的示例 if let contents = String(data: data, encoding: .eucKR) { print(contents) // 如果要更新UI,记得切回主线程 DispatchQueue.main.async { if let doc = try? HTML(html: contents, encoding: .eucKR) { // 执行你的解析逻辑 } } } } task.resume() }
关键提示:不要忽略错误信息
你之前的代码只打印"error",这完全无法定位问题!一定要打印error.localizedDescription或者直接打印error本身,这样才能知道是ATS拦截、网络超时还是编码错误。
内容的提问来源于stack exchange,提问作者Tolerance
相关产品推荐
相关产品推荐

