본문 바로가기
파이썬

네이버 블로그 자동화 2 : 이웃글 공감 누르기(2023.10.29. 업데이트)

by fecu 2023. 1. 25.
728x90

네이버 블로그에서 블로거들 끼리의 소통과 서로 이웃은 무척 중요한 요소이다. 그래서 저번 글에 이어 네이버 블로그 자동화를 위한 이웃글 공감 누르기를 만들어본다.

 

네이버 블로그 자동화 1 : 최신글 공감 누르기

최근 티스토리가 터진 후 네이버 블로그에 관심이 옮겨가면서, 네이버 블로그의 좋아요도 한번 자동화 시키면 어떨까 하는 생각이 들었다. 검색을 해보니 네이버는 체류시간이 너무 짧을 경우

fecu.tistory.com


2023.02.01~09.20. 업데이트

창의 크기에 따른 스크롤의 안정성을 위해 now_scroll_height 변수에 200을 더해 현재 창의 스크롤 위치를 구하도록 만듦. 이웃의 수가 너무 많아 스크롤이 끝없이 반복되는 경우를 제한하기 위해, 로딩하는 피드의 최대 개수의 제한을 둠.

셀레니움 업데이트에 따른 함수 변경 및 함수명 수정. 스크롤 함수 일부 수정. 더블하트를 인식하지 않는 문제를 수정. contains를 이용하여 하트를 찾도록 만듦.

 

2023.10.29. 업데이트

일부 xpath 최신화


1. 이웃 새글 페이지 스크롤

 

먼저 이웃 새글 리스트를 보기 위해 주소를 알아보니 아래와 같다. driver.get을 통해 해당 주소로 접속한다.

 

 

그리고 이전 글에서 썼던 scroll 함수를 활용하여 아래와 같이 스크롤을 해준다. 해당 코드를 활용하면 스크롤을 할 수 있는 끝까지 스크롤을 하고 이웃의 새글을 로딩한다.

 

driver.get("https://m.blog.naver.com/FeedList.naver")
time.sleep(random.uniform(2, 5))
def scrollEndPosition():
    document_height = int(driver.execute_script("return document.body.scrollHeight"))
    now_scroll_height = int(driver.execute_script("return window.scrollY + window.innerHeight"))
    if now_scroll_height >= (document_height*9/10):
        return False
    else : 
        return True
    
SCROLL_PAUSE_TIME = 0.5

while scrollEndPosition():
    driver.find_element(By.XPATH, "//body").send_keys(Keys.PAGE_DOWN)
    time.sleep(SCROLL_PAUSE_TIME)

 

2. 이웃 새글 URL 추출

 

이웃의 글에서 제목을 활용하여 URL을 추출했다. 이웃 새글의 제목의 xpath는 아래와 같았다.

 

 

find_elements를 이용해 이웃 새글의 제목 <a>태그를 담고 for문을 통해 url을 neighborUrls에 담았다.

 

neighborBlogs = driver.find_elements(By.XPATH, "//div/ul/li//div[@class ='text_area___UrFH']//a")
neighborUrls = []
for neighborBlog in neighborBlogs:
    neighborUrls.append(neighborBlog.get_attribute('href'))

 

3. URL 접속 및 좋아요 누르기

 

여기서 부터는 이전글과 완전히 동일하다. 정의했던 함수(openBlog, closeBlog, availableLike, clickLike)를 활용하여 URL을 새창에서 열고, 좋아요를 누를 수 있는 글인지 판별한 후 좋아요를 누르고 창을 닫는다.

 

def openBlog(url):
    driver.execute_script(f"window.open('{url}');")
    driver.switch_to.window(driver.window_handles[1])

openBlog(neighborUrls[2])

def closeBlog():
    driver.close()
    driver.switch_to.window(driver.window_handles[0])

def availableLike():
    try : 
        confirmlike = driver.find_element(By.XPATH, "//*[@id='body']/div[10]/div/div[1]/div/div/a").get_attribute("class").split(" ")[-1]
        if confirmlike == "on" :
            print(f'이미 좋아요 누른 게시물')
            return False
        elif confirmlike == "off" : 
            return True
    except Exception as e: 
        print(e)
        print('좋아요가 제한된 게시물')
        return False

