Posts R 크롤링 클리앙(Clien) GET / POST + Selenium (셀레니움)
Post
Cancel

R 크롤링 클리앙(Clien) GET / POST + Selenium (셀레니움)


galaxy01
클리앙에서 “갤럭시 폴드” 통합검색 결과를 크롤링 해보겠습니다
크롤링에 필요한 패키지(package)와 라이브러리(library)는 아래와 같습니다

1
2
3
4
5
6
7
8
install.packages(c("dplyr", "httr", "jsonlite", "rJava", "RSelenium", "stringr")

· library(dplyr)
· library(httr)
· library(jsonlite)
· library(rJava)
· library(RSelenium)
· library(stringr)



클리앙에 접속하여 통합검색 창에 “갤럭시 폴드”를 검색합니다
https://www.clien.net/service/search?q=갤럭시%20폴드 clien01

https://www.clien.net/service/search?q=갤럭시%20폴드
URL을 분리해봅시다


URL : https://www.clien.net/service/search
Query String(추가적 정보) :
1) q=갤럭시%20폴드


어떤 구조인지는 알겠는데 뭔가 부족한 느낌을 지울수 없습니다
그러면 2번째 페이지로 가봅시다
https://www.clien.net/service/search?q=갤럭시%20폴드&sort=recency&p=1&boardCd=&isBoard=false clien02
URL에 추가적인 꼬리가 더 붙었습니다 다시 분리해봅시다


URL : https://www.clien.net/service/search
Query String(추가적 정보) : “&”로 분리
1) q=갤럭시%20폴드 #### 검색어
2) sort=recency #### sort를 recency로 합니다(즉, 최신순 정렬이죠)
3) p=1 #### 첫번째 페이지란 뜻입니다 Query String에서 p는 페이지 정보일때가 많습니다
4) boardCd=
5) isBoard=false

다시 첫번째 페이지로 돌아가봅시다
https://www.clien.net/service/search?q=갤럭시%20폴드&sort=recency&p=0&boardCd=&isBoard=false URL이 뭔가 달라졌습니다 다시 분리 해봅시다

URL : https://www.clien.net/service/search
Query String(추가적 정보) : “&”로 분리
1) q=갤럭시%20폴드 #### 검색어
2) sort=recency #### 최신순 정렬
3) p=0 #### 0번째 페이지란 뜻입니다
4) boardCd=
5) isBoard=false

클리앙은 독특하게 1페이지 정보가 0입니다
그래도 크롤링에는 문제가 없습니다

F12를 눌러봅시다 clien03

가장 위 정보를 클릭합시다
찾지 못할경우 페이지 새로고침(F5)를 누르십시요
Header - General에서 필요한 정보는 Request URL과 Request Method입니다
아래로 내려가 Query String Parameter로 가서 정보를 확인합니다 clien04
이 정보를 바탕으로 HTTP 요청 및 응답 명령어(code)를 작성합니다

HTTP 요청 및 응답

1
2
3
4
5
6
7
8
9
10
searchword <- "갤럭시 폴드"

 

  res_cl <- GET(url = "https://www.clien.net/service/search", 
                query = list(q = searchword, 
                             sort = "recency", 
                             p = 0, 
                             boardCd = "",              ## boardCd: 에는 정보가 없는데, ""로 처리하면 됩니다
                             isBoard = "false")



크롤링의 큰 그림을 설명하겠습니다
1) 해당 게시글을 링크를 수집한다 (중요)
2) 수집한 링크에서 데이터(요소 : Element)를 찾아서 수집한다


좀 더 풀어서 설명하면
1) 1페이지의 링크를 수집
2) 수집한 링크를 타고가서 해당요소를 수집
3) for문(자동화)으로 검색한 결과 전체 크롤링


그러면 1)에 따라 링크를 수집합니다
링크를 수집하기 위해 element를 확인합니다
F12에서 보이는 제일 왼쪽 위 아이콘(Ctrl + Shift + C)을 클릭하고 게시글 제목을 클릭합니다 clien05
위 정보를 바탕으로 링크를 수집해봅시다

링크

