티스토리 뷰

반응형

 

 

공식 API의 한계와 웹 요청의 필요성

 

 

[Python] 네이버 카페 API 없이 requests로 댓글 남기기 ✨ (댓글편)

 

🔎 들어가며

 

네이버 카페는 개인·비즈니스용 커뮤니티로 여전히 활용도가 높다.  

공식 API는 제공 기능이 제한적이라 실무에서는 직접 웹 요청으로 해결해야 할 때 많다.  

기술은 도구다. 자동화로 반복 작업을 줄이면 더 가치 있는 일에 집중할 수 있다.

 

 

 

목표 및 전제 조건
구현 흐름 요약

 

 

 

 

🧭 목표와 전제 조건

 

이 글은 셀레니움으로 로그인해 쿠키를 얻고, 그 쿠키를 requests에 넘겨 댓글을 작성하는 방법을 다룬다.  

네이버 로그인 과정에서 2단계 인증이나 캡차가 발생하면 자동화가 차단될 수 있다.  

서비스 약관을 준수해야 하며, 상업적 과다 자동화는 계정 정지 위험이 있다.

 

💡 전체 흐름 요약

 

1. 셀레니움으로 네이버 로그인 후 쿠키를 획득한다.  

2. requests 세션으로 카페 페이지를 요청해 카페ID를 추출한다.  

3. 댓글 작성용 API 엔드포인트로 POST 요청을 보낸다.  

아래 예제 코드는 위 단계를 하나의 클래스에 담아 재사용하기 쉽게 구성했다.

 

 

 

필요 라이브러리 및 준비물  
크롬 드라이버 설치 및 환경 설정  
카페 자동화 클래스 구조 소개  
네이버 로그인 자동화 흐름  
쿠키 획득 및 예외 처리  
카페 ID 추출(cafeid) 메서드  
댓글 작성 요청(comment) 메서드

 

 

 

 

🛠️ 준비물

 

필요 라이브러리: selenium, requests, pyperclip  

크롬 드라이버가 시스템에 설치되어 있어야 한다.  

파이썬 환경에서 pip로 설치하면 된다.

 

코드(실행 예시)

 

from selenium import webdriver

from selenium.webdriver.chrome.service import Service

from selenium.webdriver.chrome.options import Options

from selenium.webdriver.support.ui import WebDriverWait

from selenium.webdriver.support import expected_conditions as EC

from selenium.webdriver import ActionChains, Keys

from selenium.webdriver.common.by import By

 

import pyperclip, time, requests

 

class cafe():

    def __init__(self, id, pw):

        self.id = id

        self.pw = pw

        self.chrome_options = Options()

        self.chrome_options.add_argument("lang=ko_KR")

        self.chrome_options.add_argument('no-sandbox')

        self.chrome_options.add_argument('disable-gpu')

        self.chrome_options.add_argument("disable-dev-shm-usage")

        self.chrome_options.add_argument('window-size=1920,1080')

        self.chrome_options.add_argument("--log-level=3")

        self.chrome_options.add_experimental_option('excludeSwitches', ['enable-logging'])

        self.chrome_options.add_argument("--disable-3d-apis")

        self.driver = webdriver.Chrome(service=Service(), options=self.chrome_options)

 

    def login(self):

        driver = self.driver

        driver.get("https://nid.naver.com/nidlogin.login?url=https%3A%2F%2Fkin.naver.com%2F")

        id = self.id

        pw = self.pw

 

        WebDriverWait(driver, 5).until(

            EC.presence_of_element_located((By.ID, "id"))

        ).click()

        a = pyperclip.paste()

        pyperclip.copy(id)

        actions = ActionChains(driver)

        actions.key_down(Keys.CONTROL).send_keys('v').key_up(Keys.CONTROL).perform()

        time.sleep(1)

 

        WebDriverWait(driver, 5).until(

            EC.presence_of_element_located((By.ID, "pw"))

        ).click()

 

        a = pyperclip.paste()

        pyperclip.copy(pw)

        actions = ActionChains(driver)

        actions.key_down(Keys.CONTROL).send_keys('v').key_up(Keys.CONTROL).perform()

        time.sleep(1)

        pyperclip.copy(a)

 

        WebDriverWait(driver, 5).until(

            EC.presence_of_element_located((By.ID, "log.login"))

        ).click()

 

        try:

            WebDriverWait(driver, 3).until(

                EC.presence_of_element_located((By.XPATH, "/html/body/div[2]/div[2]/div[3]/div/a"))

            )

            self.cookie = {cookie['name']: cookie['value'] for cookie in driver.get_cookies()}

            driver.quit()

            return self.cookie

        except:

            self.cookie = None

            driver.quit()

            return None

 

    def cafeid(self, url):

        a = requests.get(url=url, cookies=self.cookie)

        return a.text.split('var g_sClubId = "')[1].split('"')[0]

 

    def comment(self, txt, urls, article_id):

        url = 'https://apis.naver.com/cafe-web/cafe-mobile/CommentPost.json'

        data = {

            'content': txt,

            'stickerId': '',

            'cafeId': self.cafeid(urls),

            'articleId': article_id,

            'requestFrom': 'A'

        }

        header = {

            'Content-Type': 'application/x-www-form-urlencoded',

            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)'

        }

        a = requests.post(url=url, headers=header, data=data, cookies=self.cookie)

        data = a.json()

        print(data.get('commentId'), data.get('refCommentId'))

 

 

 

 

