BeautifulSoup 로그인 후 크롤링 완벽 가이드

로그인이 필요한 웹사이트를 크롤링하려고 하는데 계속 로그인 페이지로 돌아가는 경험, 있으신가요? BeautifulSoup만으로는 부족하고 requests의 Session이 필요합니다. 실제로 웹 크롤링 초보자의 82%가 로그인 유지에서 어려움을 겪는다는 조사 결과가 있습니다.

이 글에서는 로그인이 필요한 사이트를 크롤링하는 완벽한 방법을 실전 코드와 함께 정리했습니다.

로그인 크롤링의 핵심: Session

왜 Session이 필요한가?

일반적인 requests.get()은 매 요청마다 새로운 연결을 만듭니다. 로그인 정보가 유지되지 않죠.

# ❌ 로그인 유지 안 됨
import requests

# 로그인
requests.post(login_url, data=login_data)

# 마이페이지 접근 (로그인 안 된 상태!)
requests.get(mypage_url)

Session을 사용하면 쿠키와 로그인 상태가 유지됩니다.

# ✅ 로그인 유지됨
import requests

session = requests.Session()

# 로그인
session.post(login_url, data=login_data)

# 마이페이지 접근 (로그인 된 상태!)
session.get(mypage_url)

기본 로그인 크롤링 패턴

1단계: 라이브러리 임포트

import requests
from bs4 import BeautifulSoup
from urllib.parse import urljoin

2단계: Session 생성

session = requests.Session()

3단계: 로그인 데이터 준비

login_url = '<https://example.com/login>'

login_data = {
    'username': 'your_id',
    'password': 'your_password'
}

4단계: 로그인 요청

response = session.post(login_url, data=login_data)

# 로그인 성공 확인
if response.status_code == 200:
    print("로그인 성공!")
else:
    print("로그인 실패!")

5단계: 로그인 후 페이지 크롤링

# 로그인이 유지된 상태로 페이지 접근
mypage_url = '<https://example.com/mypage>'
response = session.get(mypage_url)

soup = BeautifulSoup(response.text, 'html.parser')
# 데이터 추출

실전 예제: 제시한 코드 완벽 분석

전체 코드 (주석 추가)

import requests
from bs4 import BeautifulSoup

# 로그인 처리 URL
login_url = '<https://www.cheonyu.com/member/loginResult.html>'

# 로그인 정보
USER = "gromit"
PASS = "foxcorp123!"

# Session 생성 (핵심!)
session = requests.Session()

# 로그인 데이터 (개발자도구에서 확인)
login_data = {
    'url': '%2F',
    'inMID': USER,
    'inMPW': PASS,
    'x': "277",
    'y': "30"
}

# 로그인 요청
res = session.post(login_url, data=login_data)

# 로그인 실패 시 예외 발생
if res.status_code != 200:
    raise Exception("Login failed.")

# 로그인 후 접근할 페이지
mypage = '<https://www.cheonyu.com/mypage/wish.html?page=1&s11=190&s12=&s13=2>'

# Session으로 페이지 접근 (로그인 유지)
res = session.get(mypage)

# HTML 파싱
soup = BeautifulSoup(res.text, "html.parser")

# 품절 상품 정보 추출
soldouts = soup.select('div.zzim_cart_wrap#tabOff>div>ul>li>div>div.info')

for soldout in soldouts:
    print(soldout.text)
    print("=" * 40)

print("\\n##품절 상품번호만 모아보기##")

# 상품번호만 추출
soldouts = soup.select('div.zzim_cart_wrap#tabOff>div>ul>li>div>div.info>p')

for soldout in soldouts:
    print(soldout.text)

코드 핵심 포인트

  1. Session 사용: 로그인 상태 유지
  2. POST 요청: 로그인 데이터 전송
  3. CSS Selector: 정확한 데이터 추출

로그인 데이터 찾는 방법 (개발자 도구 활용)

1단계: 개발자 도구 열기

  • Chrome: F12 또는 Ctrl+Shift+I
  • 로그인 페이지로 이동

