티스토리 뷰

Web Crawling

크롤링 기초

daze1002 2025. 5. 19. 01:43
반응형

📡 1. 크롤링 (Crawling)

1-1. 개요

🕸️ 1-1-1. 크롤링이란?

**크롤링(Crawling)**은 웹 페이지나 API로부터 원하는 정보를 자동으로 수집하는 기술이다.
자동화된 프로그램인 크롤러(Crawler) 또는 **스파이더(Spider)**가 웹 페이지를 탐색하며 데이터를 추출한다.
머신러닝 학습, 데이터 분석, 시장 조사 등 대량의 데이터 수집에 효과적이다.

🔍 1-1-2. 크롤링 vs 스크래핑

구분 웹 크롤링 웹 스크래핑
목적 웹 전체 탐색 및 페이지 수집 특정 데이터 추출
범위 광범위 (다수 사이트) 제한적 (특정 페이지)
방식 링크를 따라 페이지 순회 HTML 구조 분석 및 파싱
활용 예시 검색 엔진 인덱싱 가격 비교, 트렌드 분석
윤리/법 robots.txt 준수 저작권·이용약관 준수

💡 robots.txt: 크롤링 허용 여부 및 범위를 명시한 파일.
예시: https://example.com/robots.txt

🎯 1-1-3. 크롤링의 필요성

  • 자동화된 데이터 수집
  • 🔄 실시간 정보 갱신 가능
  • 📊 빅데이터 확보 → ML 학습/분석 활용
  • 🏁 경쟁 분석 및 전략 수립

1-2. 크롤링 시 주의 사항

⚖️ 1-2-1. 법적 고려사항

  1. 저작권: 무단 수집 및 재사용 금지
  2. 이용약관 준수: 크롤링 허용 범위 확인
  3. robots.txt 정책 준수: 접근 제한 경로 확인

🧩 1-2-2. 서버 부하 방지

  • 크롤링 속도 조절 (예: time.sleep)
  • 병렬 요청 제한 (동시 요청 제한)
  • User-Agent 설정 → 신뢰성 확보

🔐 1-2-3. 개인정보 및 윤리 고려

  • 민감한 정보 수집 시 법적 규제 준수
  • 데이터 활용 목적 명확히 → 윤리적 문제 방지

🚫 1-2-4. IP 차단 위험

  • 과도한 요청 → 서버 차단 가능
  • User-Agent/Proxy 설정, 요청 간 딜레이 삽입 등 회피 전략 필요

🔗 2. Open API

2-1. Open API 개요

📘 Open API란?

Open API는 누구나 접근할 수 있도록 공개된 API로, 개발자가 표준화된 방법으로 특정 서비스나 데이터에 접근할 수 있게 해주는 인터페이스입니다.


📌 특징

  • 인증 방식: API Key, OAuth
  • 사용량/요청 제한 존재
  • 요청/응답 포맷과 예제 등을 공식 문서로 제공

🚀 장점

  • 빠른 개발 (표준화된 인터페이스 제공)
  • 손쉬운 데이터 확보
  • 서비스 간 연동 및 혁신 촉진

2-2. Open API 사용법

📘 API 문서 구조

항목 설명
Endpoint API 요청 주소
Method GET, POST, PUT, DELETE 등
Parameter 쿼리 스트링 또는 요청 본문 데이터
Response JSON, XML 등
인증 API Key, OAuth 등 방식으로 수행

🧪 테스트 방법

  • Postman: GUI 기반 테스트
  • cURL: CLI 기반 요청 테스트
  • 브라우저: GET 요청 시 URL 입력으로 간단 테스트 가능

📂 공공데이터포털 API 사용 순서

  1. 회원 가입 후 API 키 발급
  2. 문서에서 요청/응답 형식 확인
  3. Python 등으로 호출하여 응답 처리

2-3. API 크롤러 만들기 (Python)

✅ Step 1. 환경 설정

pip install requests pandas
  • API 키는 .env 또는 별도 설정 파일로 안전하게 관리

✅ Step 2. 요청 예시

params = {"key": "{API_KEY}", "targetDt": "20241120"}
response = requests.get(API_URL, params=params)

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

