개발 동기
티스토리(Tistory)는 자체적으로 포럼(Forum) 사이트를 제공함으로써 많은 블로거들의 소통 공간을 마련해주고 있다.
포럼을 한 번이라도 이용해본 유저라면 알겠지만, 티스토리 블로거들 사이에는 소통뿐만 아니라 상호간의 맞구독이라는 문화가 존재한다.
여기서 '맞구독'이란, 블로거들끼리 서로의 블로그를 구독하고 협업(?)하는 개념이다.
구독자가 많으면 많을 수록 자신이 등록한 게시글을 보기 위해 블로그를 방문하는 이용자가 늘어날뿐만 아니라,
사람들이 이 블로그를 이만큼 구독할 정도로 신뢰도가 있다는 것을 의미하기 때문에
많은 티스토리 블로거들이 맞구독을 하기위해 본인의 블로그를 포럼에서 홍보하고 있는 상황이다.
본인 또한 포럼을 자주 이용하며, 스크린샷의 댓글처럼 다양한 블로거들의 게시글에 댓글을 달며 소통하고 맞구독하기 위해 노력하는 중이다.
그러다 문득 나의 '반복적인 행동'에 눈길이 끌렸고,
이 패턴을 파이썬 크롤링(Crawling) 프로그래밍을 통해 자동화(Auto)해보면 어떨까하는 생각이 들어 개발해보았다.
개발 과정
개발 라이브러리로는 크롤링의 대표적인 라이브러리인 '셀레니움(Selenium)'을 사용하였다.
사실 처음에 BeautifulSoup 라이브러리를 사용해보려고 했지만, 이 라이브러리로는 동적인 소스코드는 크롤링이 불가능하다는걸 알게되어 셀레니움으로 변경하였다.
현재 상황이 싸지방이다 보니, CMD창을 열 수가 없어서 pip으로 파이썬 라이브러리 설치가 불가능하다.
그렇기때문에 개발 환경은 리눅스 명령어로 간단히 라이브러리 설치가 가능한 '코랩(CoLab)'을 선택하였다.
!pip install selenium
!apt-get update
!apt install chromium-chromedriver
위에서 언급한 것처럼 명령어를 사용하여 셀레니움(Selenium) 라이브러리를 코랩의 Jupyter 노트북 개발환경에 설치하였다.
이 명령어를 실행하면 아래의 이미지와 같이 라이브러리를 설치하는 문장들이 출력된다.
맨 마지막 문장이 출력되면 설치가 끝난 것이다.
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
설치를 완료하였으면 셀레니움 패키지에 포함되어 있는 webdriver, Keys, By를 import해준다.
webdriver는 크롬창(Chrome)을 열기 위해 크롬 드라이버에 접근할 수 있도록 해주며,
Keys는 webdriver로 오픈한 크롬창에 키보드 값을 전달하고, By는 HTML 선택자(Selector) 요소로 어떤 것을 선택할지 입력하는 역할을 한다.
chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument('--headless') #내부 창을 띄울 수 없으므로 설정
chrome_options.add_argument('--no-sandbox')
chrome_options.add_argument('--disable-dev-shm-usage')
driver = webdriver.Chrome('chromedriver',chrome_options=chrome_options)
driver.get("https://accounts.kakao.com/login?continue=https%3A%2F%2Fkauth.kakao.com%2Foauth%2Fauthorize%3Fis_popup%3Dfalse%26ka%3Dsdk%252F1.39.16%2520os%252Fjavascript%2520sdk_type%252Fjavascript%2520lang%252Fko-KR%2520device%252FWin32%2520origin%252Fhttps%25253A%25252F%25252Fwww.tistory.com%26auth_tran_id%3Dnhcg5rir8ub8aef3eeb03fa312b81795386484f051kpdx0ii6%26response_type%3Dcode%26state%3DaHR0cHM6Ly93d3cudGlzdG9yeS5jb20v%26redirect_uri%3Dhttps%253A%252F%252Fwww.tistory.com%252Fauth%252Fkakao%252Fredirect%26client_id%3Db8aef3eeb03fa312b81795386484f051")
파이썬 IDLE창으로 셀레니움을 이용하면 실제로 크롬창을 열어 어떤식으로 크롤링이 이루어지는지 볼 수 있지만,
현재 개발환경은 코랩(Colab)이므로 크롬창이 열리지 않는다.
그렇기때문에 환경에 맞게 위 4줄의 코드를 입력하여 크롬 내부 창을 띄울 수 없다는 옵션을 추가한다.
추가가 완료되었다면, 크롬 드라이버를 가져와서 티스토리의 카카오 페이지 로그인창을 띄운다.
코드 맨 아래에 있는 URL은 카카오 로그인 페이지 url 주소이다.
(본인 블로그 계정은 카카오 연동이기 때문에 해당 페이지를 열도록 설정하였다.)
코랩 환경에서는 창이 뜨지 않아 코드를 실행해도 어떻게 진행됐는지 알 수 없겠지만,
실제로는 이 창이 열려있는 상태이다.
이제 우리는 로그인을 해야하는데, 여기서 셀레니움 라이브러리를 제대로 사용할 때가 왔다.
키보드의 F12를 누른 후 이메일 입력창에 마우스를 갖다 대보자.
그럼 이런 창이 뜨면서 로그인 페이지의 HTML 코드가 나타나는데, 우리가 필요한건 이메일 input 태그의 name값이다.
확인해본 결과 이메일 입력창의 name값은 'email'이고 비밀번호 입력창은 'password'이다.
이제 이 name값을 driver 객체에 전달해주면 로그인이 이루어진다.
#티스토리 로그인
email = input('email : ')
password = input('password : ')
#티스토리 로그인 코드
login_id = driver.find_element(By.NAME, 'email')
login_password = driver.find_element(By.NAME, 'password')
login_id.send_keys(email)
login_password.send_keys(password)
login_password.send_keys(Keys.RETURN)
driver.implicitly_wait(3)
티스토리 로그인을 위해 코드로 카카오 계정의 이메일과 비밀번호를 입력받아야 한다.
그 다음으로 driver 객체에 find_element() 메소드가 있는데,
이 메소드의 매개변수로 By.NAME과 위에서 찾은 name의 값(value)을 전달해주면, 로그인 페이지의 이메일과 패스워드 입력란을 가져올 수 있다.
가져온 login_id와 login_password 객체에 입력받은 카카오 계정 정보를 send_keys() 메소드를 통해 전달해주고,
마지막에 Keys.RETURN까지 입력하여 엔터키를 누른 효과를 낸 후 3초 기다려주면 로그인이 완료된다.
※ 하지만 제대로된 계정으로 로그인을 하지 않으면 아래 코드들이 제대로 작동하지 않을 것이다. ※
#안녕하세요ㅎㅎ\n저는 IT/코딩 블로그를 운영하고 있습니다~~!!\n서로 맞구독하고 소통해요 :)
#포럼 게시글마다 등록할 댓글 입력
comment = str(input('댓글 : '))
startpage = int(input('포럼 시작 페이지 : '))
lastpage = int(input('포럼 마지막 페이지 : '))
if startpage > lastpage: #만약 입력받은 시작 페이지 값이 마지막 페이지보다 큰 경우 예외 처리
temp = startpage
startpage = lastpage
lastpage = startpage
그 다음엔 등록할 댓글을 입력하고, 포럼의 페이지수를 입력받는다.
포럼의 페이지수란 홈페이지 맨 하단에 위치한 페이지바의 숫자들을 의미한다.
예를 들어, startpage 변수에 1을 입력하고, lastpage에 10을 입력해주면 1 ~ 10 페이지까지 사이트를 돌면서 댓글을 등록해준다.
예외 처리로는 시작 페이지가 마지막 페이지보다 클 경우엔, 반복문 코드에서 오류가 발생할 수 있기 때문에 시작 페이지와 마지막 페이지의 숫자를 바꿔주도록 하였다.
#포럼에서 자동으로 댓글달기
#for page in range(startpage,lastpage+1):
for page in range(startpage, lastpage):
driver.get('https://www.tistory.com/community/forum/?page=' + str(page))
driver.implicitly_wait(3)
print(page)
#댓글창 펼치기
opens = driver.find_elements_by_css_selector('#root > div > div.content_list > ul > li > div > button')
for open in opens:
open.click()
text_boxes = driver.find_elements_by_css_selector('#root > div > div.content_list > ul > li.on > div.box_cmt > div > form > fieldset > textarea') # 댓글 텍스트 입력창
#names = driver.find_elements_by_css_selector('#root > div > div.content_list > ul > li > div.box_cmt > div.wrap_cmt > div > div > div > a.txt_id') # 댓글 닉네임
#print(names)
for text_box in text_boxes:
#text_box.send_keys('안녕하세요ㅎㅎ\n저는 IT/코딩 블로그를 운영하고 있습니다~~!!\n서로 맞구독하고 소통해요 :)')
text_box.send_keys(comment)
text_box.submit()
우선 반복문을 통해 시작페이지부터 마지막 페이지까지 순차적으로 댓글을 등록하도록 하였다.
driver 객체의 get() 메소드로 페이지를 불러오고, 페이지를 불러오는 동안 3초정도 기다린 후 작업을 시작한다.
포럼 게시글의 댓글 창을 보기 위해서는 글 본문을 한 번 클릭해야 내용이 보이기 때문에,
클릭해야 하는 부분을 opens 변수에 불러와서 click() 메소드로 모두 열어주었다.
click() 메소드를 통해 이제야 모든 게시글의 댓글 입력창이 보이게 되었다.
창이 열렸다면 댓글을 입력하는 textarea 부분을 CSS_Selector로 요소들을 가져오는 find_elements_by_css_selector() 메소드를 사용하여 text_boxes 변수에 담아준다.
그 이후에는 각 댓글 입력창마다 반복문을 통해 comment 변수에 담아두었던 문장을 입력하도록 하면 자동으로 댓글을 등록하는 프로그램이 완성된다.
결과 및 문제점
본인은 1페이지부터 300페이지까지 댓글을 달도록 설정하고 프로그램을 실행해보았다.
실행 결과, 위 사진처럼 해당하는 범위 내의 게시글에 내 댓글이 모두 등록되었다.
이 글을 보신 구독자분들 중에 위 댓글을 보고 방문해주신 분들이 분명 있을 것이다..!!
(구독자분들 환영합니다!!😉)
아래에는 프로그램을 통해 여러 블로거분들의 포럼 게시글에 간단한 블로그 소개와 맞구독을 요청을 한 결과이다.
평균 방문자수가 30명대였던 블로그에 댓글을 보고 방문해주신 블로거분들 덕분에
하루만에 방문자수가 전일대비 489명이나 늘어났다.
맞구독을 하자고 댓글을 달았기때문에 많은 분들이 구독을 눌러주셨다.
덕분에 구독자수는 70명대에서 176명으로 늘어났다.
본인 또한 구독을 눌러주신 분들의 블로그에 방문하여 맞구독을 하고 댓글도 달았다.
지금까지는 프로그램을 통한 효과와 장점이었고, 이제 프로그램의 문제점에 대해 설명하겠다.
해당 프로그램을 여러번 실행시키면 동일한 게시글이나, 이미 댓글을 달아놓은 게시글에도 또 다시 댓글을 다는 문제점이 존재한다.
즉, 생각없이 프로그램을 여러번 실행시키면 다른 블로거분들의 포럼 게시글에 동일한 댓글이 여러개 등록될 수도 있다는 것이다.
(프로그램 테스트 과정에서 댓글이 여러 번 달리게 되어 알림 중복이 되신 분들께 진심어린 사죄의 말씀 올립니다..😖)
해결 방안은 이미 내 블로그의 구독자이거나, 댓글에 내 닉네임이 있는 글은 필터링을 통해 PASS하도록 코드를 수정하는 것이다.
시도를 안해본 것은 아니지만 셀레니움 라이브러리에 대해 깊게 공부한 것이 아니기때문에 개발 과정에서 막히는 부분이 있어, 바로 개념을 적용하지 못했다.
일단 파이썬 크롤링을 통해 이런식으로 프로그램을 만들 수도 있다는 것을 보여주고 싶은 것이 목적이었고,
이후에 해결 방안을 적용한 코드가 완성되면 다시 포스팅을 작성할 예정이다.
복잡한 코드로 이루어진 프로그램은 아니지만, 오픈 소스로 공개하여 필요한 분들이 사용할 수 있도록 하겠다.
+ 댓글을 확인해보니 이런 반복적인 행동은 티스토리 정지 사유가 될 수도 있다고 합니다.
+ 사용하는건 자유지만, '프로그래밍을 통해 이런것도 가능하구나!' 까지만 생각하시는 것을 권장합니다.👍
👍클릭으로 구독하기👍
(이해가 다소 힘들거나, 틀린 부분이 있다면 댓글 부탁드리겠습니다! 😊)
💖도움이 되셨다면 '구독'과 '공감' 부탁드립니다!💖
'Programming > 파이썬' 카테고리의 다른 글
[파이썬] Python Sqlite3 모듈을 사용하여 Database를 생성하고 데이터를 관리해보자 (10) | 2021.06.14 |
---|---|
[파이썬] Python SMTP 모듈을 사용하여 Email 전송하기 / SMTPAuthenticationError : 534 오류 해결 방법 (27) | 2021.06.07 |
[Develop/파이썬] 셀레니움 크롤링(Crawling) - Tistory 포럼 자동 댓글 프로그램 문제점 개선하기 (45) | 2021.06.06 |
[파이썬] 코랩(CoLab)에서 구글 드라이브 파일(csv, txt ...) 가져오기 (23) | 2021.06.05 |
[파이썬/Error] 셀레니움 unknown error: ChromeDriver only supports characters in the BMP 해결방법 (94) | 2021.06.03 |