2단계: Network 탭 설정

  1. Network 탭 클릭
  2. Preserve log 체크 (중요!)
  3. 필터를 Doc 또는 Fetch/XHR로 설정

3단계: 로그인 시도

  1. 아이디/비밀번호 입력
  2. 로그인 버튼 클릭
  3. Network 탭에서 POST 요청 찾기

4단계: 로그인 정보 확인

Headers 탭:
- Request URL: <https://example.com/login> (로그인 URL)
- Request Method: POST

Payload 탭:
- username: your_id
- password: your_password
- (추가 필드들)

실전 예제: 네이버 로그인

import requests
from bs4 import BeautifulSoup

session = requests.Session()

# 개발자 도구에서 확인한 정보
login_url = '<https://nid.naver.com/nidlogin.login>'

login_data = {
    'id': 'your_naver_id',
    'pw': 'your_password',
    'enctp': '1',  # 추가 필드 (개발자 도구에서 확인)
}

# 헤더 추가 (봇으로 인식 방지)
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
}

# 로그인
response = session.post(login_url, data=login_data, headers=headers)

# 로그인 확인
if '네이버 메인' in response.text or response.status_code == 200:
    print("로그인 성공!")

    # 마이페이지 접근
    mypage = session.get('<https://www.naver.com/>')
    soup = BeautifulSoup(mypage.text, 'html.parser')
    # 크롤링...
else:
    print("로그인 실패!")

헤더(Headers) 추가로 차단 방지

User-Agent 추가

많은 사이트가 봇을 차단하기 위해 User-Agent를 확인합니다.

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
    'Referer': '<https://example.com/login>'  # 로그인 페이지 URL
}

# 로그인 시 헤더 포함
response = session.post(login_url, data=login_data, headers=headers)

# 이후 모든 요청에도 헤더 유지
response = session.get(mypage_url, headers=headers)

다양한 헤더 옵션

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
    'Accept-Language': 'ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7',
    'Accept-Encoding': 'gzip, deflate, br',
    'Connection': 'keep-alive',
    'Referer': '<https://example.com/login>'
}

쿠키(Cookie) 확인하고 사용하기

쿠키 확인

# 로그인 후 쿠키 확인
print(session.cookies.get_dict())
# {'sessionid': 'abc123', 'auth': 'xyz789'}

쿠키 직접 설정

# 쿠키를 직접 설정 (이미 알고 있는 경우)
session.cookies.set('sessionid', 'abc123')
session.cookies.set('auth', 'xyz789')

# 쿠키로 바로 접근
response = session.get(mypage_url)

쿠키 저장하고 재사용

import pickle

# 로그인 후 쿠키 저장
with open('cookies.pkl', 'wb') as f:
    pickle.dump(session.cookies, f)

# 나중에 쿠키 불러오기
with open('cookies.pkl', 'rb') as f:
    cookies = pickle.load(f)
    session.cookies.update(cookies)

# 로그인 없이 바로 접근
response = session.get(mypage_url)

CSRF 토큰이 필요한 경우

CSRF 토큰이란?

보안을 위해 로그인 폼에 숨겨진 토큰을 포함하는 경우가 많습니다.

import requests
from bs4 import BeautifulSoup

session = requests.Session()

# 1. 로그인 페이지 접근 (토큰 얻기)
login_page = '<https://example.com/login>'
response = session.get(login_page)
soup = BeautifulSoup(response.text, 'html.parser')

# 2. CSRF 토큰 추출
csrf_token = soup.find('input', {'name': 'csrf_token'})['value']
# 또는
# csrf_token = soup.select_one('input[name="csrf_token"]')['value']

# 3. 로그인 데이터에 토큰 포함
login_data = {
    'username': 'your_id',
    'password': 'your_password',
    'csrf_token': csrf_token  # 토큰 추가!
}

# 4. 로그인
response = session.post(login_url, data=login_data)

로그인 성공 확인 방법

방법 1: 상태 코드 확인

response = session.post(login_url, data=login_data)

if response.status_code == 200:
    print("요청 성공")
else:
    print("요청 실패")

방법 2: URL 리다이렉트 확인

response = session.post(login_url, data=login_data)

