Limetime's TimeLine
article thumbnail
반응형
 

티스토리 자동 구독 및 자동 댓글 프로그램 만들기 프로젝트!

요즘 티스토리 블로그에 무작위 구독을 돌리는 사람이나 댓글을 다는 사람이 무척 많아졌다. 일종의 카피캣들이 많아진 것이다. 누가 시초인지는 모르겠으나, 다른 블로그(네이버)들도 마찬가

limetimeline.tistory.com

 

 

[티스토리 자동댓글 및 자동구독] 2. Anaconda 환경 구축 및 Python 라이브러리 설치

티스토리 자동 구독 및 자동 댓글 프로그램 만들기 프로젝트! 요즘 티스토리 블로그에 무작위 구독을 돌리는 사람이나 댓글을 다는 사람이 무척 많아졌다. 일종의 카피캣들이 많아진 것이다. 누

limetimeline.tistory.com


1. Google Chrome Driver

Selenium 크롤링을 하기 위해선 크롬 드라이버가 필요하다. 이 크롬 드라이버를 자동으로 열어서 Selenium이 우리가 코딩한대로 조작한다. 파이썬 코드가 입력된 py파일과 같은 폴더에 있어야한다.

우선 본인의 크롬 브라우저 버전을 파악해야 한다. 두 가지 방법이 있다.

① 브라우저 상단 URL 입력창에 'chrome://settings/help' 입력

② 설정 - Chrome 정보

버전은 '117.0.5938.92' 라고 나와 있다.

 

Chrome for Testing availability

chrome-headless-shellmac-arm64https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/118.0.5993.32/mac-arm64/chrome-headless-shell-mac-arm64.zip200

googlechromelabs.github.io

Stable한 chromedriver를 다운받으면 된다.

그 후 압축 풀어서 나온 chromedriver.exe를 python 파일과 같은 폴더에 넣어준다.

 

2. 티스토리 로그인

기본적으로 로그인은 해야 구독을 하든, 댓글을 쓰든 할 수 있을 것이다. 자동으로 로그인을 할 수도 있지만, 카카오톡 인증처럼 이중 인증을 해놓은 상태에선 차라리 수동으로 하는 것이 낫다.

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
import time
import os
import random

driver = webdriver.Chrome()
url = 'https://www.tistory.com/feed'
driver.get(url)

위 코드는 크롬을 열어서 https://www.tistory.com/feed 를 열라는 뜻이다. feed페이지로 가려면 로그인이 필요하므로 로그인을 하면 된다. 이제 위 코드가 기본 코드가 될 것이다.

 

3. 전체코드

CommentList : 댓글 종류다. 원하는거 추가하거나 수정하면 된다.

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
import time
import os
import random

driver = webdriver.Chrome()
url = 'https://www.tistory.com/feed'
driver.get(url)

# 쓸 수 있는 댓글 리스트입니다. 수정 및 추가는 자유입니다~
CommentList = ["좋은 글 보고 갑니다.", 
    "글을 잘 쓰시네요~ 좋은 하루보내세요!", 
    "좋은 글 보고가요~", 
    "좋은 정보 얻었어요~ 좋은 하루보내세요~", 
    "좋은 정보 얻어가요~ 또 올게요!", 
    "글을 참 잘 쓰시네요! 좋은 정보 감사합니다~", 
    "글을 잘 쓰시는 것 같아요! 좋은 글 감사합니다~", 
    "포스팅 잘봤습니다. 행복한 하루되세요.", 
    "공감 꾸욱하고 갑니다. 기분좋은 하루 보내세요.^^", 
    "언제나 좋은 글 올려주시네요. 잘 보고 갑니다. 감사합니다", 
    "오늘도 유익한 포스팅 잘보고 공감 살포시 누르고 갑니다! 좋은 하루 보내세요~"]

# 스토리 리스트 이므로 건드릴 필요 없습니다.
CategoryList = ["life", "travel", "culture", "it", "sports", "current"]


# ------ 자동 댓글/공감 프로그램 ------
#  *주의 : 크롬 창을 끄지 마세요!, 반드시 로그인 한 상태에서 진행하세요.
# 1. 구독자 피드 리스트 생성  --> 구독자가 있을 때 진행하세요. 구독자가 0명이면 '3번 구독 늘리기'부터 하세요. (추가된 리스트는 postList.txt에 저장됩니다.)
# 2. 댓글 쓰기 및 공감 누르기  --> '1번 구독자 피드 리스트 생성'이나 '4번 스토리 피드 리스트 생성'을 한 번이라도 진행해야 가능합니다.
# 3. 구독늘리기(최대 500개)   --> 구독자가 없거나 구독자를 늘리고 싶을 때, 진행하세요. (단순히 구독만 합니다.)
# 4. 스토리 피드 리스트 생성  --> 자동구독 및 스토리 피드를 리스트에 추가합니다. (추가된 리스트는 postList.txt에 저장됩니다.)
# 5. PostList 불러오기(postList.txt)   --> 따로 postList.txt에 블로그를 추가해서 불러올 수 있습니다. (양식에 맞춰야 합니다.)







