개발/자동화

티스토리 좋아요 자동화(외부 라이브러리 설치) (#7)

kimchangmin02 2025. 7. 26. 06:20

똑같은 코드라도, 실행이 안될때가 있음

그건, 필요한 라이브러리 설치가 안됫기때문인데

 

이 라이브러리를 설치 햇는데도 실행이 안되는 경우가 있음

 

 

 

 

 

"파이썬 실행 환경 불일치" 문제입니다.

 

문제의 핵심 원인

터미널(CMD)에서 사용하는 파이썬과, 코드를 실행하는 프로그램(예: VS Code, Jupyter, PyCharm)이 사용하는 파이썬이 서로 다른 별개의 파이썬이기 때문입니다.

컴퓨터에는 여러 버전의 파이썬이 설치될 수 있습니다. (예: 시스템 기본 파이썬, 사용자가 따로 설치한 파이썬, Anaconda 파이썬, 가상환경의 파이썬 등)

현재 상황을 비유하자면 이렇습니다.

  1. 사용자: (터미널에서) "내 A 서랍(c:\python312\)에 webdriver-manager 책 좀 넣어줘."
  2. pip: "네, 이미 A 서랍에 그 책이 있습니다."
  3. 사용자: (코드 에디터에서) "자, 이제 코드를 실행해줘!"
  4. 코드 에디터: "알겠습니다. B 서랍에 있는 파이썬으로 실행할게요. 어? 그런데 B 서랍에는 webdriver-manager 책이 없네요. ModuleNotFoundError!"

즉, 터미널은 c:\python312라는 경로의 파이썬을 가리키고 있지만, 실제 코드를 실행하는 환경은 다른 곳에 설치된 파이썬을 사용하고 있는 것입니다.


해결 방법: 올바른 파이썬 환경에 라이브러리 설치하기

가장 확실한 해결책은 코드를 실행하는 바로 그 환경에 직접 라이브셔리를 설치하는 것입니다.

어떤 환경에서 코드를 실행하고 계신가요? 경우에 따라 해결 방법이 약간 다릅니다.

경우 1: Visual Studio Code (VS Code) 사용 시

VS Code는 현재 사용 중인 파이썬 환경(인터프리터)을 화면 하단에 표시해 줍니다.

  1. VS Code의 터미널을 사용하세요.
    • VS Code 상단 메뉴에서 터미널(Terminal) -> 새 터미널(New Terminal)을 엽니다.
    • VS Code 내장 터미널은 현재 선택된 파이썬 환경에 맞춰져 있을 확률이 높습니다.
    • 그 터미널에 아래 명령어를 다시 입력하고 실행합니다.
    Generated bash
    pip install webdriver-manager
    pip install selenium
     
    Use code with caution.Bash
  2. 파이썬 인터프리터를 직접 지정하여 설치
    • 화면 오른쪽 아래(또는 왼쪽 아래)에 Python 3.x.x와 같이 생긴 부분을 클릭합니다. 그러면 VS Code가 인식하고 있는 모든 파이썬 설치 경로 목록이 나타납니다.
    • 이 목록을 통해 현재 어떤 파이썬으로 코드를 실행하고 있는지 확인하고, 그 파이썬에 직접 모듈을 설치해야 합니다.
    • 가장 확실한 방법은 아래와 같이 -m 플래그를 사용하는 것입니다.
    Generated bash
    # 현재 VS Code가 사용하는 파이썬으로 pip를 실행하라는 뜻
    python -m pip install webdriver-manager
    python -m pip install selenium
     
    Use code with caution.Bash
    (만약 python 명령어가 안 되면 python3로 시도해보세요)

경우 2: Jupyter Notebook (Anaconda 또는 직접 설치) 사용 시

Jupyter Notebook/Lab은 자체 커널(실행 환경)을 사용합니다.

  • 코드 셀에서 직접 설치 명령을 실행하세요.
  • 가장 확실하고 간단한 방법입니다. 노트북의 코드 셀에 아래 코드를 입력하고 실행(Shift+Enter)하세요. !는 '이것은 파이썬 코드가 아니라 터미널 명령어다'라는 뜻입니다.Generated python
    !pip install webdriver-manager
    !pip install selenium
     
    Use code with caution.Python
  • 설치가 끝나면, 상단 메뉴에서 커널(Kernel) -> 커널 다시 시작(Restart Kernel)을 눌러 변경 사항을 적용한 후, 원래 코드 셀을 다시 실행합니다.

경우 3: PyCharm 사용 시

PyCharm은 프로젝트별로 가상환경을 만드는 것이 기본 설정입니다.

  1. PyCharm 하단의 Terminal 탭을 엽니다.
  2. 이 터미널은 현재 프로젝트의 파이썬 환경(가상환경일 가능성이 높음)에 자동으로 연결되어 있습니다.
  3. 여기에 pip install webdriver-manager를 입력하면 정확한 위치에 설치됩니다.

지금 바로 시도해볼 것

  1. 코드를 실행하고 있는 바로 그 프로그램(VS Code, Jupyter 등)에서 제공하는 터미널이나 코드 셀을 여세요.
  2. 아래 명령어를 입력하여 설치를 다시 시도하세요.Generated bash
    # (VS Code, PyCharm 터미널에서)
    pip install webdriver-manager

    # (Jupyter Notebook 코드 셀에서)
    !pip install webdriver-manager

 

 

 

 

 

 

즉, 그냥 cmd에 

이렇게 입력하면 안된다는 의미

 

이렇게 주피터 노트북의 셸안에 입력해야함

 

 

 

 

 

 

근데 이 프로그램 실행중에 다른 활동 해도 이 프로그램은 정상적으로 실행되는가

 

1. 영향을 주는 활동 (주의! 피해야 할 행동)

이 활동들은 자동화 스크립트의 실행을 방해하거나 오류를 발생시킬 수 있습니다.

  • 자동화 중인 브라우저 창을 직접 조작하는 행위:
    • Selenium이 제어하고 있는 크롬 창을 최소화하거나, 다른 창 뒤로 숨기거나, 창 크기를 조절하는 경우.
    • 해당 창에서 마우스로 다른 곳을 클릭하거나, 키보드로 무언가를 입력하는 행위.
    • 이런 행동은 절대 금물입니다. Selenium은 특정 요소의 좌표를 기준으로 클릭을 시도하는데, 창이 최소화되거나 다른 요소가 클릭을 가리면 ElementNotInteractableException (클릭할 수 없음) 같은 오류가 발생합니다.
  • 마우스 커서를 가져가는 행위:
    • 사용자님의 코드는 ActionChains를 사용해 마우스를 정교하게 움직입니다. 이때 사용자가 마우스를 직접 움직여 자동화 중인 브라우저 창 위에 올려두면, 스크립트의 마우스 이동을 방해하여 의도치 않은 요소 위로 마우스가 올라가거나 클릭에 실패할 수 있습니다.
  • 시스템 리소스를 많이 사용하는 다른 프로그램을 실행하는 경우:
    • 고화질 동영상 인코딩, 무거운 게임, 대용량 파일 복사 등 CPU나 메모리를 많이 사용하는 작업을 동시에 하면 컴퓨터가 전반적으로 느려집니다.
    • 이로 인해 웹페이지 로딩이 늦어져서 Selenium이 요소를 찾기 전에 타임아웃(TimeoutException)이 발생할 수 있습니다.

2. 영향을 주지 않는 활동 (안전한 행동)

자동화 스크립트에 거의 영향을 주지 않으므로 자유롭게 하셔도 됩니다.

  • 자동화 중인 브라우저 창을 건드리지 않고 다른 작업하기:
    • 가장 좋은 방법은 Selenium이 띄운 창은 그냥 화면 한쪽에 그대로 두고, 다른 모니터나 다른 공간에서 다른 작업을 하는 것입니다.
    • 다른 브라우저 창(Chrome, Edge 등)을 새로 열어서 웹 서핑하기.
    • 메모장, 워드, 엑셀 등 문서 작업하기.
    • 카카오톡 같은 메신저 사용하기.
    • 음악 듣기.

안전하게 멀티태스킹하는 팁

  1. "Headless" 모드 사용 (궁극의 해결책):
    • 나중에 더 안정적인 자동화를 원하신다면 "헤드리스 모드"를 사용해 보세요.
    • 이 모드는 화면에 브라우저 창을 아예 띄우지 않고 백그라운드에서 모든 작업을 처리합니다.
    • 사용자는 화면에 보이는 게 없으므로 실수로 건드릴 일이 전혀 없고, 컴퓨터 자원도 더 적게 사용합니다.
    • 설정 방법은 간단합니다. ChromeOptions에 아래 한 줄만 추가하면 됩니다.
    Generated python
    # ...
    chrome_options = webdriver.ChromeOptions()
    chrome_options.add_argument("--headless")  # 이 줄 추가
    chrome_options.add_argument("--window-size=1920,1080") # 헤드리스 모드에서는 창 크기를 지정해주는 것이 좋습니다.
    
    driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=chrome_options)
    # ...
     
    Use code with caution.Python
    • 단점: 눈으로 직접 진행 상황을 볼 수 없어 디버깅이 조금 더 어렵습니다. 코드가 완전히 안정화된 후에 적용하는 것을 추천합니다.
  2. 가상 데스크톱 사용 (Windows 기능):
    • Windows의 가상 데K스크톱 기능을 활용하는 것도 좋은 방법입니다.
    • Ctrl + Win + D 키를 눌러 새로운 가상 데스크톱을 만듭니다.
    • 그곳에서 자동화 스크립트를 실행하고, 원래 데스크톱(Ctrl + Win + ←/→ 로 전환)으로 돌아와 다른 작업을 하면 서로 방해하지 않습니다.