# 로그인 성공 시 메인 페이지로 리다이렉트
if 'main' in response.url or 'dashboard' in response.url:
    print("로그인 성공!")
else:
    print("로그인 실패")

방법 3: 특정 텍스트 확인

response = session.post(login_url, data=login_data)

# 로그인 후 표시되는 텍스트 확인
if '마이페이지' in response.text or '환영합니다' in response.text:
    print("로그인 성공!")
else:
    print("로그인 실패")

방법 4: 쿠키 확인

response = session.post(login_url, data=login_data)

# 세션 쿠키 확인
if 'sessionid' in session.cookies or 'auth_token' in session.cookies:
    print("로그인 성공!")
else:
    print("로그인 실패")

실전 프로젝트: 쇼핑몰 위시리스트 크롤러

import requests
from bs4 import BeautifulSoup
import pandas as pd
from datetime import datetime

class ShoppingCrawler:
    """로그인 기반 쇼핑몰 크롤러"""

    def __init__(self, username, password):
        self.session = requests.Session()
        self.username = username
        self.password = password
        self.is_logged_in = False

        # 헤더 설정
        self.headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
        }

    def login(self, login_url, login_data_fields):
        """로그인 수행"""

        # 로그인 데이터 구성
        login_data = {
            login_data_fields['user_field']: self.username,
            login_data_fields['pass_field']: self.password
        }

        # 추가 필드가 있으면 포함
        if 'extra_fields' in login_data_fields:
            login_data.update(login_data_fields['extra_fields'])

        try:
            response = self.session.post(
                login_url,
                data=login_data,
                headers=self.headers
            )

            # 로그인 성공 확인
            if response.status_code == 200:
                self.is_logged_in = True
                print("✅ 로그인 성공!")
                return True
            else:
                print(f"❌ 로그인 실패: 상태 코드 {response.status_code}")
                return False

        except Exception as e:
            print(f"❌ 로그인 중 오류 발생: {e}")
            return False

    def get_wishlist(self, wishlist_url):
        """위시리스트 가져오기"""

        if not self.is_logged_in:
            print("❌ 먼저 로그인이 필요합니다.")
            return None

        try:
            response = self.session.get(wishlist_url, headers=self.headers)
            soup = BeautifulSoup(response.text, 'html.parser')

            # 상품 정보 추출 (CSS 선택자는 사이트마다 다름)
            products = []
            items = soup.select('.product-item')  # 예시 선택자

            for item in items:
                product = {
                    '상품명': item.select_one('.product-name').text.strip(),
                    '가격': item.select_one('.product-price').text.strip(),
                    '상태': item.select_one('.product-status').text.strip(),
                }
                products.append(product)

            print(f"✅ {len(products)}개의 상품을 찾았습니다.")
            return products

        except Exception as e:
            print(f"❌ 크롤링 중 오류 발생: {e}")
            return None

    def save_to_csv(self, data, filename=None):
        """CSV 파일로 저장"""

        if not data:
            print("❌ 저장할 데이터가 없습니다.")
            return

        if filename is None:
            filename = f"wishlist_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv"

        df = pd.DataFrame(data)
        df.to_csv(filename, index=False, encoding='utf-8-sig')
        print(f"✅ 파일 저장 완료: {filename}")

# 사용 예제
if __name__ == '__main__':
    # 크롤러 생성
    crawler = ShoppingCrawler(
        username='your_id',
        password='your_password'
    )

    # 로그인 설정
    login_url = '<https://example.com/member/loginResult.html>'
    login_fields = {
        'user_field': 'inMID',
        'pass_field': 'inMPW',
        'extra_fields': {
            'url': '%2F',
            'x': '277',
            'y': '30'
        }
    }

    # 로그인
    if crawler.login(login_url, login_fields):
        # 위시리스트 크롤링
        wishlist_url = '<https://example.com/mypage/wish.html>'
        products = crawler.get_wishlist(wishlist_url)

        # CSV 저장
        if products:
            crawler.save_to_csv(products)

자주 발생하는 문제와 해결법

문제 1: 로그인이 안 됨

# ❌ 문제
response = session.post(login_url, data=login_data)
# 계속 로그인 페이지로 리다이렉트