# 피드 리스트 생성 함수
def LoadPost(url):
    driver.get(url)

    # preloading 때문에 내려야함
    for c in range(0,25): # 25가 적당. 안바꿔도 됨 => 더보기 버튼이 작동해서..
        driver.find_element(By.TAG_NAME,'body').send_keys(Keys.PAGE_DOWN)
        time.sleep(1)

    postList = []


    time.sleep(5)
    mArticle = driver.find_element(By.ID,'mArticle')
    
    # preloading 이후 더보기 버튼 클릭
    for i in range(10):
        divSectionList = mArticle.find_element(By.CLASS_NAME,'section_list')
        btn_more = divSectionList.find_element(By.CLASS_NAME, 'btn_more')
        driver.execute_script("arguments[0].click();", btn_more)
        time.sleep(1)

    ul = divSectionList.find_element(By.TAG_NAME, 'ul')

    for item in ul.find_elements(By.TAG_NAME, 'li'):
        aTagHref = item.find_element(By.TAG_NAME, 'a')

        div = item.find_element(By.TAG_NAME, 'div')
        desc_tit = div.find_element(By.CLASS_NAME, 'desc_tit')
        aTagDesc = desc_tit.find_element(By.TAG_NAME, 'a')

        if aTagHref.get_attribute('href')[-1] == '/':
            continue # 링크의 마지막이 /로 끝나면 out
        elif aTagHref.get_attribute('href').rsplit('/',1)[1].count('-') > 0:
            continue # 링크의 페이지 번호가 숫자가 아니라 '블로그-첫-글' 형식이면 out
        elif aTagHref.get_attribute('href').count('/') > 3:
            continue # 링크에 /가 3개 초과이면 out (https://limetimeline.tistory.com/32가 정상.)
        else:
            posts = []
            posts.append(aTagDesc.text) # 글 제목
            posts.append(aTagHref.get_attribute('href')) # 글 링크

            postList.append(posts)

    return postList        

def SaveList(postList):
    with open('postList.txt','w',encoding='UTF-8') as f:
        for post in postList:
            f.write(f'{post[0]}%^%{post[1]}\n')

def OpenList():
    postList = []
    f = open('./postList.txt','r',encoding='UTF8')
    lines = f.readlines()
    for line in lines:
        post = []
        line = line.replace('\n','')
        post.append(line.split('%^%')[0])
        post.append(line.split('%^%')[1])
        postList.append(post)
    f.close()
    return postList
    
# 댓글 쓰기 및 공감 누르기 Setting 함수
def Action(postList):
    while(True):
        answer = 0

        os.system('cls')
        print("------ 댓글 쓰기 및 공감 누르기 Setting ------")
        print(" *주의 : 크롬 창을 끄지 마세요!")
        print("1. 댓글만 쓰기")
        print("2. 공감만 누르기")
        print("3. 댓글도 쓰고, 공감도 누르기")
        print("4. 뒤로가기")

        answer = (int)(input("숫자를 입력하세요: "))
        
        if answer == 1: # 댓글만 쓰기
            for post in postList:
                driver.get(post[1])
                time.sleep(5)
                postNum = post[1].rsplit('/',1)[1]
                PostComment(postNum)
        elif answer == 2: # 공감만 누르기
            for post in postList:
                driver.get(post[1])
                time.sleep(5)
                postNum = post[1].rsplit('/',1)[1]
                PostLike(postNum)
        elif answer == 3: # 댓글도 쓰고, 공감도 누르기
            for post in postList:
                driver.get(post[1])
                time.sleep(5)
                postNum = post[1].rsplit('/',1)[1]
                PostComment(postNum)
                PostLike(postNum)
        elif answer == 4: # 뒤로가기
            return
        else:
            continue

# 공감 누르기 함수
def PostLike(postNum):
    try:
        postbtn_like = driver.find_element(By.CLASS_NAME,'postbtn_like')
        
        print('reaction-'+postNum)
        reaction = postbtn_like.find_element(By.ID,'reaction-'+postNum).click()
    except:
        pass