1
2
3
4
5
6
7
8
9
10
11
12
13
14
링크_cl <- c()                                                     ## 수집한 링크를 담을 빈 벡터 공간을 만듭니다

   
  링크.tmp <- res_cl %>%  
    read_html() %>%  
    html_nodes("a.subject_fixed") %>%        ##링크 주소 바로 위에 있는 Element입니다 
    html_attr("href") %>%                              ## href="링크주소"를 긁는 명령어입니다
    unique()                                                       ##중복되는 링크를 제거해주는 함수입니다
  

  링크.tmp <- paste0("https://www.clien.net",링크.tmp)    ### 수집한 링크 앞에 "https://www.clien.net"를 넣어줍니다

   
  링크_cl <- append(링크.tmp,링크_cl)  



링크 수집을 완료하였습니다
이번에는 링크를 타고 들어가기 전에 날짜도 수집합시다
F12에서 보이는 제일 왼쪽 위 아이콘(Ctrl + Shift + C)을 클릭하고 게시글 날짜를 클릭합니다 clien06

element정보를 보니
span.time popover에는 13:29
span.timestamp에는 2020-02-11 13:29:49가 있습니다
날짜까지 포함한 element인 후자를 선택합시다

##날짜

1
2
3
4
5
6
7
8
9
10
11
12
13
날짜_cl <- c()                                                   ## 수집한 날짜를 담을 빈 벡터 공간을 만듭니다

   
  날짜.tmp <- res_cl %>%  
    read_html() %>%  
    html_nodes("span.timestamp") %>% 
    html_text()  
   
  if (length(날짜.tmp) == 0) { 
    날짜_cl <- append(날짜_cl, "수동확인") 
  } else { 
    날짜_cl <- append(날짜_cl, 날짜.tmp) 
  }



그럼 이제 수집한 링크를 타고가서
“제목”, “본문”, “조회수”, “댓글수” 그리고 이번엔 “댓글”까지도 크롤링합시다
크롤링한 페이지의 링크는 따로 저장하기 위해 “주소”로 저장합니다


크롤링 하기로한 element 이름으로 빈 벡터공간을 만듭니다

1
2
3
4
5
6
7
8
9
10
11
제목_cl <- c()

본문_cl <- c()

조회수_cl <- c()

댓글수_cl <- c()

댓글_cl <- c() 

주소_cl <- c()



그리고 셀레니움을 켭니다
명령프롬프트를 키고

1
2
1) cd C:\r_selenium 
2) java -Dwebdriver.gecko.driver="geckodriver.exe" -jar selenium-server-standalone-4.0.0-alpha-1.jar -port 4445를 입력합니다




RSelenium

1
2
3
4
remDr <- remoteDriver(remoteServerAddr="localhost", 
                      port=4445L, 
                      browserName="chrome")
remDr$open()

링크와 게시글 제목을 수집한것 처럼
F12에서 보이는 제일 왼쪽 위 아이콘(Ctrl + Shift + C)을 클릭하고 수집하려는 element를 클릭합니다


스크린샷은 생략하겠습니다
아래는 element를 수집하는 명령어입니다
사전에 수집한 링크의 첫번째 페이지를 수집합니다

1
링크_cl[1] = https://www.clien.net/service/board/kin/14581236?combine=true&q=%EA%B0%A4%EB%9F%AD%EC%8B%9C+%ED%8F%B4%EB%93%9C&p=0&sort=recency&boardCd=&


1
2
3
remDr$navigate(링크_cl[1])                          ## 링크_cl[1]에 할당된 URL를 탐색합니다
body <- remDr$getPageSource()[[1]]          ## URL page Source를 가져옵니다
body <- body %>% read_html()                  ## html를 읽어들입니다



##제목

1
2
3
4
5
6
7
8
9
    제목.tmp <- body %>%  
      html_nodes("h3.post_subject") %>%  
      html_text() 
       
    if (length(제목_cl) == 0) { 
      제목_cl <- append(제목_cl, "수동확인") 
    } else { 
      제목_cl <- append(제목_cl, 제목.tmp) 
    }



##본문

1
2
3
4
5
6
7
8
9
     본문.tmp <- body %>%  
      html_nodes("div.post_article") %>%  
      html_text() 
     
    if (length(본문_cl) == 0) { 
      본문_cl <- append(본문_cl, "수동확인") 
    } else { 
      본문_cl <- append(본문_cl, 본문.tmp) 
    }



##조회수

1
2
3
4
5
6
7
8
9
조회수.tmp <- body %>%  
      html_nodes("span.view_count") %>%  
      html_text() 
     
    if (length(조회수_cl) == 0) { 
      조회수_cl <- append(조회수_cl, "수동확인") 
    } else { 
      조회수_cl <- append(조회수_cl, 조회수.tmp) 
    }



