본문 바로가기

소프트웨어/R programming

이디야 매장 크롤링 - R programming

참고 URL : http://www.datamarket.kr/xe/board_BoGi29/13827

아래 내용은 위 사이트에 있는 내용을 가져온 것입니다. 참고하세요~~

----


어떤 경로로 이 게시물을 접하시든 간에, 쉽게 이해하고 따라하실 수 있게 노력했습니다!

그럼 크롤링 설명 시작할게요!!

먼저 R을 이용한 크롤링에는 XML패키지와 stringr 패키지가 필요합니다.
>> library(XML)
>> library(stringr)

제가 공부하면서 겪은 R크롤링에서의 유형 두 가지는,
1. url 주소창에 page주소가 그대로 나오는 유형 (비교적 쉬움) 
2. url 주소창에 page주소가 그대로 나오지 않고 진짜 주소가 숨겨진 유형 (꽁꽁 숨기면 짜증남)
(cf. 페이지주소가 나온다는 뜻은 페이지를 넘길 때 마다 url주소에 page=1, page=2...처럼 표시된다는 뜻)

제가 할건 1번 유형: url 주소창에 page주소가 그대로 나오는 유형입니다.

그럼 이해를 돕기 위해서 네이버영화 페이지에 종합 리뷰 페이지로 예를 들어보겠습니다.

bb04edb4f0af871e42eb8dc6a2fc7ee0.JPG
페이지 구성은 이런식으로 되어있고, 밑에 [1], [2], [3], [4], [5] 버튼박스들을 누르게 되면 페이지가 바뀌죠??
이 때, url 주소를 확인해보시면


2d53175bfa7258f185a88b3118082fdd.JPG
url 주소 뒤에 page=1, page=2, ... 이런 식으로 같이 바뀌는 걸 알 수 있습니다. 
이런 경우는 상대적으로 크롤링 하기 편한 경우입니다. 굳이 숨겨진 주소를 찾을 필요 없는 착한 사이트입니다 굿굿!!

그럼 먼저 리뷰 1페이지의 <리뷰한 영화제목>과 <리뷰내용>을 크롤링 해볼게요.

먼저 url이라는 변수에 url 주소 정보를 입력해줍시다. 
리뷰 1페이지만 크롤링 해볼거기 때문에 page=1로 고정합니다.

다음은 readLines라는 함수를 통해서 해당 url주소의 html소스를 데이터로 받아옵니다.
(크롬 브라우저로 "페이지소스보기" 클릭하면 직접 하나하나 볼 수 있어요)
그리고 해당 url주소의 인코딩값도 넣어줘야 합니다. 네이버 리뷰의 경우에는 "euc-kr"이라는 인코딩을 사용 중입니다.
(인코딩에 관한 정보도 "페이지소스보기"를 통해서 확인할 수 있어요)
     readLines(크롤링할주소, 크롤링할주소의 인코딩)
>> line <- readLines(url, encoding = "euc-kr")

자 그럼 readLines 함수를 통해서 얻은 데이터에서 <리뷰한 영화 제목>을 추출해볼게요.
먼저 str_detect 함수를 통해서 특정 패턴의 string이 들어간 소스 줄만 가져옵니다.
소스를 봤더니 <리뷰한 영화 제목> 앞에는 class="movie">라는 html 소스가 반복해서 나타납니다.
>> title <- line[str_detect(line, "class=\"movie\">")]

여기서 중요한 점은, html소스에서 쓰인 따옴표("")가 R에서 쓰는 ""구분과 겹쳐서 인식을 이상하게 해버린다는 점인데요
그럴 땐, 역슬래쉬(\)를 문자로 인식하게 하고 싶은 html따옴표 앞에 붙여줌으로써 
"class=\"movie\">"
R이 문자로 제대로 인식하게 해주면 됩니다.

그럼 한번 "class=\"movie\">"가 포함된 줄을 어떻게 가져왔는지 보면,
>> title

온갖 특수문자들이 같이 포함되어서 원하는 정보를 보기 어렵습니다.
그래서 gsub함수를 통해서 불필요한 항목을 제거합니다.
     gsub(바꾸고싶은것, 이렇게바꿔줘, 데이터)
>> title <- gsub("<.+?>|\t", "", title)

이제 다시 title을 보니 잘 분류된 것 같아요.

그럼 <리뷰 내용>도 크롤링해보겠습니다.
똑같은 방식으로 소스가 포함된 라인을 가져와주는데, <리뷰 내용>은 class="movie">가 포함된 소스 줄로부터
4줄 더한 라인에 속해있네요!! 
그럼 인덱싱에 있어서 +4만 추가해줍니다.
>> content <- line[which(str_detect(line, "class=\"movie\">"))+4]

똑같이 특수문자 등등을 gsub함수를 통해서 제거해주고,
>> content <- gsub("<.+?>|\t", "", content)

남는 공백을 제거하기 위해서 str_trim 함수를 사용해서 제거합니다.
     str_trim(공백을 제거할 데이터)
>> content <- str_trim(content)

잘 정리됐습니다.
>> content

보기 좋게 cbind로 묶어서 한 페이지로 볼게요.
>> page <- cbind(title, content)

굳굳! 네이버영화 1페이지 크롤링 완료
>>page



그럼 본격적인 이디야 매장 크롤링을 시작해볼게요.

이디야커피 공식 홈페이지 - 매장안내에 들어갔더니 페이지변화가 눈에 보이는 유형입니다.