# 댓글 쓰기 함수
def PostComment(postNum):
    try:
        entryComment = driver.find_element(By.ID,'entry'+postNum+'Comment')

        randomComment = random.randrange(0, len(CommentList))

        print('entry'+postNum+'Comment')

        textarea = entryComment.find_element(By.TAG_NAME, 'textarea')
        textarea.send_keys(CommentList[randomComment])
        print(CommentList[randomComment])
        time.sleep(1)
        form = entryComment.find_element(By.TAG_NAME, 'form')


        Button = form.find_element(By.TAG_NAME, 'button')
        print(Button.text)
        Button.click()

        # Alert 창 대처
        alert = driver.switch_to.alert
        alert.dismiss()

    except:
        return
    
# 자동 구독 함수
def FollowerINC(categoryNum):
    print(f"{CategoryList[categoryNum]} 자동 구독 중...")
    driver.get("https://www.tistory.com/category/"+CategoryList[categoryNum])
    

    # 페이지 preloading 때문에 내려야함
    for c in range(0,30): # 원하는 만큼 지정하면 됨
        driver.find_element(By.TAG_NAME,'body').send_keys(Keys.PAGE_DOWN)
        time.sleep(1)

    time.sleep(10) # 구독하기 로딩

    try:
        mArticle = driver.find_element(By.ID,'mArticle')
        divSectionList = mArticle.find_element(By.CLASS_NAME,'section_list')
        ul = divSectionList.find_element(By.TAG_NAME, 'ul')

        for item in ul.find_elements(By.TAG_NAME, 'li'):
            # 구독 버튼 누르기
            info_subscribe = item.find_element(By.CLASS_NAME, 'info_subscribe')
            button = info_subscribe.find_element(By.TAG_NAME, 'button')

            if str(button.get_attribute('innerHTML')) == "구독하기":
                # 블로그 이름 따기
                a = item.find_element(By.TAG_NAME, 'a')
                info_g = a.find_element(By.CLASS_NAME, 'info_g')
                txt_id = info_g.find_element(By.CLASS_NAME, 'txt_id')
                print(f"블로그 이름 : {txt_id.text} : {button.get_attribute('innerHTML')}")
                driver.execute_script("arguments[0].click();", button)
                time.sleep(1)
            else:
                continue
            
    except:
        pass


def StoryFeed():
    postList = []
    for categoryNum in range(len(CategoryList)):
        print(f"{CategoryList[categoryNum]} 리스트 추가 중...")
        driver.get("https://www.tistory.com/category/"+CategoryList[categoryNum])
        
        # 페이지 preloading 때문에 내려야함
        for c in range(0,50): # 원하는 만큼 지정하면 됨
            driver.find_element(By.TAG_NAME,'body').send_keys(Keys.PAGE_DOWN)
            time.sleep(1)

        time.sleep(10) # 구독하기 로딩

        try:
            mArticle = driver.find_element(By.ID,'mArticle')
            divSectionList = mArticle.find_element(By.CLASS_NAME,'section_list')
            ul = divSectionList.find_element(By.TAG_NAME, 'ul')

            for item in ul.find_elements(By.TAG_NAME, 'li'):
                # 구독 버튼 누르기
                info_subscribe = item.find_element(By.CLASS_NAME, 'info_subscribe')
                button = info_subscribe.find_element(By.TAG_NAME, 'button')

                if str(button.get_attribute('innerHTML')) == "구독하기":
                    # 블로그 이름 따기
                    a = item.find_element(By.TAG_NAME, 'a')

                    info_g = a.find_element(By.CLASS_NAME, 'info_g')
                    txt_id = info_g.find_element(By.CLASS_NAME, 'txt_id')

                    # print(a.get_attribute('href'))

                    if a.get_attribute('href')[-1] == '/':
                        continue # 링크의 마지막이 /로 끝나면 out
                    elif a.get_attribute('href').rsplit('/',1)[1].count('-') > 0:
                        continue # 링크의 페이지 번호가 숫자가 아니라 '블로그-첫-글' 형식이면 out
                    elif a.get_attribute('href').count('/') > 3:
                        continue # 링크에 /가 3개 초과이면 out (https://limetimeline.tistory.com/32가 정상.)
                    else:
                        posts = []
                        posts.append(txt_id.text) # 글 제목
                        posts.append(a.get_attribute('href')) # 글 링크
                        postList.append(posts)

                        # print(f"블로그 이름 : {txt_id.text} : {button.get_attribute('innerHTML')}")
                        time.sleep(1)
                else:
                    continue     
        except:
            pass
    
    return postList
        