요약:

Selenium이 띄운 브라우저 창은 "신성불가침 영역"이라고 생각하시고, 그 창만 건드리지 않으면 다른 작업은 대부분 괜찮습니다.

가장 안전한 방법은 스크립트가 돌아가는 동안 다른 창에서 작업을 하거나, 나중에 headless 모드를 도입하는 것입니다.

 

 

 

 

 

 

a

주석처리된 break를 해제하면 무한 루프를 돌고

break가 있으면 한번만 실행되는 구조임

 

 

 

 

 

 

 

 

전체 코드는 다음과 같음

 

import time
import random
from selenium import webdriver
from seleniuhttp://m.webdriver.common.by import By
from seleniuhttp://m.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from seleniuhttp://m.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
from seleniuhttp://m.webdriver.common.action_chains import ActionChains

# --- [추가] 마우스 위치를 추적하고 출력하는 헬퍼 함수 ---

def setup_mouse_position_tracker(driver):
    """
    브라우저에 마우스 위치를 추적하는 JavaScript를 주입합니다.
    페이지가 로드된 후 한 번만 실행하면 됩니다.
    """
    js_mouse_tracker = """
    window.mousePos = { x: -1, y: -1 };
    document.addEventListener('mousemove', function(event) {
        window.mousePos = { x: event.clientX, y: event.clientY };
    });
    """
    driver.execute_script(js_mouse_tracker)
    # print("[좌표 추적기 설치 완료]")