##댓글수

1
2
3
4
5
6
7
8
9
댓글수.tmp <- body %>%  
      html_nodes('div.comment_head') %>% 
      html_text() 
     
    if (length(댓글수_cl) == 0) { 
      댓글수_cl <- append(댓글수_cl, "수동확인") 
    } else { 
      댓글수_cl <- append(댓글수_cl, 댓글수.tmp) 
    }



##댓글

1
2
3
4
5
6
7
8
9
댓글.tmp <- body %>%  
      html_nodes("div.comment_view") %>%  
      html_text() 
     
    if (length(댓글_cl) == 0) { 
      댓글_cl <- append(댓글_cl, "수동확인") 
    } else { 
      댓글_cl <- append(댓글_cl, 댓글.tmp) 
    } 



##주소

1
주소_cl <- append(주소_cl, 링크_cl[1])



수집한요소를 전처리 합시다

1
2
3
4
5
6
7
8
9
10
11
12
제목_cl <- gsub("\n", "", 제목_cl) 
제목_cl <- gsub("\t", "", 제목_cl) 

본문_cl <- gsub("\n", "", 본문_cl) 
본문_cl <- gsub("\t", "", 본문_cl) 

조회수_cl <- gsub("\\D", "", 조회수_cl)             ## "\\D"은 숫자가 아닌 문자를 선택하는 정규표현식입니다

댓글_cl <- gsub("\n", "", 댓글_cl) 
댓글_cl <- gsub("\t", "", 댓글_cl) 

댓글수_cl <- gsub("\\D", "", 댓글수_cl)



수집한 element를 df로 만들어 csv파일로 저장합니다

1
2
3
4
5
clien_갤럭시폴드_본문 <- data.frame(날짜_cl, 제목_cl, 본문_cl, 조회수_cl, 댓글수_cl, 주소_cl)   
clien_갤럭시폴드_댓글 <- data.frame(댓글_cl)  

write.csv(clien_갤럭시폴드_본문, file = "D:/clien_갤럭시폴드_본문.csv", row.names=FALSE) 
write.csv(clien_갤럭시폴드_댓글, file = "D:/clien_갤럭시폴드_댓글.csv", row.names=FALSE)



for문으로 자동화하기(중요!!)


첫 페이지 크롤링을 모두 완료하였습니다
for문과 tryCatch( )를 사용하여 모든 페이지를 크롤링합니다
아래의 R명령어로 검색결과 전체를 크롤링 및 전처리, csv로 저장 할 수 있습니다

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
#####링크 수집


n <- 50 
searchword <- "갤럭시 폴드" 

링크_cl <- c() 
날짜_cl <- c() 

for(i in 0:n){ 
  tryCatch({ 
  res_cl <- GET(url = "https://www.clien.net/service/search", 
                query = list(q = searchword, 
                             sort = "recency", 
                             p = i, 
                             boardCd = "", 
                             isBoard = "false")) 
   
  cat('현재', i, '페이지 수집 중! 상태코드는', status_code(x = res_cl), '입니다.\n') 
   
  ##링크 
   
  링크.tmp <- res_cl %>%  
    read_html() %>%  
    html_nodes("a.subject_fixed") %>% 
    html_attr("href") %>% 
    unique() 
   
  링크.tmp <- paste0("https://www.clien.net",링크.tmp) 
   
  링크_cl <- append(링크.tmp,링크_cl)  
   
   
   
  ##날짜 
   
  날짜.tmp <- res_cl %>%  
    read_html() %>%  
    html_nodes("span.timestamp") %>% 
    html_text()  
   
  if (length(날짜.tmp) == 0) { 
    날짜_cl <- append(날짜_cl, "수동확인") 
  } else { 
    날짜_cl <- append(날짜_cl, 날짜.tmp) 
  } 
   
   
  Sys.sleep(time = 1)  ## (중요!) 반복되는 작업으로 디도스(DDOS)로 오인 받지 않을려면 반드시 넣습니다!!
   
  }, error = function(e) cat("불러올 수 없습니다!\n")) 
   
} 




## 명령프롬프트 실행


#cd C:\r_selenium 
# java -Dwebdriver.gecko.driver="geckodriver.exe" -jar selenium-server-standalone-4.0.0-alpha-1.jar -port 4445 

 