def main():
    answer = 0

    mArticle = 'mArticle'
    divSectionList = 'section_list'

    postList = []

    while(True):
        os.system('cls')
        print("------ 자동 댓글/공감 프로그램 ------")
        print(" *주의 : 크롬 창을 끄지 마세요!, 반드시 로그인 한 상태에서 진행하세요.")
        print("1. 구독자 피드 리스트 생성")
        print("2. 댓글 쓰기 및 공감 누르기")
        print("3. 구독늘리기(최대 500개)")
        print("4. 스토리 피드 리스트 생성")
        print("5. PostList 불러오기(postList.txt)")

        answer = (int)(input("숫자를 입력하세요: "))
        
        if driver.current_url == url:
            if answer == 1:
                os.system('cls')
                print("피드 리스트 생성\n")
                postList = LoadPost(url)
                SaveList(postList)
                for i in postList:
                    print(f"title : {i[0]}, href : {i[1]}")
                driver.get(url)

            elif answer == 2:
                os.system('cls')
                if postList is not None:
                    print("댓글 쓰기 및 공감 누르기 \n")
                    Action(postList)
                    driver.get(url)
                else:
                    print("피드 리스트를 생성하고 오세요.")
                    driver.get(url)
                    time.sleep(3)
                    continue

            elif answer == 3:
                print("구독 늘리기\n")
                os.system('cls')
                for categoryNum in range(len(CategoryList)):
                    FollowerINC(categoryNum)
                driver.get(url)
            
            elif answer == 4:
                print("스토리 피드 리스트 생성")
                os.system('cls')
                
                postList = StoryFeed()
                SaveList(postList)
                for i in postList:
                    print(f"title : {i[0]}, href : {i[1]}")
                driver.get(url)
            elif answer == 5:
                print("postList 불러오기")
                os.system('cls')
                postList = OpenList() 
                
            # elif answer ==3:
            #     driver.get('https://wikibaff.tistory.com/67')
            #     PostComment('67')
            else:
                os.system('cls')
                continue
        else:
            print("로그인을 해주세요!!")
            driver.get(url)
            time.sleep(3)
            continue

if __name__ == "__main__":
    main()

 

4. 사용방법

Powershell이나 CMD 같은 터미널에서 아래 명령어를 입력하면 실행할 수 있다.

python 파일이름

 

 

일단 반드시 로그인을 해줘야하고 반드시 피드 리스트가 생성되어야 댓글쓰기 및 공감을 수행할 수 있다.

ⓐ 구독자가 없을 경우

  • 구독늘리기(최대 500개)→구독자 피드 리스트 생성→댓글 쓰기 및 공감 누르기
  • 스토리 피드 리스트 생성→댓글 쓰기 및 공감 누르기
    • 스토리 피드 리스트 생성은 자동 구독 및 스토리 피드를 리스트에 추가한다.
  • PostList 불러오기(postList.txt) →댓글 쓰기 및 공감 누르기
    • postList.txt는 구독자 피드 리스트 생성 및 스토리 피드 리스트 생성을 1회 진행하면 생성된다.
    • 리스트 생성을 하지 않더라도 'postList.txt' 파일을 생성하면 불러올 수 있다.
      • 양식 : 블로그이름%^%블로그주소 (Limetime's TimeLine%^%https://limetimeline.tistory.com)

ⓑ 구독자가 있을 경우

  • 구독자 피드 리스트 생성→댓글 쓰기 및 공감 누르기
  • 스토리 피드 리스트 생성→댓글 쓰기 및 공감 누르기
  • PostList 불러오기(postList.txt) →댓글 쓰기 및 공감 누르기

 

3번으로 구독자를 좀 늘려주고, 1번으로 피드 리스트를 생성해서 2번 댓글 및 공감 누르기 진행해도 된다.

4번으로 스토리 피드 리스트 생성하고, 2번 댓글 및 공감 누르기 진행해도 된다.

일단 피드 리스트나 스토리 피드 리스트를 생성하게 되면 'postList.txt'가 생성되는데 이 파일 안에는 '블로그 이름', '블로그 주소'가 들어 있기 때문에, 혹시나 도중에 오류가 발생하면 파일을 열어서 시작할 부분만 남겨두고, 5번 불러오기로 불러온 후 2번을 진행해도 된다.

 


[패치 노트]

  • V1.0
    • 블로그 주소가 'https://000.tistory.com/나는-오늘-좋았다' 형식이면 건너뜀 (https://000.tistory.com/420 형식만 가능)
    • 피드 리스트, 스토리 피드 리스트를 메모장으로 저장하고 불러오기 기능
    • 이미 구독된 블로그 건너뛰기
    • 댓글쓰기 및 공감 누르기 기능
    • 스킨마다 댓글 치환자가 달라서 지원이 되지 않을 수도 있다.
    • 댓글 캡차가 있으면 댓글이 안써진다.
  • V1.1
    • 'find_element_by_tag_name' 오류 수정

 

 

GitHub - limetimeline/Tistory-Macro-Bot

Contribute to limetimeline/Tistory-Macro-Bot development by creating an account on GitHub.

github.com

 

반응형
profile

Limetime's TimeLine

@Limetime

포스팅이 좋았다면 "공감❤️" 또는 "구독👍🏻" 해주세요!