2017년 11월 10일 금요일

파이썬을 이용한 네이버 카페 업무 자동화

네이버의 영어책 읽기 카페에서 스탭으로 활동하고 있는데, 연말에 회원 레벨 조정 작업을 할 일이 생겼다. 간단한 일이지만 수백명이나 되는 회원에 대해 확인을 수동으로 다 하려니 상당히 지루한 일이 될 것 같아, 자동화를 위해 방법을 찾아보기로 했다.

일단 아래 적은 것들 대부분 인터넷 검색하면 다 나오는 것이므로, 다른 사이트에서 자세히 설명되어 있는 내용을 부가적으로 설명하지는 않고 전체적인 흐름만 기록하고자 한다. 전체적으로 여기의 도움을 많이 받았다.

첫번째로 필요한 것은 파이썬 설치다. 아직 파이썬2를 쓰는 사람도 있지만 특별한 이유가 없다면 가급적 파이썬3를 설치하도록 하자. Windows 피씨에도 무리없이 설치할 수 있고, path도 설정해 주면 cmd 터미널에서 현재 어느 디렉토리에 있든지 쉽게 사용 가능하다.

둘째 웹 자동화에 필수적인 것이 셀레늄(Selenium)이다. 파이썬 모듈로 설치하면 된다. pip install selenium 명령으로 쉽게 설치할 수 있다. 또한 웹페이지를 읽고 처리하려면 Beautiful Soup의 도움이 필요하다. 역시 pip을 써서 pip install bs4 명령으로 쉽게 설치할 수 있다.

세째 셀레늄에서 다룰 수 있는 브라우저 설치다. 크롬 드라이버를 설치하면 된다. 위에서 언급한 블로그에 자세히 나와 있으므로 따라하면 된다.

다 설치되었으면 cmd 창에서 python shell을 띄우고 크롬을 띄워보자. 크롬 브라우저가 새로 뜨면서 "자동화된 테스트 소프트웨어에 의해 제어되고 있습니다"라는 안내창이 보일 것이다. 아래에서 물론 경로는 크롬 드라이버가 깔려 있는 디렉토리명이다.

>>> from selenium import webdriver
>>> driver = webdriver.Chrome('c:/temp/chromedriver')

네째로 알아야 할 것은 브라우저의 개발자 도구다. 이건 별도로 설치할 필요는 없고 크롬 메뉴에서 개발자 도구를 선택하면 된다. 웹페이지에서 특정 리스트 항목이나 버튼의 element나 xpath를 확인하기 위해서는 마우스 오른쪽 버튼을 클릭하고, 맨 아래 "검사(N)" 메뉴를 선택하면 된다. 즉시 오른쪽에 새로운 창이 생기면서 상세한 내용을 보여준다.

이제 본격적으로 네이버를 공략할 차례다. 매일 자동으로 사람 손을 거치지 않고 반복해서 해야 하는 일이 있다면 로긴을 위해 아이디, 패스워드를 자동으로 보낼 수도 있으나, 코드에 하드코딩하는 것은 가급적 피하는 것이 좋다. 나는 아이디까지만 입력된 상태에서 파이썬 코드는 잠시 대기시키고, 패스워드 입력은 수동으로 하는 쪽을 택했다. input()을 이용해 파이썬은 대기시킨 상태에서, 패스워드 입력 후 로긴에 성공하고 나서 cmd 창에서 enter를 눌러 이후 코드를 진행시켜주면 된다.

네이버 카페에서 내가 필요로 하는 작업은 두가지였다. 하나는 관리 메뉴에서 특정 레벨의 회원 명단을 조회하여 아이디 리스트를 얻어오는 것, 둘째는 특정 게시판에서 이 아이디로 각각 검색하여 검색 결과 (게시물의 개수)를 얻어오는 것. 현재는 해당 레벨의 회원 수가 수백명 수준이라 대충 마우스로 긁어다 엑셀에 넣는 방식으로 아이디 리스트를 뽑아내는 것도 가능하겠지만, 만약 수천명이 된다면 그렇게는 불가능할 것이다.

1. 특정 레벨의 아이디 리스트 얻기
네이버 카페 관리 메뉴의 전체 회원 조회 페이지를 보면, 드롭 다운 메뉴로 레벨을 고르고, 또 그 옆의 드롭 다운 메뉴로 한 페이지에 보여지는 회원수를 설정하게 되어 있다. 회원수가 한번에 보여줄 수 있는 숫자를 넘게 되면 하단에 페이지 번호가 표시된다.