def print_mouse_position(driver, message=""):
    """
    현재 기록된 마우스의 좌표를 가져와 출력합니다.
    """
    try:
        pos = driver.execute_script("return window.mousePos;")
        # print(f"    ㄴ [마우스 좌표 확인] {message}: X={pos['x']}, Y={pos['y']}")
    except Exception as e:
        # print(f"    ㄴ [마우스 좌표 확인 실패] {message}: {e}")
        pass

# --- 함수 정의 ---

def human_like_mouse_move_to_element(driver, element):
    """
    [좌표 출력 버전] 마우스 이동 전/후의 좌표를 출력하여 실제 이동 여부를 검증합니다.
    """
    # 1. 목표 요소를 화면 중앙으로 스크롤
    driver.execute_script("arguments[0].scrollIntoView({block: 'center', behavior: 'smooth'});", element)
    # print("목표('좋아요' 버튼)를 화면 중앙으로 스크롤했습니다.")
    time.sleep(random.uniform(0.8, 1.5))

    # print_mouse_position(driver, "이동 시작 전")

    # 2. 첫 번째 이동: 목표 요소 근처의 다른 곳으로 이동
    actions_step1 = ActionChains(driver)
    element_size = element.size
    offset_x = random.randint(int(element_size['width'] * 0.7), int(element_size['width'] * 1.5)) * random.choice([-1, 1])
    offset_y = random.randint(int(element_size['height'] * 0.7), int(element_size['height'] * 1.5)) * random.choice([-1, 1])
   
    actions_step1.move_to_element(element).move_by_offset(offset_x, offset_y).perform()
    # print(f"1단계: 목표 근처(오프셋: {offset_x}, {offset_y})로 마우스를 이동합니다.")
    # print_mouse_position(driver, "1단계 이동 직후")
    time.sleep(random.uniform(0.5, 1.0))

    # 3. 두 번째 이동: 최종적으로 목표 요소 위로 정확히 이동
    actions_step2 = ActionChains(driver)
    actions_step2.move_to_element(element).perform()
    # print("2단계: 목표물에 마우스를 정확히 위치시킵니다.")
    # print_mouse_position(driver, "2단계 이동 직후 (최종 위치)")
    time.sleep(random.uniform(0.3, 0.6))

    # print("마우스 이동 완료! 이제 클릭 준비가 되었습니다.")


