티스토리 뷰
2023.05.19 - [여러가지/기타] - 농담으로 한 말이 이렇게 되었습니다.
이렇게 일이 진행될 줄은 몰랐는데
이왕 이렇게 된거 간단히 해봅시다.
일단 저는 위 페이지에 있는 식당 리스트를 가져와서 랜덤으로 찍어주는 함수를 만들꺼에요.
(이렇게 만들면 서버 따로 안만들고 저것만 변경해서 식당리스트를 제 맘대로 관리할수있으니까요)
근데 그전에 잠깐 지금 무엇을 하는 건지
모르시는 분들을 위해 간단히 몇가지 이야기 하고 넘어갑시다.
웹 크롤링 (Web Crawling)
- 웹 페이지를 그대로 가져와서 거기서 데이터를 추출하는 방법을 말합니다.
- 여기서 웹페이지를 가져온다는 뜻은 해당 웹의 html 같은 구성 코드를 들고온다는 의미입니다.
해당 웹페이지의 구성 코드를 어떻게 알고 필요한 걸 가져오나요?
- 필요시 해당 웹페이지로 들어가서 코드를 직접 보고 판단해 가져오는 방법도 있습니다.
1. 원하시는 웹페이지에서 우클릭 후 아래 이미지를 참고하셔서 "검사"를 눌러주세요.
2. 그럼 아래와 같이 해당 페이지를 구성하는 코드가 오른쪽에 뜨게 됩니다.
자 이제 다시 Xcode 로 돌아와서 이야기 해볼까요?
아 그전에 참고말하면 저희는 아래 사진에 보이는 "RestrauntList"를 가져오는게 목표입니다.
저는 SwiftSoup 이라는 패키지를 사용할겁니다.
(애는 가져온 데이터를 사용하기 쉽게 도와주는 패키지입니다(통신 X))
https://github.com/scinfu/SwiftSoup
pod 'SwiftSoup'
패키지가 추가되어있다는 가정하에 진행하겠습니다.
(cocoapod 이나 swift package manager 를 통해 추가해주세요.)
import SwiftSoup // 여기에 오류가 안나면 설치된겁니다.
이제 여기서 부터는 금방입니다.
저희는 아까 그 웹사이트를 사용할꺼라고 했죠?
let testUrl = "https://world-of-larooly.tistory.com/129"
(위 주소는 연습하시는 분들을 위해 계속 열어두겠습니다.)
아 그런데 일단 통신을 해야 웹페이지랑 연결이 가능하겠죠?
그래서 잠시 URLSession 을 이용해 웹페이지 정보를 가져오겠습니다.
(URLSession : 기본으로 제공해주는 통신 도우미라고 생각하시면 됩니다.)
* 원래는 다른방식도 가능했는데 Xcode14 기준 보라색 경고문이 떠서 아래 방법으로 변경했습니다.*
if let url = URL(string: testUrl) {
URLSession.shared.dataTask(with: url) { (data, response, error) in
// 여기서 처리해주시면됩니다.
}.resume()
}
* 왜 URLSession 을 사용해서 표현하나요?
- 그냥 하게 되면 웹페이지에서 정보를 가져온 후에 화면을 그려 사용자 입장에서는 느리거나 멈춘것처럼 보일수있습니다.
- 아래 방식을 사용하면 다운로드를 다 받지 않아도 다른 코드를 실행해 이와 같은 일을 줄일 수 있습니다.
- 이런걸 보통 비동기 처리 방식 이라고 합니다.
이제 받아온 데이터를 html 로 바꿔서 본격적으로 크롤링 해봅시다!
저는 해당 부분이 길어져서 전체 html 을 받아와 String 으로 만들고
전체 html(String) 에서 제가 원하는 부분을 뽑아내는 함수를 따로 만들었습니다. (getStringListFromHtml)
URLSession.shared.dataTask(with: url) { (data, response, error) in
guard let htmlData = data else { return }
let webString = String(data: htmlData, encoding: .utf8)
print(webString) // 해당 웹 페이지의 html 이 출력됩니다.
let foodList = self.getStringListFromHtml(htmlString: webString!, kind: "RestrauntList") + self.getStringListFromHtml(htmlString: webString!, kind: "BreadList")
DispatchQueue.main.async {
// UI에 관련된 처리를 하려면 반드시 main스레드에서 작성해주세요!
self.textLbl.text = foodList.randomElement()
}
}.resume()
일단 코드 먼저 보여드릴께요.
func getStringListFromHtml(htmlString : String, kind : String) -> [String] {
var resultArray : [String] = []
do{
let doc = try SwiftSoup.parse(htmlString)
if let getList = try doc.getElementById(kind)?.select("p").array(){
for item in getList{
let text = try item.select("p").text()
resultArray.append(text)
}
}
return resultArray
}catch{
return []
}
}
생각보다 간단합니다
저는 해당 부분을 [String]으로 가져오기 위해 저렇게 표현을 했습니다.
일단 해당 조건을 만족하는 부분을 배열의 형태로 가져오고
let doc = try SwiftSoup.parse(htmlString) // 전체 html 코드
if let getList = try doc.getElementById(kind)? //특정 id부분을 잘라서 가져오고
.select("p") // 해당 부분 안의 <p></p>를 가져와
.array() // 배열의 형식으로 표현해달라
아래처럼 해당 배열을 [String] 형태로 가져오는 겁니다.
for item in getList{
let text = try item.select("p").text() // 해당 <p></p>안에 글씨를 가져오는 부분
resultArray.append(text) // 배열안에 해당 String 을 넣어줍니다.
}
html 에서 자신이 데이터를 가져오길 원하는 부분의 id만 파악하면 위처럼 뽑아내는게 가능합니다.
간단하죠?
아래는 전체 코드입니다.
import UIKit
import SwiftSoup
class ViewController: UIViewController {
@IBOutlet weak var textLbl: UILabel!
let testUrl = "https://world-of-larooly.tistory.com/129"
override func viewDidLoad() {
super.viewDidLoad()
setListFromStringrURL(stringUrl: testUrl)
}
func getStringListFromHtml(htmlString : String, kind : String) -> [String] {
var resultArray : [String] = []
do{
let doc = try SwiftSoup.parse(htmlString)
if let getList = try doc.getElementById(kind)?.select("p").array(){
for item in getList{
let text = try item.select("p").text()
resultArray.append(text)
}
}
return resultArray
}catch{
return []
}
}
func setListFromStringrURL(stringUrl: String) {
if let url = URL(string: stringUrl) {
URLSession.shared.dataTask(with: url) { (data, response, error) in
guard let imageData = data else { return }
let webImage = UIImage(data: imageData)
let webString = String(data: imageData, encoding: .utf8)
let foodList = self.getStringListFromHtml(htmlString: webString!, kind: "RestrauntList") + self.getStringListFromHtml(htmlString: webString!, kind: "BreadList")
DispatchQueue.main.async {
self.textLbl.text = foodList.randomElement()
}
}.resume()
}
}
* 번외
- 참고로 여기서 Data 타입으로 넘어오기 때문에 원하시는 타입으로 바꿔 쓰시면
이미지나 파일도 가져오는게 가능합니다.
URLSession.shared.dataTask(with: url) { (data, response, error) in
guard let imageData = data else { return }
let webImage = UIImage(data: imageData)
}.resume()
뭔가 간단하게 적는다고 쓰다보니
내용이 길어졌네요.
그래도 누군가에게 도움이 되었으면 좋겠네요.
오늘도 파이팅입니다.
'iOS개발 > Swift 기능' 카테고리의 다른 글
Swift 패턴 잠금 만들기 (with. CCGestureLock ) (0) | 2024.04.22 |
---|---|
KeyChain 단순 데이터 저장 방법 (Swift / Obj-C) (0) | 2024.01.26 |
Swift Charts 한 표 안에 다수의 그래프 그리기 (0) | 2023.03.21 |
Swift Side Menu UI 만들기 (with SideMenu) (0) | 2023.02.07 |
Swift Data로 바꾸기 (String,UIImage, Url) (with. Alamofire) (0) | 2023.01.12 |