IT·개발

Python Selenium 네이버 로그인 우회 3가지 — 2026년 Selenium 4 가이드

5월 16, 2026 3 min read

2021년 1월, Selenium을 막 배우기 시작하던 시기에 외부 블로그(cceeddcc.tistory.com/98)를 참고해 정리해 뒀던 학습 노트다. 네이버 로그인 폼에 자동 입력을 시도하면서 막히고 우회하는 과정을 단계별로 메모해 둔 것으로, 본 포스팅 하단에 원 출처 링크를 달아 두었다.

그 전에 한 가지 짚고 넘어가면,

⚠️ 약관 주의: 이 글은 Selenium 동작 원리를 이해하기 위한 학습 목적의 메모다. 네이버를 포함한 대부분의 포털은 자동 로그인·크롤링을 이용약관에서 제한하고 있다. 본 코드를 실서비스 자동화에 그대로 적용하는 것은 약관 위반 소지가 있으니 삼가야 한다.


준비 — Selenium 핵심 함수 참고표

Selenium으로 브라우저를 제어할 때 기본이 되는 함수들을 먼저 표로 정리해 뒀다.

함수설명
webdriver.Chrome("c:/...")chromedriver 경로 지정 후 사용
implicitly_wait(3)웹 페이지 로드를 위해 3초 대기
get(url)url에 접근
page_source현재 렌더링된 페이지의 Elements를 모두 가져오기
find_element_by_name('...')name 속성으로 단일 element 접근
find_element_by_id('...')id로 접근
find_element_by_xpath('...')xpath로 접근
find_element_by_css_selector('...')css selector로 접근
find_element_by_class_name('...')class 이름으로 접근
find_element_by_tag_name('...')tag 이름으로 접근

요소를 어떻게 찾느냐는 HTML 구조에 따라 달라진다. 고유한 id가 있으면 find_element_by_id가 가장 간결하고, 동적으로 생성되는 요소라면 xpathcss_selector 쪽이 유연하다. classtag는 여러 요소가 같은 값을 공유하는 경우가 많아 단일 요소를 특정할 때는 주의가 필요하다.

[2026 메모]find_element_by_* 시리즈는 Selenium 4.0부터 deprecation warning이 발생하며, 향후 버전에서 완전 제거 예정이다. 새 코드 작성 시에는 find_element(By.ID, '...') 형태를 쓰는 것이 권장된다. 자세한 내용은 2026년 회고 메모에서 다룬다.


방법 1 — send_keys로 직접 입력 (현재 차단됨)

가장 직관적인 접근은 find_element_by_id로 폼 요소를 잡고 send_keys()로 값을 바로 집어넣는 방식이다.

# 2021년 원본 환경: pip install selenium==3.141.0 beautifulsoup4==4.9.3
# 2026년 현재 권장: pip install "selenium>=4.0" "beautifulsoup4>=4.9.3" (§회고 참조)
from selenium import webdriver
from bs4 import BeautifulSoup as bs
import time

# chromedriver의 위치 지정
driver = webdriver.Chrome("c:/Users/학습러/Desktop/chromedriver_win32/chromedriver.exe")

login_url = "https://nid.naver.com/nidlogin.login"
driver.get(login_url)

driver.find_element_by_id("id").send_keys('my_id')  # id 넣기
driver.find_element_by_id("pw").send_keys('my_pw')  # password 넣기

# 로그인 클릭
driver.find_element_by_xpath('//*[@id="frmNIDLogin"]/fieldset/input').click()

time.sleep(2)
driver.close()

## 2019/02/20 기준 send_keys 함수 사용하면
## 네이버가 자동화된 소프트 웨어라 판단하고 막아놓음

원문 주석: “2019/02/20 기준 send_keys 함수 사용하면 네이버가 자동화된 소프트 웨어라 판단하고 막아놓음”

원문에 따르면 이 방식은 맨 처음 한 번만 통과 가능한 상태였고, 이후로는 막혔다. send_keys()는 키보드 입력 이벤트를 직접 발생시키는 방식으로 동작하기 때문에 사람의 타이핑 패턴과 달리 자동화 소프트웨어로 판단된다는 것이 원문 주석의 설명이다.


방법 2 — pyperclip 클립보드 붙여넣기 우회

send_keys()가 막히는 이유가 키 입력 패턴 탐지라면, 실제 타이핑 대신 OS 클립보드 붙여넣기 이벤트를 활용하는 방식이 대안이 된다. pyperclip으로 ID와 비밀번호를 클립보드에 복사한 뒤 ActionChains로 Ctrl+V(Mac에서는 Cmd+V)를 전송하면, 브라우저 입장에서는 OS 수준의 붙여넣기 이벤트로 인식되어 키 입력 탐지를 비껴가는 원리다.

아래 코드는 방법 1에서 초기화한 driverlogin_url 변수를 이어받는다. 방법 1 코드 다음에 연결해서 사용하면 된다. 원문 코드에서는 url로 표기되어 있으나, 방법 1의 login_url("https://nid.naver.com/nidlogin.login")과 동일한 값을 가리킨다.

# 추가 설치: pip install "pyperclip>=1.8.2"
import time
import random
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.keys import Keys
import pyperclip

userid = 'my_id'
userpw = 'my_pw'