## RSelenium 

remDr <- remoteDriver(remoteServerAddr="localhost",  
                      port=4445L,  
                      browserName="chrome") 
remDr$open() 



## 제목 본문 댓글 조회수 댓글수 주소 

제목_cl <- c() 
본문_cl <- c() 
댓글_cl <- c() 
조회수_cl <- c() 
댓글수_cl <- c() 
주소_cl <- c() 


  for (i in 403:length(링크_cl)){ 
  tryCatch({ 
    remDr$navigate(링크_cl[i]) 
    body <- remDr$getPageSource()[[1]] 
     
    cat('현재', i, '페이지 수집 중! \n')  
     
    body <- body %>% read_html() 
     
     
    ##제목 
     
    제목.tmp <- body %>%  
      html_nodes("h3.post_subject") %>%  
      html_text() 
       
    if (length(제목_cl) == 0) { 
      제목_cl <- append(제목_cl, "수동확인") 
    } else { 
      제목_cl <- append(제목_cl, 제목.tmp) 
    } 
     
     
    ##본문 
     
    본문.tmp <- body %>%  
      html_nodes("div.post_article") %>%  
      html_text() 
     
    if (length(본문_cl) == 0) { 
      본문_cl <- append(본문_cl, "수동확인") 
    } else { 
      본문_cl <- append(본문_cl, 본문.tmp) 
    } 
     
     
     
    ##댓글 
     
    댓글.tmp <- body %>%  
      html_nodes("div.comment_view") %>%  
      html_text() 
     
    if (length(댓글_cl) == 0) { 
      댓글_cl <- append(댓글_cl, "수동확인") 
    } else { 
      댓글_cl <- append(댓글_cl, 댓글.tmp) 
    } 
     
     
    ##조회수 
     
    조회수.tmp <- body %>%  
      html_nodes("span.view_count") %>%  
      html_text() 
     
    if (length(조회수_cl) == 0) { 
      조회수_cl <- append(조회수_cl, "수동확인") 
    } else { 
      조회수_cl <- append(조회수_cl, 조회수.tmp) 
    } 
     
     
    ##댓글수 
     
    댓글수.tmp <- body %>%  
      html_nodes('div.comment_head') %>% 
      html_text() 
     
    if (length(댓글수_cl) == 0) { 
      댓글수_cl <- append(댓글수_cl, "수동확인") 
    } else { 
      댓글수_cl <- append(댓글수_cl, 댓글수.tmp) 
    } 
     
     
     
    ##주소 
     
    주소_cl <- append(주소_cl, 링크_cl[i]) 
     
     
     
    Sys.sleep(time = 1)     ## (중요!) 반복되는 작업으로 디도스(DDOS)로 오인 받지 않을려면 반드시 넣습니다!!
     
  }, error = function(e) cat("불러올 수 없습니다!\n")) 
} 
  
  
  
## 데이터 전처리
 
제목_cl <- gsub("\n", "", 제목_cl) 
제목_cl <- gsub("\t", "", 제목_cl) 

본문_cl <- gsub("\n", "", 본문_cl) 
본문_cl <- gsub("\t", "", 본문_cl) 

조회수_cl <- gsub("\\D", "", 조회수_cl) 

댓글_cl <- gsub("\n", "", 댓글_cl) 
댓글_cl <- gsub("\t", "", 댓글_cl) 

댓글수_cl <- gsub("\\D", "", 댓글수_cl) 



## data.frame 저장

clien_갤럭시폴드_본문 <- data.frame(날짜_cl, 제목_cl, 본문_cl, 조회수_cl, 댓글수_cl, 주소_cl)   
clien_갤럭시폴드_댓글 <- data.frame(댓글_cl)  

write.csv(clien_갤럭시폴드_본문, file = "D:/clien_갤럭시폴드_본문.csv", row.names=FALSE) 
write.csv(clien_갤럭시폴드_댓글, file = "D:/clien_갤럭시폴드_댓글.csv", row.names=FALSE) 

최종결과로 csv저장된 파일입니다 clien07 클리앙 : 날짜 제목 본문 조회수 댓글수 주소 clien08 클리앙 : 댓글

다음 포스팅은 GET/POST방법으로만 클리앙(Clien)을 크롤링 하겠습니다

This post is licensed under CC BY 4.0 by the author.