✅ Step 3. 데이터 저장 (CSV 예시)

import csv

with open('movie_data.csv', 'w', encoding='utf-8') as f:
    writer = csv.writer(f)
    writer.writerow(['순위', '영화이름', '개봉일자'])
    for item in items:
        writer.writerow([item['rank'], item['movieNm'], item['openDt']])

✅ Step 4. 자동화 및 예외 처리

try:
    response = requests.get(url, params=params)
    response.raise_for_status()
except requests.exceptions.RequestException as e:
    print(f"Error: {e}")

✅ Step 5. 데이터 정제 및 저장

import pandas as pd

df = pd.read_csv('movie_data.csv')
df.dropna(inplace=True)
df['개봉일자'] = pd.to_datetime(df['개봉일자'])
df.to_csv('final_data.csv', index=False)

WEB 구조 정보 정리

탐색과 수집의 구조

형식: 웹, 웹 구조, HTML, HTTP, 서버, 통신 구조, 크롤러, 스파이더, JavaScript, AJAX, Selenium, robots.txt, sitemap.xml, BFS, DFS


3-1. WEB 구조 기초

3-1-1. 기본 구성 요소

  • URL (Uniform Resource Locator)

    • 웹에서 자원의 위치를 나타내는 표준 주소 체계
    • 프로토콜, 도메인, 경로, 쿼리 스트링 등으로 구성
  • HTTP / HTTPS

    • 웹 클라이언트와 서버 간 통신을 위한 프로토콜
    • 주요 요청 메서드: GET, POST, PUT, DELETE
    • 응답 상태 코드: 2xx(성공), 3xx(리다이렉션), 4xx(클라이언트 오류), 5xx(서버 오류)
  • HTML / CSS / JavaScript

    • HTML: 웹 페이지의 구조 정의
    • CSS: 웹 페이지의 스타일 및 레이아웃 정의
    • JavaScript: 웹 페이지의 동적 기능 구현

3-1-2. HTML 문서 구조

  • 기본 구조: <!DOCTYPE html>, <html>, <head>, <body>

  • DOM (Document Object Model)

    • HTML 문서를 트리 구조로 표현
    • JavaScript 등을 통해 DOM 요소 접근 및 조작 가능

3-1-3. 웹의 연결성

  • 하이퍼링크: <a href="URL"> 태그로 구현
  • 웹 그래프: 페이지는 노드, 링크는 엣지로 구성된 그래프
  • 탐색 알고리즘: 깊이 우선 탐색(DFS), 너비 우선 탐색(BFS)

3-2. HTTP 프로토콜과 크롤링

3-2-1. HTTP 요청과 응답 구조

  • 요청 메서드: GET, POST, PUT, DELETE
  • 상태 코드: 2xx, 3xx, 4xx, 5xx
  • 헤더 정보: User-Agent, Accept, Content-Type 등

3-2-2. 크롤러 요청 구성

  • User-Agent 설정 필요 (크롤러 신원 표시)
  • 인증정보나 쿠키 등 헤더에 포함 가능
  • 요청 간 딜레이 적용 권장 (서버 부하 방지 및 IP 차단 방지)

3-3. robots.txt와 sitemap.xml

3-3-1. robots.txt

  • 웹 사이트의 루트 디렉토리에 위치한 크롤링 접근 제어 파일

  • 예시:

    User-agent: *
    Disallow: /private/

3-3-2. sitemap.xml

  • 사이트 내 URL 목록 제공

  • 크롤러가 페이지를 효율적으로 탐색하도록 도와줌

  • 예시:

    <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
      <url>
        <loc>https://www.example.com/page1</loc>
        <lastmod>2023-10-01</lastmod>
        <changefreq>monthly</changefreq>
        <priority>0.8</priority>
      </url>
    </urlset>
  • robots.txt 내 명시:

    Sitemap: https://www.example.com/sitemap.xml

3-4. 동적 웹 페이지 크롤링

3-4-1. 동적 렌더링

  • JS 기반으로 렌더링된 콘텐츠는 일반 크롤러가 수집 불가
  • AJAX, SPA 등으로 데이터가 비동기적으로 로딩됨