이번에는 for문을 이용해서 1페이지 뿐만 아니라 11페이지 끝까지 크롤링을 해보겠습니다.

먼저 크롤링 결과물을 정리할 빈 벡터 final을 정의해주시고,
>> final <- NULL

for문을 통해서 R이 자동적으로 url을 바꿔가면서 크롤링할 수 있게 합니다.
>> for(i in 1:11)  
>> {
paste0함수를 통해서 (url주소) + (i가 1부터 11까지) 들어가면서 자동으로 url을 바꿔가며 크롤링합니다.
 
>> line <- readLines(url, encoding = "UTF-8")

이번에는 <a class="btn navybtn" 태그가 들어간 소스 줄에서 7줄 모자란 라인에 위치 정보가 있습니다.
>> location <- line[which(str_detect(line, " <a class=\"btn navybtn\""))-7]

마찬가지로 gsub을 통해 잡문자를 제거해줍니다.
>> location <- gsub("<.+?>|\t", "", location)

str_trim을 통해 공백도 제거해주고요.
>> location <- str_trim(location)
>> location

똑같은 방식으로 매장명을 크롤링합니다.
이번엔 <a class="btn navybtn" 태그가 들어간 소스 줄에서 6줄 모자란 라인에 매장명 정보가 있습니다.
>> name <- line[which(str_detect(line, " <a class=\"btn navybtn\""))-6]
>> name <- gsub("<.+?>|\t", "", name)
>> name <- str_trim(name)
>> name

마찬가지로 주소 정보를 크롤링합니다.
주소 정보는 <a class="btn navybtn" 태그가 들어간 소스 줄에서 5줄 모자란 라인에 있습니다.
>> address <- line[which(str_detect(line, " <a class=\"btn navybtn\""))-5]
>> address <- gsub("<.+?>|\t", "", address)
>> address <- str_trim(address)
>> address

문제는 이제 매장 테마 정보인데요!
이놈이 이미지로 되어 있어서 뽑아오기 난감해요..
그래도 다행히 img src 태그안에 테마정보 텍스트가 남아 있어서 가져오면 될 것 같습니다!
(이해가 안가시는 분은 페이지소스보기를 통해 확인해주세요)

# img src안에 있는 한글텍스트 뽑아오기
테마 정보는 <a class="btn navybtn" 태그가 들어간 소스 줄에서 3줄 모자란 라인에 있네요.
>>theme <- line[which(str_detect(line, " <a class=\"btn navybtn\""))-3]

temp라는 벡터에 str_extract_all 함수를 통해서 
img src 태그안에 있는 테마정보 텍스트를 가져오겠습니다. 
※ str_extract_all(데이터, 추출할값)
여기서는 테마정보가 한글이므로 한글만 가져오기 위해서 정규표현식 [가-힣]+ 를 사용했습니다.
그리고 str_extract_all의 반환값은 list 형태입니다.
>> temp <- str_extract_all(theme, "[가-힣]+")

근데 문제가 생기는 부분이 있어요..
"상품권 판매"라는 테마 정보가 있는데, 공백 때문에 str_extract_all 함수가
"상품권" "판매" 로 인식해버립니다.
다행히 이디야매장의 4개 테마 "테라스", "미팅룸", "상품권 판매", "와이파이존" 중에
공백을 가진건 "상품권 판매" 하나뿐이라서 이 부분만 고쳐주면 될 것 같습니다.
문제를 해결하기 위해서 공백을 허물어줄 함수를 정의해주겠습니다.
>> temp.function <- function(x)
>> { 
>>   kk <- paste(x, collapse=" ")
>>   return(kk)
>> }

이렇게 정의한 함수를 list형태인 theme에 일괄적용하기 위해서 lapply 함수를 사용합니다.
>> theme <- lapply(temp, temp.function)

그럼 테마 정보도 공백이 무너져서 "상품권판매"로 인식하게 됐습니다!!
이제 취합한 정보들을 보기좋게 정리해보겠습니다.

page 벡터에 정보들을 모아주고
>> page <- cbind(location, name, address, theme) 

for문 전에 선언했던 빈 벡터인 final에 1부터 11페이지의 정리본들을 rbind로 묶겠습니다.
>> final <- rbind(final, page)
>> }      #for문 끝

>> final

크롤링 포스팅 마치겠습니다.



####################최종코드#######################
# 이디야 매장 크롤링
final <- NULL
for(i in 1:11)
{
line <- readLines(url, encoding = "UTF-8")
location <- line[which(str_detect(line, " <a class=\"btn navybtn\""))-7]
location <- gsub("<.+?>|\t", "", location)
location <- str_trim(location)
location

name <- line[which(str_detect(line, " <a class=\"btn navybtn\""))-6]
name <- gsub("<.+?>|\t", "", name)
name <- str_trim(name)
name

address <- line[which(str_detect(line, " <a class=\"btn navybtn\""))-5]
address <- gsub("<.+?>|\t", "", address)
address <- str_trim(address)
address

# img src안에 있는 한글텍스트 뽑아오기
theme <- line[which(str_detect(line, " <a class=\"btn navybtn\""))-3]
theme <- gsub(" ", "", theme) 
temp <- str_extract_all(theme, "[가-힣]+")

temp.function <- function(x)
  kk <- paste(x, collapse=" ")
  return(kk)
}

theme <- lapply(temp, temp.function)

page <- cbind(location, name, address, theme)
final <- rbind(final, page)
}
final