드롭 다운 메뉴가 골라진 상태(특정 등급, 한번에 보여주는 회원 수)의 쿼리 URL이 있을 법한데 찾기 어려워, 셀레늄을 이용해 드롭 다운 메뉴를 선택시켰다. 드롭 다운 메뉴를 골라 선택하기 위해서는 브라우저의 개발자 모드를 이용해 element의 id를 찾고, 셀레늄의 Select를 활용해 해당 값을 찾아내어 select하면 된다. (하기 코드 #18~#26 참고)

이제 원하는 명단이 화면에 떴으니, 필요한 정보를 골라 저장하면 된다. Beautiful Soup을 활용하면 다양한 조건에 맞는 element들을 찾아낼 수 있다. 리스트로 뽑아진 결과물에서 내가 필요로 하는 것은 memberid 뿐이므로, 리스트에서 memberid만 추출해 파일에 따로 저장한다.

멤버 명단이 한 페이지가 넘어가면 다음 페이지로 넘겨야 한다. 다행히 총 멤버 수를 명시해 주기 때문에, 해당 멤버수를 근거로 몇번이나 페이지를 넘겨야 할지 알 수 있다. 문제는 1000명이 넘어가면 정확한 숫자가 아니라 "1000이상"으로 출력한다는 것이고, 이 문제는 나중에 따로 생각해 봐야 할 것 같다. 10페이지 단위로 페이지 넘김이 컨트롤되기 때문에 1000명 이상의 임의의 숫자에 잘 대응하는 코드를 작성하려면 좀 고민이 필요해 보인다. 당장 내가 작업해야 하는 등급의 멤버는 400여명 수준이라 이 고민은 일단 생략.

아무튼 페이지 넘기는 버튼은 크롬 개발자 도구에서 xpath를 찾아내어 Selenium으로 클릭해 준다. 여기서 나중에 실행시 이 버튼이 안 찾아진다는 오류 메시지를 만나서 당황했었는데, 알고보니 네이버에서 플래쉬 관련 공지가 해당 버튼을 덮어버려서 생긴 문제였다. 명단 첫 페이지 띄울 때 한번만 뜨기 때문에 나는 그냥 수동으로 닫았는데, 찾아서 자동으로 닫는 걸 시도해도 좋을 듯 하다.

새로운 페이지를 띄울 때마다 Beautiful Soup에 넘기기 전에 살짝 sleep을 주는게 좋다. 안 그러면 덜 완성된 부정확한 정보가 넘어가게 될 수 있다. Selenium Webdriver의 wait을 이용하는 방법과 그냥 간단히 time.sleep()을 이용하는 방법이 있는데 다양하게 테스트해보고 싶었으나 귀찮으므로 일단 2, 3초간 sleep()을 주는 것으로 간단히 해결.

네이버 로긴부터 아이디 수집까지 정리된 코드를 아래 정리했다. 인원수에 따른 반복 처리 및 페이지 넘김 부분은 생략했으니 필요시 추가하면 된다.


2. 찾아진 명단으로 게시판 검색
게시판 검색은 다행히 URL을 이용한 쿼리로 대부분 가능하기 때문에, 앞의 경우처럼 버튼의 xpath를 찾아서 클릭해줘야 할 필요는 없었다. 나는 검색으로 찾아진 게시물의 개수만 필요했기 때문에 (50개가 넘는 경우도 굳이 알 필요 없었기에) 간단하게 끝났지만, 해당 게시물들을 크롤링하며 추가 정보를 찾는 경우나 50개를 넘어서 정확한 게시물의 개수를 다 세어야 하는 경우라면 좀더 복잡한 로직이 필요할 것이다.

쿼리는 아래와 같이 필요한 정보를 넣으면 된다. 기간 정보도 아래처럼 search.searchdate로 포함시킬 수 있다. 검색 버튼을 마우스 우클릭하고 새 탭에서 열기를 누르면 쿼리 URL을 볼 수 있으며, 이 중 불필요한 것은 지우고 필요한 것만 사용하면 된다.

http://cafe.naver.com/카페주소?iframe_url=/ArticleSearchList.nhn%3Fsearch.clubid=클럽아이디%26search.menuid=1280%26search.searchdate=2017-01-012017-12-31%26userDisplay=50%26search.query=검색어

검색으로 나온 게시글 리스트에 접근하려면 먼저 iframe으로 전환해야 한다. 이후 Beautiful Soup select로 원하는 리스트를 찾아서 개수를 저장했다.

아래 정리된 코드는 네이버 로긴 부분은 생략하고, 파일에서 멤버 아이디를 읽어와서 해당 아이디로 검색하고, 해당하는 게시글의 개수를 구해서 저장하는 루틴이다.



결론적으로 네이버 카페도 Selenium과 Beautiful Soup, 그리고 크롬 개발자 도구를 이용해 원하는 작업을 대부분 자동화시킬 수 있을 것으로 보인다. 다만 대부분 iframe 안에서 테이블 리스트 구조로 컨텐츠가 되어 있고 한 화면에 최대로 보여줄 수 있는 리스트의 수가 정해져 있어, 여러 페이지로 결과물이 나오게 될 경우 페이지를 넘겨 가며 작업하는 루틴을 짜는 것이 좀 번거로울 듯 하다.


참고한 글
1. 나만의 웹 크롤러 만들기(3): Selenium으로 무적 크롤러 만들기
2. Django selenium으로 iframe 내부에 접근하기
3. Beautiful Soup 4.4.0 documentation
4. http://selenium-python.readthedocs.io/waits.html
5. 블로그 등에 소스 코드 Snippet 붙여넣기 - GitHub Gist