네이버 별점, 방문자리뷰수, 블로그리뷰수, 블로그리뷰 텍스트 총 4가지를 가지고 맛집을 도출해보도록 하겠습니다.
별점, 방문자 리뷰 수 , 블로그 리뷰 수는 셀레니움으로 스크래핑 하고
부산시 소상공인 시장진흥공단_상가에서 상호명과 동이름만남기고 모조리 지우는 전처리를 했습니다.
스크래핑부터 차례대로 시작해봅시다.
한국에서 크롤링이라고 많이 표현을 하는데 스크래핑이 정확한 표현이라고 합니다.
부전 1동 부전 2동에 있는 음식점으로 분류된 가게가 1914개가 존재합니다.
결측값은 없습니다.
처음 네이버 지도 리뷰에서 스크래핑을 시도했습니다.
네이버나 다음이나 블로그던 카페던 본문은 iframe 태그로 이루어져 있는데
스크래핑 작업을 할 때 iframe 소스에서 path 를 따와서 url 에 붙여주는 작업이 필요합니다.
iframe 은 여러 html 파일을 한 화면에 렌더링을 가능케 하는 태그입니다.
하지만 분명 네이버 지도같은 경우에는 본문 페이지 소스와 프레임 소스가 나뉘어져 있는데도 iframe 태그가 보이지 않았습니다.
html 이나 path를 가져와주는 스크립트가 있을 것으로 예상됩니다.
이런 케이스에서 모바일 주소로 접속해서 스크래핑을 하면 문제가 해결되는 경우가 많습니다.
이번에도 모바일 주소로 스크래핑을 했습니다.
loop 안에 있는 첫 코드 뭉치는 검색창을 비우고 검색창을 찾아서 원하는 키워드를 보내고 엔터까지 누르는 과정입니다.
다음 try except가 3중으로 뭉쳐있는 코드를 봅시다.
3번의 시도를 하고 있습니다.
네이버에 검색어를 입력하면 이렇게 가게가 바로 나오는 경우가 있고
가게이름들이 리스트의 형태로 나오는 경우가 있고
치킨이나 피자등 음식 이름이 카테고리로 나오는 경우까지 총 3가지 경우가 있습니다.
이 경우들을 다 나누어주어야 함으로 try가 3번으로 중첩되었습니다.
세 경우 모두 아니라면 전부 NULL을 할당합니다.
다음 조건문과 예외처리문이 섞여있는 뭉치를 살펴보도록 합시다.
어떤 값이 2이냐 3이냐에 따라 코드를 구분했습니다.
이 가게를 보면 별점이 없고
이 가게는 별점이 있습니다.
같은 코드로 스크래핑을 하면 어떤 결과가 나올까요?
이 코드를 보면 가져온 xpath의 요소들이 어떤 배열의 형태를 띄고있는 것을 볼 수 있습니다.
맨 위 부분이 별점이고 순서대로 방문자리뷰, 블로그 리뷰입니다.
여기서 별점이 없어진다면 배열이 한 칸씩 앞으로 밀려서 소스가 나오기 때문에 스크래핑 했을 때 잘못된 결과를 가져올 수 있습니다.
따라서 저 부분의 길이를 재서 2이냐 3이냐에 따라 코드를 나누어 주었습니다.
나중에 스크래핑 데이터 전처리를 할 때 세 개의 값 중 하나라도 NULL이 들어갔다면 drop 시켜줬기 때문에 결국은 필요없는 로직이 되었군요.
어찌됐던 이렇게 해서 음식점 1914개의 별점과 리뷰수를 전부 가져왔습니다.
셀레니움 스크래핑 고찰
1) 데이터가 로딩되기 전에 스크래핑을 시도하면 결측이 되기 때문에 timesleep 1초면 충분하다고 생각하고 슬립을 주었는데 제대로 스크랩이 안되는 경우가 있었습니다.
이럴땐 셀레니움에서 wait라는 방법이 있는데 이것도 불안정하기 때문에 추천하지 않는다고 합니다.
expected_conditions를 사용하는 걸 추천드립니다.
로딩이 끝날때까지 기다리자 (Waits)
Selenium을 사용해 테스트를 할때 element를 찾을 수 있도록 Web Page가 로딩이 끝날때 까지 기다려야 합니다. AJAX를 이용해 만든 Web의 경우 리소스가 로드하는데 부문별로 다를 수 있습니다. Selenium에
dejavuqa.tistory.com
2) 셀레니움은 느립니다.
자동이라고 한다지만 UI 상에서 제어되는 셀리니움의 특성상 beautiful soup(이하 bs)가 가능하다면 bs를 쓰는게 시간상의 이점이 있습니다.
스크래핑 데이터 전처리는 별점의 평균과 방문자리뷰의 평균을 구해서 평균이하의 가게는 다 잘랐습니다.
아무래도 맛집을 추천하다보니 이런 수치적인 기준이 하나쯤 필요하겠다 생각이 들었습니다.
다음은 Beautiful soup로 네이버 블로그 리뷰를 스크래핑 할 차례입니다.
여기선 처음 말했던 iframe 으로 첨부되어 있는 html 파일의 path를 src에서 건져와서 잘 연결해주는 모양새입니다.
검색어를 loop로 돌리고 검색어 마다 상위리뷰 5개의 텍스트를 모조리 가지고 옵니다.
보면 스크래핑에 실패하는 블로그도 있습니다.
DOM의 구조가 다른 포스팅이랑 확연하게 다른 포스팅이 간혹가다 존재했는데 갯수가 몇 개 되지 않아 저는 무시했습니다.
TF-IDF 벡터화
문서를 TF-IDF 기능의 매트릭스로 변환합니다.
sklearn.feature_extraction.text.TfidfVectorizer — scikit-learn 0.24.2 documentation
scikit-learn.org
작성된 HP는 모델이 너무 깊어지지 않기위한 설정이라고 보면 됩니다.
벡터화한 데이터를 기반으로 코사인 유사도를 분석합니다.
코사인 유사도 - 위키백과, 우리 모두의 백과사전
코사인 유사도(― 類似度, 영어: cosine similarity)는 내적공간의 두 벡터간 각도의 코사인값을 이용하여 측정된 벡터간의 유사한 정도를 의미한다. 각도가 0°일 때의 코사인값은 1이며, 다른 모든
ko.wikipedia.org
파라미터에 들어가는 데이터를 보면 방금 벡터화한 데이터 한 개가 두 번 들어가는 것을 확인할 수 있습니다.
그러니 1행 1열은 자기 자신끼리 비교하는 것이니 당연히 유사도가 1이 나올것이고 그런식으로 우하향으로 내려가는 대각선은 전부 1입니다.
그리고 다른 행열들이 전부 코사인유사도에 기반해서 값이 분석됩니다.
그리고 리뷰 수에 따라서 부여되는 가중치를 삭제했습니다.
버거킹 같은 경우에 리뷰 숫자가 워낙 많아서 피자를 검색하건 사시미를 검색하건 버거킹이 항상 끼어있는 사태가 벌어졌습니다.
결과에 악영향을 끼친다고 판단했습니다.
사실, 스케일러를 적용하는 방법도 있죠.
저번에 사용했었던 RobustScaler 로 feature scaling 을 진행하면
outlier 로 판단되는 값의 영향을 최소화 할 수 있기 때문에 가중치 적용도 나름 평등할 것 같기도 합니다.
하지만 그래도 프랜차이즈가 리뷰수에 압도적인건 부정할 수 없으므로 지우기로 결정했습니다.
또한 현재 동작은 사용자가 입력한 키워드가 가게 상호명에 포함되는지 검사하고 포함되는게 없으면 블로그 텍스트에서 그 키워드가 가장 많이 나온 블로그를 기준삼아서 코사인 유사도 분석 결과를 도출합니다.
기준으로 삼은 가게가 맨 위에 하나가 나오고(1행 1열 유사도가 1이니까 당연히 자기자신이 첫번째) 그 외 유사도가 가장 높은 4개의 결과가 나옵니다.
다음 워드클라우드 만드는 것 까지 간단하게 작성해 보았습니다.
검색어는 '닭발' 로 해볼해보니 '발빠닭' 키워드가 크게 나오네요.
서면에서 핫한가봅니다.
검색어가 닭발인데 주먹밥을 이기고 있습니다.
그리고 Node.js 로 백엔드 구축하고 사이트도 하나 꾸며보았습니다.
서버에서 파이썬 파일을 호출해서 데이터를 파라미터로 넣고 결과를 받아서 다시 리스폰 해주는 식으로 진행했습니다
여기서 입력한 키워드가 서버로 날아감과 동시에 파이썬 파일을 호출해서 파라미터로 집어넣습니다.
그리고 로컬에서 앞서 했던 유사도를 분석해서 결과를 띄워줍니다.
개인적으로 유익하고 재밌는 시간이었네요.
'인공지능' 카테고리의 다른 글
(ML/DL)Heart Attack 예측 모델 (0) | 2021.07.26 |
---|---|
타이타닉 생존자 예측, 머신러닝(feat.sklearn) (0) | 2021.07.05 |