2019. 9. 5. 16:06ㆍ프로그래밍 언어/Python
지인 요청으로 네이버 카페 게시물의 댓글수와 조회수를 가져오는 간단한 크롤러를 만들었습니다.
요구사항
input : 네이버 카페 게시물 url 리스트가 있는 엑셀 파일 (.xlsx)
process : 게시물 url에서 댓글 수와 조회수를 가져온다. 엑셀 파일 해당 라인의 댓글 수, 조회수 열에 덮어쓰기한다.
output : 댓글 수, 조회수가 덮어쓰기 된 엑셀 파일 (.xlsx)
* 기재된 카페와는 아무 관련이 없습니다.
개발 환경
[OS]
- MacOS Mojave 10.14.6
[Language]
- Python 3.7
[Library]
- Selenium 3.141.0
- Beautiful Soup4 4.8.0
- OpenPyXL 2.6.3
[Driver]
- ChromeDriver 76.0.3809
[IDE]
- Eclipse 2019-06 (4.12.0)
- pyDev 7.3.0
아래는 크롤러를 구현하면서 발생한 문제점과 해결방법들을 적어보겠습니다.
정답은 아니고 제가 해결해본 방법일 뿐이기 때문에
다른 좋은 방법이 있거나 제 방식이 틀렸을 경우 댓글 부탁드리겠습니다 !!
1. ChromeDriver 버전 오류
https://sites.google.com/a/chromium.org/chromedriver/downloads
위의 링크에서 크롬 드라이버를 설치했습니다.
자신의 PC에 설치된 크롬 버전과 드라이버의 버전이 맞아야 합니다.
버전확인을 잘 하시고 OS에 맞는 파일을 다운받아서 압축해제하시면 됩니다.
크롬 버전 확인은 아래의 두 경로에서 확인이 가능합니다.
(직접 주소창에 입력해주셔야합니다.)
만약 버전에 맞지 않는 드라이버를 설치했을 경우 아래와 같은 exception이 발생합니다.
selenium.common.exceptions.SessionNotCreatedException: Message: session not created: This version of ChromeDriver only supports Chrome version 77
2. ChromeDriver 경로 오류
크롬 드라이버를 아래처럼 일반 사용자 폴더인 Documents, Downloads에 압축해제후 연결할 경우
# 크롬 드라이버 연결
driver = webdriver.Chrome('/User/사용자이름/Documents/chromedriver')
크롬 드라이버 실행파일이 경로에 있어야 한다는 exception이 발생합니다.
selenium.common.exceptions.WebDriverException: Message: 'chromedriver' executable needs to be in PATH. Please see https://sites.google.com/a/chromium.org/chromedriver/home
이 문제는 드라이버 경로를 /usr/local/bin 하위에 위치시켜서 해결하였습니다.
# 크롬 드라이버 연결
driver = webdriver.Chrome('/usr/local/bin/chromedriver')
4. 네이버 로그인
네이버 카페 게시물을 보려면 아래의 조건을 충족해야 합니다.
1) 게시물이 전체공개일 때
① 로그인하지 않아도 조회 가능
2) 게시물이 멤버공개일 때
① 네이버에 로그인 되어있는 상태
② 해당 카페에 가입되어있는 상태
③ 해당 게시물을 볼 수 있는 권한 (회원등급)이 있는 상태
2-2, 2-3번 문제의 경우 요청하신 분 께서 권한은 전부 있다고 하셔서 넘겼습니다.
2-1번 문제는 맨 처음 실행시 네이버 로그인 후 카페 게시물로 페이지 이동하도록 수정했습니다.
네이버 정책상 셀레늄 같은 자동화 도구를 통한 접근을 부정적 이용으로 판단하고 있어
가장 간단하게 send_keys 메소드를 이용해 로그인 구현시 캡챠(자동입력방지)가 실행되어 한 번에 로그인이 되지 않습니다.
# 네이버 로그인
id = 'user_id' # 사용자 아이디
pw = 'user_password' # 비밀번호
driver.find_element_by_name('id').send_keys(id)
driver.find_element_by_name('pw').send_keys(pw)
driver.find_element_by_class_name('btn_global').click()
그래서 아래와 같이 스크립트 구문을 만들어서 아이디와 비밀번호를 입력했습니다.
중간중간 타임슬립도 랜덤하게 지정해주면 캡챠에 잘 걸리지 않는다고 하여 추가했습니다.
그러나 추후에는 이 방법도 막힐 수 있습니다.
# 네이버 로그인
id = 'user_id' # 사용자 아이디
pw = 'user_password' # 비밀번호
driver.execute_script("document.getElementsByName('id')[0].value=\'" + id + "\'")
driver.execute_script("document.getElementsByName('pw')[0].value=\'" + pw + "\'")
time.sleep(randrange(1,3))
driver.find_element_by_class_name('btn_global').click()
4. iframe
우선 네이버 카페 게시물은 이렇게 생겼습니다.
오른쪽 부분이 게시물 컨텐츠가 담긴 부분인데요, 여기가 iframe으로 구성되어있습니다.
코드로 보시면 "cafe_main"이란 name의 iframe이 있고
#document가 중첩되어 새로 시작되는 것을 볼 수 있습니다.
iframe 태그에서 src를 "about:blank"로 받아오기 때문에, Beautiful Soup4만 써서는 크롤링이 어려웠습니다.
결국 Selenium과 Beautiful Soup4를 같이 사용해 iframe의 src를 받아오고
switch_to 메소드로 프레임을 전환하여 cafe_main 하위에 있는 요소에 접근하였습니다.
driver.switch_to_default_content # 상위 프레임으로 전환
driver.switch_to.frame('cafe_main') # cafe_main 프레임으로 전환
html = driver.page_source # 현재 페이지의 주소를 반환
soup = BeautifulSoup(html, 'html.parser')
# 댓글수와 조회수를 찾는다
reply_sort = soup.find_all('div', class_='fl reply_sort')
5. 조회수를 알 수 없는 게시물
6. 삭제된 게시물
try-except 구문으로 감싸서
얼럿 창이 있을 경우 삭제되었거나 없는 게시물
없을 경우 댓글수/조회수 수집하도록 처리
2021-03-08 본 게시물의 크롤러는 공유가 어려운 점 참고부탁드립니다.
'프로그래밍 언어 > Python' 카테고리의 다른 글
Selenium 개발도구 로그 숨기기 (0) | 2020.06.24 |
---|