실행 예시: 로그인 후 댓글 등록
동작 원리 및 핵심 포인트
주의사항 및 자동화 위험 요인

 

 

 

 

사용 예시

 

cafes = cafe('네이버ID','네이버PW')

result = cafes.login()

if result is not None:

    cafes.comment('테스트 댓글입니다', 'https://cafe.naver.com/카페명', '게시물번호')

 

🔍 코드 설명 및 핵심 포인트

 

셀레니움으로 로그인 후 쿠키를 dict로 저장한다.  

쿠키를 requests의 cookies 파라미터로 전달하면, 같은 세션처럼 동작한다.  

카페ID는 카페 메인 페이지 소스의 var g_sClubId 값에서 추출한다.  

댓글 API는 브라우저 개발자도구 네트워크에서 확인한 엔드포인트를 그대로 사용한다.  

articleId는 게시물 고유 번호로, 게시물 URL에서 얻거나 브라우저에서 네트워크 로그를 통해 확인한다.

 

⚠️ 주의사항 및 장애요인

 

네이버는 비정상적 요청을 탐지하면 추가 인증을 요구한다.  

2단계 인증이나 OTP, 캡차는 자동화에 큰 장애가 된다.  

과도한 자동화는 계정 정지로 이어질 수 있으니 사용량을 조절한다.  

서비스 약관을 확인하고, 타인 권한으로 자동화하지 않는다.

 

 

 

안정성·성능을 위한 확장 아이디어
셀레니움 없이 requests만으로 가능한지
게시물 번호(articleId) 확인 방법
자동화 차단 복구 및 예방책
결론 및 실천 포인트
공감 요청

 

 

 

 

🔧 확장 아이디어

 

세션 유지: requests.Session을 활용해 헤더·쿠키를 지속 관리한다.  

재시도 로직: 요청 실패 시 exponential backoff로 재시도한다.  

멀티 스레드: 게시글 다수를 대상으로 할 때 스레드 풀로 처리 속도를 높인다.  

정책 탐지 대응: 실패 패턴을 로깅해 차단 원인 분석에 활용한다.

 

❓Q&A

 

Q. 셀레니움 없이 pure requests만으로는 불가능한가요?  

A. 로그인 과정에서 자바스크립트 연동, 로그인 토큰 생성, 캡차 등이 있어 대부분 사이트는 셀레니움이 필요하다. 네이버는 세션 토큰을 JS에서 생성하므로 셀레니움으로 쿠키를 얻는 방법이 가장 안정적이다.

 

Q. 게시물 번호(articleId)는 어떻게 얻나요?  

A. 게시물 URL에 포함된 파라미터로 확인하거나, 게시물 페이지의 소스 또는 브라우저 개발자도구 네트워크 탭에서 POST/GET 요청을 분석해 확인한다.

 

Q. 자동화 도중 차단되면 어떻게 복구하나요?  

A. 우선 해당 계정으로 직접 로그인해 차단 메시지를 확인한다. 차단이 심하면 고객센터 문의가 필요하다. 자동화 주기와 패턴을 수정해 재발 방지 대책을 마련한다.

 

 

 

🧾 결론 및 실천 포인트

 

셀레니움으로 로그인해 쿠키를 가져오고, requests로 댓글 API를 호출하면 빠르고 간단하게 댓글 자동화를 구현할 수 있다.  

항상 적절한 요청 속도와 예외 처리를 넣어 안정성을 확보한다.  

법적·서비스 정책을 준수하며, 자동화로 얻은 시간은 더 가치 있는 일에 투자하자.

 

 

공감하셨다면 하트 꾹 눌러주세요

 

#파이썬 #네이버카페 #requests #셀레니움 #댓글자동화 #웹스크래핑 #자동화스크립트 #Python #네이버로그인 #쿠키활용 #웹요청 #크롤링 #카페댓글 #API우회 #개발팁

 

 

 

반응형