# 클립보드에 input을 복사한 뒤 해당 내용을 actionChain을 이용해 로그인 폼에 붙여넣기
def copy_input(xpath, input):
    pyperclip.copy(input)
    driver.find_element_by_xpath(xpath).click()
    # ActionChains(driver).key_down(Keys.CONTROL).send_keys('v').key_up(Keys.CONTROL).perform() # win linux
    ActionChains(driver).key_down(Keys.COMMAND).send_keys('v').key_up(Keys.COMMAND).perform() # mac
    time.sleep(random.uniform(0,3))

def naver_log_in(id, pw) :
    driver.get(login_url)  # login_url = "https://nid.naver.com/nidlogin.login"
    driver.implicitly_wait(10)
    time.sleep(random.uniform(1,2))

    copy_input('//*[@id="id"]', id)
    time.sleep(random.uniform(1,2))

    copy_input('//*[@id="pw"]', pw)
    time.sleep(random.uniform(1,2))

    driver.find_element_by_xpath('//*[@id="frmNIDLogin"]/fieldset/input').click()
    time.sleep(3)


naver_log_in(userid, userpw)

코드를 보면 random.uniform(0,3)·random.uniform(1,2) 같이 대기 시간을 무작위로 흩어 놓아 일정한 리듬이 없도록 했다. 키 분기는 Windows·Linux에서는 Keys.CONTROL, macOS에서는 Keys.COMMAND를 쓰며, 코드 주석에 두 케이스가 모두 적혀 있다. 원문에서 명시했듯 “linux에서 사용하기 까다롭다”는 한계가 있어 크로스플랫폼 환경이라면 미리 고려해야 한다.

userid, userpw 같은 자격 증명을 코드에 하드코딩하면 유출 위험이 있다. 나도 이때 메모하면서 그냥 하드코딩했는데, 나중에 돌아보니 학습 환경에서도 환경변수로 빼두는 게 맞더라.

클립보드 방식도 결국 OS 의존성이라는 벽이 있었다. 이 한계를 넘으려고 찾아낸 세 번째 방법이 파이썬 레이어를 아예 건너뛰고, 브라우저 내부에서 직접 값을 세팅하는 방식이었다.


방법 3 — execute_script로 JavaScript 직접 주입

파이썬 레이어에서 키를 보내는 방식이 탐지된다면, 브라우저 내부에서 값을 세팅하는 방법이 있다.

아래 코드는 방법 2의 copy_input() 호출 부분을 대체하는 스니펫이다. driver, id, pw는 방법 1·2에서 초기화·전달한 변수를 그대로 사용한다.

# execute_script 함수 사용 (자바스크립트로 아이디, 패스워드를 넘겨주는 형태)
driver.execute_script("document.getElementsByName('id')[0].value=\'"+id+"\'")
driver.execute_script("document.getElementsByName('pw')[0].value=\'"+pw+"\'")

driver.find_element_by_xpath('//*[@id="frmNIDLogin"]/fieldset/input').click()

원문 설명 그대로 옮기면, “파이썬에서 키를 직접 넘겨주는 게 아니라 브라우저 내에서 자바스크립트로 아이디 값을 넘겨주기 때문에 네이버의 자동화된 소프트와 알고리즘을 우회하는 원리”다. execute_scriptinput 요소의 value 속성을 JS 컨텍스트 안에서 직접 세팅하므로, Selenium의 키 입력 레이어를 아예 건너뛰는 구조다.

단, 단순 value 변경만으로 폼 유효성 로직이 활성화되지 않는 경우가 있다. React·Vue 등 SPA 기반 폼은 DOM 속성 변경과 상태 관리가 별도로 동작하는 구조라 이 방식이 동작하지 않을 수 있다. 이는 SPA 폼 전반에 대한 일반론이며, 특정 서비스의 동작을 단정하는 것은 아니다.


2026년 시점 회고 메모

이 메모를 처음 정리한 지 5년이 지났다. 지금 시점에서 세 가지를 덧붙여 둔다.

Selenium 4 이후 API 변경

본문에 등장하는 find_element_by_id(), find_element_by_xpath()find_element_by_* 시리즈는 Selenium 4.0부터 deprecation warning이 발생하며, 향후 버전에서 완전 제거 예정이다. 공식 마이그레이션 가이드(Selenium 공식 문서 — Upgrade to Selenium 4)에서는 from selenium.webdriver.common.by import By를 임포트한 뒤 find_element(By.ID, '...'), find_element(By.XPATH, '...') 형태로 작성하도록 권장한다. 2021년 코드를 현재 환경에서 그대로 실행하면 DeprecationWarning이 뜨거나 오류가 발생할 수 있다.

보안 강화

포털 로그인 보안은 그 사이 CAPTCHA 고도화·디바이스 핑거프린팅 등으로 훨씬 까다로워졌다. 본 메모에서 소개한 우회 원리가 지금도 동일하게 통한다고 단정할 수 없다.

약관 문제

자동 로그인은 서비스 이용약관 위반 소지가 크다. 학습·원리 이해를 넘어 실서비스 연동이 필요한 상황이라면, 지금이라면 공식 OpenAPI부터 먼저 찾아볼 것 같다.


출처: cceeddcc.tistory.com/98