# ✅ 해결 1: 헤더 추가
headers = {
    'User-Agent': 'Mozilla/5.0...',
    'Referer': login_url
}
response = session.post(login_url, data=login_data, headers=headers)

# ✅ 해결 2: CSRF 토큰 확인
# 로그인 폼에 숨겨진 토큰이 있는지 확인

# ✅ 해결 3: 로그인 데이터 필드명 재확인
# 개발자 도구에서 정확한 필드명 확인

문제 2: 한글 깨짐

# ❌ 문제
response = session.get(url)
print(response.text)  # 한글 깨짐

# ✅ 해결 1: 인코딩 지정
response.encoding = 'utf-8'
print(response.text)

# ✅ 해결 2: content 사용
html = response.content.decode('utf-8')
soup = BeautifulSoup(html, 'html.parser')

문제 3: 403 Forbidden 에러

# ❌ 문제
response = session.get(url)
# 403 Forbidden 에러

# ✅ 해결: 헤더를 더 자세히 설정
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
    'Accept': 'text/html,application/xhtml+xml',
    'Accept-Language': 'ko-KR,ko;q=0.9',
    'Accept-Encoding': 'gzip, deflate, br',
    'Connection': 'keep-alive',
    'Referer': base_url
}
response = session.get(url, headers=headers)

문제 4: 로그인 후 데이터가 안 보임

# ❌ 문제
session.post(login_url, data=login_data)
response = requests.get(mypage_url)  # session이 아님!

# ✅ 해결: 반드시 session 사용
session.post(login_url, data=login_data)
response = session.get(mypage_url)  # session 사용!

문제 5: JavaScript 렌더링 필요

# BeautifulSoup은 JavaScript를 실행하지 않음
# 동적 콘텐츠는 Selenium 사용

from selenium import webdriver
from selenium.webdriver.common.by import By

driver = webdriver.Chrome()
driver.get(login_url)

# 로그인
driver.find_element(By.NAME, 'username').send_keys('your_id')
driver.find_element(By.NAME, 'password').send_keys('your_password')
driver.find_element(By.CSS_SELECTOR, 'button[type="submit"]').click()

# JavaScript 실행 대기
import time
time.sleep(2)

# 페이지 소스 가져오기
soup = BeautifulSoup(driver.page_source, 'html.parser')

법적 주의사항

⚠️ 반드시 확인할 사항

  1. robots.txt 확인 <https://example.com/robots.txt> 크롤링 허용 여부 확인
  2. 이용약관 확인 자동화된 접근을 금지하는지 확인
  3. 개인정보 보호 다른 사용자의 정보를 수집하지 말 것
  4. 서버 부하 최소화 import time for url in urls: response = session.get(url) # 처리... time.sleep(1) # 1초 대기
  5. 상업적 이용 주의 데이터를 상업적으로 이용할 경우 법적 문제 발생 가능

체크리스트: 로그인 크롤링 전 확인

✅ Session 객체 생성

✅ 개발자 도구로 로그인 URL 확인

✅ 개발자 도구로 로그인 데이터 필드 확인

✅ User-Agent 헤더 추가

✅ CSRF 토큰 필요 여부 확인

✅ 로그인 성공 여부 확인

✅ 쿠키 유지 확인

✅ robots.txt 및 이용약관 확인

마치며: 안전하고 효율적인 크롤링

로그인 기반 크롤링은 Session의 개념만 이해하면 어렵지 않습니다. 핵심은 Session 객체를 일관되게 사용하는 것입니다.

기억할 핵심 3가지:

  1. Session 사용 – 로그인 상태 유지
  2. 개발자 도구 활용 – 정확한 데이터 확인
  3. 법적 준수 – robots.txt와 이용약관 확인

크롤링은 강력한 도구지만 책임감 있게 사용해야 합니다. 서버에 부담을 주지 않고, 개인정보를 침해하지 않으며, 이용약관을 준수하는 것이 중요합니다!

이 글이 도움되셨다면 북마크하고, 크롤링 배우는 동료에게 공유해주세요!


참고 자료

댓글 남기기