대응 방법:

  1. Selenium, Puppeteer 등의 헤드리스 브라우저 사용
  2. 네트워크 요청 중 API 엔드포인트 직접 호출
  3. Splash, Rendertron 등으로 JS 렌더링 처리

3-5. 크롤러 설계 시 고려 사항

3-5-1. URL 관리

  • 중복 URL 정규화 필요
  • 상대 경로를 절대 경로로 변환
  • 대소문자, 슬래시 통일 등 표준화 필요

3-5-2. 상태 유지와 세션

  • 로그인 유지 필요 시 쿠키 및 세션 정보 사용
  • 서버로부터 받은 세션 정보를 다음 요청에 포함

3-5-3. 데이터 파싱

  • HTML 파싱 도구: BeautifulSoup (Python), Cheerio (Node.js)
  • XPath, CSS 선택자 활용
  • 예외 및 오류 처리 로직 추가

3-6. 웹 크롤링 확장 전략

3-6-1. 스케줄링 및 주기적 크롤링

  • Cron (Linux), Task Scheduler (Windows) 사용
  • ETag, Last-Modified 등을 활용해 변경 여부 판단

3-6-2. 웹 표준 및 시맨틱 정보 활용

  • W3C 표준 준수 웹 페이지는 크롤링 효율 높음
  • <meta> 태그, OG 프로토콜 등 활용 가능

4. 크롤링 데이터 저장

4-1. 데이터 저장 개요

4-1-1. 저장의 필요성

  • 수집한 데이터를 안전하게 저장하고, 분석이나 공유, 학습 등에 활용하기 위해 영속성 확보 필요
  • 구조화된 저장을 통해 검색과 처리 효율 향상
  • 팀 및 프로젝트 간 재사용 가능

4-1-2. 저장 시 고려 사항

  • 데이터 특성 파악: 표 형식, 중첩 구조 여부, 크기, 변경 빈도
  • 활용 목적 고려: 분석용, 학습용, 웹 서비스용 등
  • 보안 및 법적 준수: 민감 정보 암호화, 접근 권한 설정, 개인정보 보호법 준수
  • 품질 관리: 저장 전 데이터 검증 및 정제
  • 장애 대응: 저장 오류 기록 및 모니터링 체계
  • 버전 및 확장성 설계

4-1-3. 저장 방식 종류

  • 파일 시스템: CSV, JSON, XML, Excel
  • 관계형 데이터베이스: MySQL, PostgreSQL
  • NoSQL 데이터베이스: MongoDB, Redis
  • 빅데이터 저장소: Hadoop HDFS, Amazon S3
  • 클라우드 데이터베이스: Firebase, AWS DynamoDB

4-2. 파일 기반 저장

CSV

  • 텍스트 기반, 표 형태에 적합
  • Excel 등으로 열람 가능
  • 중첩 데이터에는 부적합
import csv

data = [
    {'name': 'Alice', 'age': 30, 'city': 'Seoul'},
    {'name': 'Bob', 'age': 25, 'city': 'Busan'}
]

with open('data.csv', 'w', newline='', encoding='utf-8') as csvfile:
    fieldnames = ['name', 'age', 'city']
    writer = csv.DictWriter(csvfile, fieldnames=fieldnames)

    writer.writeheader()
    for row in data:
        writer.writerow(row)

JSON

  • 키-값 구조, 계층적 데이터 표현 가능
  • 웹 앱과 호환성 좋음
import json

data = [
    {'name': 'Alice', 'age': 30, 'city': 'Seoul'},
    {'name': 'Bob', 'age': 25, 'city': 'Busan'}
]

with open('data.json', 'w', encoding='utf-8') as jsonfile:
    json.dump(data, jsonfile, ensure_ascii=False, indent=4)

XML

  • 태그 기반, 문서 구조 표현
  • 의미 표현은 우수하지만 구문 복잡
import xml.etree.ElementTree as ET

root = ET.Element('people')