def clickLike():
    SCROLL_PAUSE_TIME = 0.5
    while scrollEndPosition():
        driver.find_element(By.XPATH, "//body").send_keys(Keys.PAGE_DOWN)
        time.sleep(SCROLL_PAUSE_TIME)
    
    like_btn = driver.find_element(By.XPATH, "//div[@class='btn_like']/div")
    driver.execute_script("arguments[0].scrollIntoView({block : 'center'});", like_btn)
    like_btn.click()
    print(f"블로그 좋아요 누름")
    closeBlog()

if availableLike() :
    clickLike()
else : 
    closeBlog()

 

이제 남은건 이것을 for 문을 통해 모두 클릭해주는것 뿐이다.

 

4. 순서도

 

이웃 새글의 url을 추출하는 함수를 neighborNewFeed()라고 이름지어 보아다. 재미있게도 이전의 코드를 잘 짜놓았더니 중간 과정만 바꾸면 다음 과정은 모두 같다. 바뀐 것은 추출한 url 뿐이다.

 

 

5. 전체코드

 

이번에는 이웃의 블로그 공감을 누르기 위한 코드를 짜 보았다. 유용하게 쓰길 바란다.

 

from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
import pyperclip as pp
import time
from random import uniform, randrange, shuffle

#자신의 아이디, 비밀번호
yourid : str = "자신의 아이디"
yourpassword : str = "자신의 비밀번호"

# 좋아요를 누르기 전 스크롤을 할 때 스크롤 최소, 최대 시간
scrollMinPauseTime : float = 0.5
scrollMaxPauseTime : float = 5.0

# 원하는 태그 목록
searchWords : list = ["원하는","태그","입력"]

# 태그 순서 섞기
shuffle(searchWords)

# 각 태그당 좋아요를 누를 최소, 최대 개수
tagMinNum : int = 40
tagMaxNum : int = 60

#좋아요 누른 개수, 다음 태그로 넘어가는 개수
clickedLikeNum : int = 0
stopTagNum : int = 0

# 이웃 블로그 최대 수(이웃이 많을 경우 스크롤 제한하기)
maxneighbornum = 50

options = webdriver.ChromeOptions()
options.add_experimental_option('excludeSwitches', ['enable-logging'])
options.add_argument('--no-sandbox')
options.add_argument("disable-gpu")
# options.add_argument('headless')
options.add_argument('window-size=1920x1080')
options.add_argument("user-agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36")
driver = webdriver.Chrome(options=options)

def inputkeys(someWord : str, placeholder : str):
    pp.copy(someWord)
    holderInput = driver.find_element(By.XPATH, f"//input[@placeholder='{placeholder}']")
    holderInput.click()
    pp.copy(someWord)
    time.sleep(uniform(3.0, 10.0))
    
    # 윈도우 환경에서 붙여넣기
    # idInput.send_keys(Keys.CONTROL, 'v')
    
    # 맥 환경에서 붙여넣기
    holderInput.send_keys(Keys.COMMAND, 'v')
    
def login(naverid : str, naverpassword : str):
    driver.get("https://nid.naver.com/nidlogin.login?svctype=262144&url=http://m.naver.com/aside/")    
    inputkeys(naverid, "아이디")
    inputkeys(naverpassword, "비밀번호")
    driver.find_element(By.XPATH, f"//input[@placeholder='비밀번호']").send_keys(Keys.ENTER)
    time.sleep(2)

def scrollEndPosition():
    document_height = int(driver.execute_script("return document.body.scrollHeight"))
    now_scroll_height = int(driver.execute_script("return window.scrollY + window.innerHeight"))
    if now_scroll_height >= (document_height*9/10):
        return False
    else : 
        return True
    