# --- 메인 코드 ---
BASE_URL = "https://kimchangmin02.tistory.com"
TARGET_URLS = [f"{BASE_URL}/{i}" for i in range(1, 55)]
WAIT_TIMEOUT = 10

# print("진짜 최종 완성 버전! 자동 '좋아요' 로봇을 시작합니다. (좌표 추적 기능 포함)")
# print(f"총 {len(TARGET_URLS)}개의 게시물을 대상으로 작업을 반복합니다.")
# print("프로그램을 종료하려면 이 창에서 Ctrl + C 를 누르세요.")

while True:
    driver = None
    try:
        target_page = random.choice(TARGET_URLS)
        # print("\n--- 새로운 시도를 시작합니다 ---")
       
        chrome_options = webdriver.ChromeOptions()
        driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=chrome_options)
        wait = WebDriverWait(driver, WAIT_TIMEOUT)
       
        driver.get(target_page)
        # print(f"'{target_page}' 페이지로 이동했습니다.")
       
        # [중요] 페이지가 로드된 후, 마우스 좌표 추적기를 설치합니다.
        setup_mouse_position_tracker(driver)
       
        scroll_time = random.uniform(1.5, 4.0)
        # print(f"사람처럼 행동하기 위해 {scroll_time:.2f}초 동안 페이지를 스크롤합니다...")
        driver.execute_script(f"window.scrollTo(0, document.body.scrollHeight * 0.3);")
        time.sleep(scroll_time)

        like_button_selector = "div[id^='reaction-'] button.btn_post"
        # print(f"CSS 선택자: '{like_button_selector}' 를 사용하여 '좋아요' 버튼을 찾습니다...")
        like_button = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, like_button_selector)))
        # print("성공: '좋아요' 버튼을 찾았습니다.")

        human_like_mouse_move_to_element(driver, like_button)
       
        like_button.click()
        # print("성공: '좋아요' 버튼을 확실하게 클릭했습니다.")
       
        time.sleep(random.uniform(0.5, 1.0))

        # print("클릭 완료! 마우스 커서를 다른 곳으로 치웁니다...")
        actions = ActionChains(driver)
        body_element = driver.find_element(By.TAG_NAME, 'body')
        actions.move_to_element_with_offset(body_element, 5, 5).perform()
        # print("마우스 커서를 안전한 위치로 이동했습니다.")
        # print_mouse_position(driver, "마지막 커서 이동 후")

        viewing_time = random.uniform(2, 5)
        # print(f"작업 완료! {viewing_time:.2f}초 더 머문 뒤 브라우저를 닫습니다.")
        time.sleep(viewing_time)

    except Exception as e:
        # print(f"실패: 작업 중 오류가 발생했습니다 - {e}")
        import traceback
        # traceback.print_exc() # 오류의 상세 내용을 출력합니다.
        error_sleep_time = random.uniform(5, 10)
        # print(f"오류 발생으로 인해 {error_sleep_time:.2f}초 대기합니다.")
        time.sleep(error_sleep_time)

    finally:
        if driver:
            # print("브라우저를 종료합니다.")
            driver.quit()

    #break

    break_time = random.uniform(10, 25)
    # print(f"\n다음 시도를 위해 {break_time:.2f}초간 충분히 휴식합니다...")
    time.sleep(break_time)