person1 = ET.SubElement(root, 'person')
ET.SubElement(person1, 'name').text = 'Alice'
ET.SubElement(person1, 'age').text = '30'
ET.SubElement(person1, 'city').text = 'Seoul'

person2 = ET.SubElement(root, 'person')
ET.SubElement(person2, 'name').text = 'Bob'
ET.SubElement(person2, 'age').text = '25'
ET.SubElement(person2, 'city').text = 'Busan'

tree = ET.ElementTree(root)
tree.write('data.xml', encoding='utf-8', xml_declaration=True)

Excel

  • 시각화 및 분석에 유리
  • 비개발자 접근 용이
import pandas as pd

data = [
    {'name': 'Alice', 'age': 30, 'city': 'Seoul'},
    {'name': 'Bob', 'age': 25, 'city': 'Busan'}
]

df = pd.DataFrame(data)
df.to_excel('data.xlsx', index=False)

4-3. 관계형 데이터베이스 저장 (MySQL)

  • 스키마 기반, SQL로 자유로운 조작 가능
  • 데이터 무결성 보장, 스키마 변경은 어려움
import pymysql

data = [
    {'name': 'Alice', 'age': 30, 'city': 'Seoul'},
    {'name': 'Bob', 'age': 25, 'city': 'Busan'}
]

connection = pymysql.connect(
    host='localhost',
    user='user',
    password='password',
    db='mydatabase',
    charset='utf8mb4'
)

try:
    with connection.cursor() as cursor:
        sql = "INSERT INTO people (name, age, city) VALUES (%s, %s, %s)"
        for person in data:
            cursor.execute(sql, (person['name'], person['age'], person['city']))
    connection.commit()
finally:
    connection.close()

4-4. NoSQL 저장

MongoDB

  • 유연한 스키마, 중첩 구조에 적합
  • JSON 형태의 문서 저장
from pymongo import MongoClient

data = [
    {'name': 'Alice', 'age': 30, 'city': 'Seoul'},
    {'name': 'Bob', 'age': 25, 'city': 'Busan'}
]

client = MongoClient('localhost', 27017)
db = client['mydatabase']
collection = db['people']

collection.insert_many(data)

Redis

  • 키-값 저장, 인메모리 기반으로 속도 빠름
  • 대용량에는 부적합
import redis
import json

data = [
    {'name': 'Alice', 'age': 30, 'city': 'Seoul'},
    {'name': 'Bob', 'age': 25, 'city': 'Busan'}
]

r = redis.Redis(host='localhost', port=6379, db=0)

for idx, person in enumerate(data):
    r.set(f'person:{idx}', json.dumps(person))

4-5. 대용량 저장소

Hadoop HDFS

  • 분산 파일 시스템, 수평 확장 가능
  • 설정 및 실시간 처리에는 어려움
hdfs dfs -put data.csv /user/hadoop/data/

Amazon S3

  • AWS의 객체 저장소, 인터넷을 통해 접근 가능
  • 비용 발생, 네트워크 지연 가능성 있음
import boto3

s3 = boto3.client('s3')
s3.upload_file('data.csv', 'my-bucket', 'data/data.csv')

4-6. 클라우드 데이터베이스

Firebase Realtime Database

  • 실시간 동기화 지원, 백엔드 간편 구축
  • 관계형 구조에는 부적합
import firebase_admin
from firebase_admin import credentials, db

cred = credentials.Certificate('path/to/serviceAccountKey.json')
firebase_admin.initialize_app(cred, {
    'databaseURL': '<https://your-database-name.firebaseio.com/>'
})

ref = db.reference('people')
data = {
    'Alice': {'age': 30, 'city': 'Seoul'},
    'Bob': {'age': 25, 'city': 'Busan'}
}
ref.set(data)

AWS DynamoDB

  • 완전 관리형 NoSQL 서비스
  • 확장성 높고, 모델링 복잡 가능성 있음
import boto3

dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('people')

data = [
    {'name': 'Alice', 'age': 30, 'city': 'Seoul'},
    {'name': 'Bob', 'age': 25, 'city': 'Busan'}
]

with table.batch_writer() as batch:
    for person in data:
        batch.put_item(Item=person)