def searchBlog(searchWord : str, articleLimit : int):
    adress = "https://m.search.naver.com/search.naver?where=m_blog&query="+searchWord+"&nso=so%3Add%2Cp%3Aall"
    driver.get(adress)
    driver.implicitly_wait(10)
    articles = driver.find_elements(By.XPATH, "//div[@class='title_area']/a")
    numOfArticles = len(articles)
    SCROLL_PAUSE_TIME = 1
    while numOfArticles < articleLimit :
        driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
        time.sleep(SCROLL_PAUSE_TIME)
        articles = driver.find_elements(By.XPATH, "//div[@class='title_area']/a")
        numOfArticles = len(driver.find_elements(By.XPATH, "//div[@class='title_area']/a"))
    
    articles = driver.find_elements(By.XPATH, "//div[@class='title_area']/a")
    numOfArticles = len(articles)
    urls = []
    for i in range(numOfArticles):
        url = str(articles[i].get_attribute("href"))
        urls.append(url)
    return urls

def openBlog(url):
    driver.execute_script(f"window.open('{url}');")
    driver.switch_to.window(driver.window_handles[1])

def closeBlog():
    driver.close()
    driver.switch_to.window(driver.window_handles[0])

def availableLike():
    global stopTagNum
    try : 
        confirmlike = driver.find_element(By.XPATH, "//*[@id='body']/div[10]/div/div[1]/div/div/a").get_attribute("class").split(" ")
        if "on" in confirmlike :
            stopTagNum += 1
            print(f'이미 좋아요 누른 게시물 {stopTagNum}개')
            return False
        elif "off" in confirmlike : 
            return True
    except Exception as e: 
        print(e)
        print('좋아요가 제한된 게시물')
        return False
    
def clickLike():
    while scrollEndPosition():
        driver.find_element(By.XPATH, "//body").send_keys(Keys.PAGE_DOWN)
        time.sleep(uniform(scrollMinPauseTime, scrollMaxPauseTime))
    
    like_btn = driver.find_element(By.XPATH, "//div[@class='btn_like']/div")
    driver.execute_script("arguments[0].scrollIntoView({block : 'center'});", like_btn)
    like_btn.click()
    global clickedLikeNum
    clickedLikeNum += 1
    print(f"블로그 좋아요를 {clickedLikeNum}개 누름")
    closeBlog()
    
def neighborNewFeed(maxnum : int):
    driver.get("https://m.blog.naver.com/FeedList.naver")
    time.sleep(uniform(6, 15))
    unliked_blog_xpath = "//div/ul/li//a[contains(@class,'u_likeit_list_btn _button off')]/ancestor::div[5]//div[@class ='text_area___UrFH']//a"
    neighborBlogs = driver.find_elements(By.XPATH, unliked_blog_xpath)   
    numOfneighborblogs = len(neighborBlogs)
    
    SCROLL_PAUSE_TIME = 2
    while numOfneighborblogs < maxnum :
        driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
        time.sleep(SCROLL_PAUSE_TIME)
        neighborBlogs = driver.find_elements(By.XPATH, unliked_blog_xpath)
        numOfneighborblogs = len(neighborBlogs)
        if scrollEndPosition() == False:
            break
    print(numOfneighborblogs)
    neighborUrls = []
    for neighborBlog in neighborBlogs:
        neighborUrls.append(neighborBlog.get_attribute('href'))
    return neighborUrls

login(yourid, yourpassword)
            
urls = neighborNewFeed(maxneighbornum)

# 이웃 새글 공감 누르기
for url in urls:
    openBlog(url)
    # 블로그 페이지 로딩을 위한 시간
    time.sleep(uniform(5.0, 10.0))
        
    # 좋아요가 클릭 가능한지 확인 후 클릭, 아니면 창 닫기 
    if availableLike() :
        clickLike()
    else : 
        closeBlog()
        
# # 설정한 태그 공감 누르기
# for searchWord in searchWords :
#     urls = searchBlog(searchWord, randrange(tagMinNum, tagMaxNum))
#     for url in urls:
#         openBlog(url)
#         # 블로그 페이지 로딩을 위한 시간
#         time.sleep(uniform(3.0, 7.0))
        
#        # 좋아요가 클릭 가능한지 확인 후 클릭, 아니면 창 닫기 
#         if availableLike() :
#             clickLike()
#         else : 
#             closeBlog()
            
driver.quit()
728x90