Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
Tags
- Clean Code
- MVVM
- 클린 코드
- 애니메이션
- uiscrollview
- Observable
- collectionview
- combine
- Xcode
- ribs
- Refactoring
- map
- UICollectionView
- rxswift
- tableView
- 리팩토링
- Protocol
- HIG
- ios
- clean architecture
- RxCocoa
- uitableview
- swiftUI
- Human interface guide
- SWIFT
- UITextView
- 스위프트
- 리펙토링
- swift documentation
- 리펙터링
Archives
- Today
- Total
김종권의 iOS 앱 개발 알아가기
[iOS - swift] Web crawling(웹 크롤링), web scraping, (swiftsoup, Alamofire, 한글 깨짐) 본문
iOS 응용 (swift)
[iOS - swift] Web crawling(웹 크롤링), web scraping, (swiftsoup, Alamofire, 한글 깨짐)
jake-kim 2021. 3. 17. 01:42파싱을 위한 HTML 기초
- HTML 구성
<!docutype html>
<head>
...
</head>
<body>
...
</body>
- body 태그안에 자주 사용되는 태그
<br>
<div>
<p>
<span>
<form>
<h1>
<a>
<img>
<table>
<ul>
<li>
<nav>
- css: 디자인
<style> h1 {color: red;} </style>
- javascript: 동적인 부분을 변경시켜 주는 것
<script> alert("테스트") </script>
css의 id와 class 개념
- id와 class의 차이점은 우선순위: id > class > 태그
- class
<!DOCTYPE html>
<html>
<head>
<style>
.class1 {color: red; background-color: yellow;}
h3.class1 {color: navy; background-color: blue;}
</style>
</head>
<body>
<h1 class="class1">클래스1 예제</h1>
<h3 class="class1">h3인 클래스1 예제</h3>
</body>
</html>
- id
<!DOCTYPE html>
<html>
<head>
<style>
#id1 {color: blue; background-color; yellow;}
</style>
</head>
<body>
<h1 id="id1">ID1 선택자</h1>
</body>
</html>
가장 중요한 개념
- id /class / tag / attribute 구분
- attribute는 tag안의 값
- <a href="ios-development.tistory.com">인 경우, href의 정체는 attribute
- SwiftSoup의 Element속성 중 id, class, tag 는 모두 element.select()로 접근하는 반면, attribute는 element.attr()로 접근하는 것을 주의
SwiftSoup 프레임워크 준비
pod 'SwiftSoup'
웹 크롤링 방법
- 크롤링할 사이트를 크롬으로 열은 후 크롤링할 문구 오른쪽 클릭 -> 검사 선택
- 검색을 눌렀을 때 오른쪽에 html 코드 정보 확인
- 결과: #mArticle > div:nth-child(7) > a.link_post > strong
웹 클롤링
- Alamofire를 통해 해당 사이트에 있는 html을 획득
struct CrawlManager {
static func crawlJakeBlog() {
let urlStr = "https://ios-development.tistory.com/"
// let classPath = "#mArticle > div:nth-child(6) > a.link_post > strong"
AF.request(urlStr).responseString { (response) in
guard let html = response.value else {
return
}
}
}
}
- html을 파싱하여 데이터 획득
- 위에서 얻은 class path사용: "#mArticle > div:nth-child(7) > a.link_post > strong"
struct CrawlManager {
static func crawlJakeBlog() {
let urlStr = "https://ios-development.tistory.com/"
// let classPath = "#mArticle > div:nth-child(6) > a.link_post > strong"
AF.request(urlStr).responseString { (response) in
guard let html = response.value else {
return
}
do {
let doc: Document = try SwiftSoup.parse(html)
// #newsContents > div > div.postRankSubjectList.f_clear
let elements: Elements = try doc.select("#mArticle > div")
for element in elements {
print(try element.select("a.link_post > strong").text())
}
} catch {
print("crawl error")
}
}
}
}
- 결과
response.value값에 한글이 깨지는 경우
- CFStringConvertEncodingToNSStringEncoding 사용
let encodedHtml = NSString(data: response.data!, encoding: CFStringConvertEncodingToNSStringEncoding( 0x0422 ) )
if let encodedHtml = encodedHtml {
html = encodedHtml as String
}
- 전체 코드
struct CrawlManager {
static func crawlJakeBlog() {
let urlStr = "https://ios-development.tistory.com/"
// let classPath = "#mArticle > div:nth-child(6) > a.link_post > strong"
AF.request(urlStr).responseString { (response) in
guard var html = response.value else {
return
}
if let data = response.data {
let encodedHtml = NSString(data: data, encoding: CFStringConvertEncodingToNSStringEncoding( 0x0422 ) )
if let encodedHtml = encodedHtml {
html = encodedHtml as String
}
}
do {
let doc: Document = try SwiftSoup.parse(html)
// #newsContents > div > div.postRankSubjectList.f_clear
let elements: Elements = try doc.select("#mArticle > div")
for element in elements {
print(try element.select("a.link_post > strong").text())
}
} catch {
print("crawl error")
}
}
}
}
* 만약 href에 접근하고 싶은 경우, element.select(a).attr("href") // 문자열로 반환
ex) <a href="ios-development.tistory.com/">
* 접근이 안되는 경우, html파일을 보고, tag로 하나하나 접근 - 아래에서 "프리미어리그" 파싱방법
- 접근: doc.select("channel > item > title")
let url = "https://trends.google.com/trends/trendingsearches/daily/rss?geo=KR"
AF.request(url).responseString { (response) in
guard let html = response.value else {
return
}
do {
let doc: Document = try SwiftSoup.parse(html)
let elements: Elements = try doc.select("channel > item")
for element in elements {
let title = try element.select("title")
print(try title.text())
}
} catch {
print(error)
}
}
결과
Selector가 아닌 tagName으로 파싱 방법
- selector로 파싱이 안될 경우, tagName을 알아내어 파싱 시도
for element in elements {
print(element.tagName())
print("1---------------------------")
for elementChildren in element.children() {
print(elementChildren.tagName())
print("2---------------------------")
for htNewsItemChildren in try elementChildren.tagName("ht:news_item").children() {
print(htNewsItemChildren.tagName())
}
}
}
- for문으로 접근
for element in elements {
var isFindTargetContents = false
for elementChildren in element.children() {
let targetElement = try elementChildren.tagName("ht:news_item").children().first()
let description = try targetElement?.tagName("ht:news_item_snippet").text()
if let description = description {
if isFindTargetContents {
break
} else {
isFindTargetContents = true
print(description)
}
}
}
}
- ' '와 같은 HTML특수문자 코드를 일반적인 문자열로 변경하는 방법 참고: https://ios-development.tistory.com/485
'iOS 응용 (swift)' 카테고리의 다른 글
[iOS - swift] 로컬 푸시 (local notification) (5) | 2021.03.21 |
---|---|
[iOS - swift] os_log, Logger, 통합 로깅 시스템 (unified logging system) (0) | 2021.03.21 |
[iOS - swift] app store로 이동 (버전 업데이트, 다시 돌아온 경우 처리, 현재 버전, 최신 버전 가져오는 방법) (6) | 2021.03.15 |
[iOS - swift] tableView refresh (상단, 하단 새로고침) (0) | 2021.03.13 |
[iOS - swift] keychain에 암호화/복호화하여 저장 방법 (SecureEnclave) (0) | 2021.03.12 |
Comments