태지쌤

로봇 & 코딩교육 No.1 크리에이터

파이썬

브런치스토리 brunchstory 저작권 보호글 파이썬으로 우회 복사하는 방법(웹 크롤링)

태지쌤 2025. 4. 28. 12:10
반응형

https://link.coupang.com/a/cqO1aS

 

Apple 2024 맥북 프로 14 M4 - 노트북 | 쿠팡

현재 별점 4.9점, 리뷰 425개를 가진 Apple 2024 맥북 프로 14 M4! 지금 쿠팡에서 더 저렴하고 다양한 노트북 제품들을 확인해보세요.

www.coupang.com

 

카카오의 티스토리말고

브런치라는 서비스도 있어요.

개인적인 경험으로 일반인이 운영하는 블로그보다

훨씬 글의 퀄리티가 높습니다.

작가들의 블로그라고 할 수 있어요.

그런데 불편한 점은

좋은 내용이라 참고하고 싶은데

저작권 보호를 위해서

작가 본인만 글을 복사할 수 있도록 되어있더라구요.

브런치 사이트의 복사/붙여넣기 방지를 우회하여

Python으로 크롤링하는 방법으로 해결가능합니다.

어떤 원리로 이게 가능할까요?

주로 이런 사이트들은 JavaScript 이벤트 핸들러나

CSS를 사용해 복사를 방지하지만,

서버에서 HTML을 받아오면

이러한 제한을 우회할 수 있습니다.

 

코드 사용법:

1) 단일 글을 크롤링하려면 article_url 변수에

원하는 브런치 글 URL을 입력하고 실행합니다.

2) 매거진 전체를 크롤링하려면

하단의 주석 처리된 부분을 해제하고

magazine_url에 매거진 URL을 입력합니다.

3) 이 코드는 다음과 같은 방식으로 작동합니다:

- HTTP 요청을 통해 브런치 페이지의

HTML을 직접 가져옵니다

- BeautifulSoup으로 HTML을 파싱하여

필요한 콘텐츠를 추출합니다

- 사용자 에이전트 헤더를 설정하여

일반 브라우저처럼 동작합니다

- 추출한 콘텐츠는 텍스트 파일로 저장됩니다

실제 사이트 구조에 따라 일부 선택자(selector)를

수정해야 할 수도 있습니다.

또한 브런치에서 크롤링 방지 정책이 변경될 경우

코드를 업데이트해야 할 수 있습니다.

 

import requests
from bs4 import BeautifulSoup
import time
import random
import re
import os


def get_article_content(article_url):
    """
    브런치 글 URL을 받아 콘텐츠를 추출하는 함수
    """
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
        'Accept-Language': 'ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7',
        'Referer': 'https://brunch.co.kr/'
    }
    
    try:
        response = requests.get(article_url, headers=headers)
        response.raise_for_status()  # 요청이 성공했는지 확인
        
        soup = BeautifulSoup(response.text, 'html.parser')
        
        # 제목 추출
        title = soup.select_one('h1.cover_title')
        title_text = title.text.strip() if title else "제목 없음"
        
        # 작성자 추출
        author = soup.select_one('span.author_name')
        author_text = author.text.strip() if author else "작성자 미상"
        
        # 본문 내용 추출 (브런치의 경우 article 태그 내부에 있는 경우가 많음)
        content_divs = soup.select('div.item_view article p, div.item_view article h1, div.item_view article h2, div.item_view article h3')
        if not content_divs:
            content_divs = soup.select('div.wrap_body p, div.wrap_body h1, div.wrap_body h2, div.wrap_body h3')
        
        content = []
        for div in content_divs:
            text = div.get_text(strip=True)
            if text:
                content.append(text)
                
        # 만약 위 선택자로 내용을 찾지 못했다면 다른 방법 시도
        if not content:
            article_content = soup.select_one('.wrap_body')
            if article_content:
                content = [p.text.strip() for p in article_content.find_all(['p', 'h1', 'h2', 'h3']) if p.text.strip()]
        
        return {
            'title': title_text,
            'author': author_text,
            'content': '\n\n'.join(content),
            'url': article_url
        }
        
    except requests.exceptions.RequestException as e:
        print(f"요청 중 오류 발생: {e}")
        return None
    except Exception as e:
        print(f"처리 중 오류 발생: {e}")
        return None


def save_article(article_data, folder='brunch_articles'):
    """
    추출한 글을 파일로 저장하는 함수
    """
    if not article_data:
        return False
    
    # 폴더가 없으면 생성
    if not os.path.exists(folder):
        os.makedirs(folder)
    
    # 파일명 생성 (특수문자 제거)
    filename = re.sub(r'[\\/*?:"<>|]', "", article_data['title'])
    filename = f"{filename}_{article_data['author']}.txt"
    filepath = os.path.join(folder, filename)
    
    try:
        with open(filepath, 'w', encoding='utf-8') as f:
            f.write(f"제목: {article_data['title']}\n")
            f.write(f"작성자: {article_data['author']}\n")
            f.write(f"원본 URL: {article_data['url']}\n\n")
            f.write("=" * 50 + "\n\n")
            f.write(article_data['content'])
        
        print(f"파일 저장 완료: {filepath}")
        return True
    except Exception as e:
        print(f"파일 저장 중 오류 발생: {e}")
        return False


def crawl_brunch_magazine(magazine_url):
    """
    브런치 매거진의 모든 글을 크롤링하는 함수
    """
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
    }
    
    try:
        response = requests.get(magazine_url, headers=headers)
        response.raise_for_status()
        
        soup = BeautifulSoup(response.text, 'html.parser')
        
        # 글 링크 추출 (이 부분은 브런치 사이트 구조에 따라 조정 필요)
        article_links = soup.select('a.link_post')
        article_urls = []
        
        for link in article_links:
            if 'href' in link.attrs:
                url = link['href']
                if not url.startswith('http'):
                    url = f"https://brunch.co.kr{url}"
                article_urls.append(url)
        
        print(f"총 {len(article_urls)}개의 글을 발견했습니다.")
        
        # 각 글 처리
        for i, url in enumerate(article_urls):
            print(f"[{i+1}/{len(article_urls)}] 처리 중: {url}")
            article_data = get_article_content(url)
            if article_data:
                save_article(article_data)
            
            # 서버 부하를 줄이기 위해 요청 간 간격 두기
            time.sleep(random.uniform(1.5, 3.0))
            
    except Exception as e:
        print(f"매거진 크롤링 중 오류 발생: {e}")


# 사용 예시
if __name__ == "__main__":
    # 단일 글 크롤링
    article_url = "https://brunch.co.kr/@글주소"  # 실제 브런치 글 URL로 변경
    article_data = get_article_content(article_url)
    if article_data:
        save_article(article_data)
    
    # 매거진 전체 크롤링
    # magazine_url = "https://brunch.co.kr/@매거진주소"  # 실제 브런치 매거진 URL로 변경
    # crawl_brunch_magazine(magazine_url)

brunch-crawler.py
0.01MB

 

이런 식으로 텍스트 파일로

저장되어있는 걸 볼 수 있구요.

메모장 열어서 활용할 수 있어요.

사실 더 쉬운 방법은

코딩하지 않고 웹크롤링 없이

아래와 같이 브라우저 개발자 도구들어가서

디버거에 자바스크립트 작동하지 않도록

체크하는 것으로 해결할 수 있어요.

그냥 파이썬 코드 연습해보자는 겁니다^^;;

반응형