Skip to content

Upstage-Ambassador-1th-Team1/Data-ETL-PipeLIne

Repository files navigation

κ³΅κ³΅μž„λŒ€μ£Όνƒ 곡고 μžλ™ μˆ˜μ§‘ νŒŒμ΄ν”„λΌμΈ

SH(μ„œμšΈμ£Όνƒλ„μ‹œκ³΅μ‚¬) 및 LH(ν•œκ΅­ν† μ§€μ£Όνƒκ³΅μ‚¬) κ³΅κ³΅μž„λŒ€μ£Όνƒ 곡고λ₯Ό μžλ™μœΌλ‘œ ν¬λ‘€λ§ν•˜κ³ , PDFμ—μ„œ 정보λ₯Ό μΆ”μΆœν•˜μ—¬ PostgreSQL λ°μ΄ν„°λ² μ΄μŠ€μ— μ €μž₯ν•˜λŠ” Airflow 기반 νŒŒμ΄ν”„λΌμΈμž…λ‹ˆλ‹€.

λͺ©μ°¨

μ£Όμš” κΈ°λŠ₯

1. 닀쀑 곡사 지원

  • SH 곡사: BeautifulSoup 기반 정적 μ›Ή 크둀링
  • LH 곡사: Selenium 기반 동적 νŽ˜μ΄μ§€ 크둀링

2. λ‹€μ–‘ν•œ 파일 ν˜•μ‹ 처리

  • PDF 파일 직접 λ‹€μš΄λ‘œλ“œ
  • Excel νŒŒμΌμ„ PDF둜 μžλ™ λ³€ν™˜ (LibreOffice ν™œμš©)
  • 닀쀑 파일 μžλ™ 병합

3. AI 기반 정보 μΆ”μΆœ

  • Upstage Information Extract API ν™œμš©
  • JSON μŠ€ν‚€λ§ˆ 기반 κ΅¬μ‘°ν™”λœ 데이터 μΆ”μΆœ
  • 곡급 ν”„λ‘œμ νŠΈ, 일정, 자격 μš”κ±΄ λ“± μžλ™ νŒŒμ‹±

4. μžλ™ν™”λœ νŒŒμ΄ν”„λΌμΈ

  • Apache Airflow 기반 μŠ€μΌ€μ€„λ§
  • 전체 μˆ˜μ§‘ / 증뢄 μˆ˜μ§‘ λͺ¨λ“œ 지원
  • 쀑볡 데이터 μžλ™ 필터링

μ‹œμŠ€ν…œ μ•„ν‚€ν…μ²˜

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                        데이터 μ†ŒμŠ€                               β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚      SH 곡사 ν™ˆνŽ˜μ΄μ§€        β”‚         LH 곡사 ν™ˆνŽ˜μ΄μ§€           β”‚
β”‚     (정적 HTML νŽ˜μ΄μ§€)       β”‚      (JavaScript 동적 νŽ˜μ΄μ§€)      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
               β”‚                               β”‚
               β–Ό                               β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   sh_parsing_with_db.py  β”‚   β”‚      lh_parsing_with_db.py       β”‚
β”‚   ─────────────────────  β”‚   β”‚   ────────────────────────────   β”‚
β”‚   - BeautifulSoup        β”‚   β”‚   - Selenium + ChromeDriver      β”‚
β”‚   - requests             β”‚   β”‚   - μ—‘μ…€ λ‹€μš΄λ‘œλ“œ & λ³€ν™˜          β”‚
β”‚   - PDF 직접 λ‹€μš΄λ‘œλ“œ     β”‚   β”‚   - LibreOffice (soffice)       β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚   - PDF 병합 (pypdf)             β”‚
               β”‚               β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
               β”‚                               β”‚
               β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                               β–Ό
               β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
               β”‚         PostgreSQL DB          β”‚
               β”‚   ───────────────────────────  β”‚
               β”‚   - announcements (곡고)       β”‚
               β”‚   - pdf_files (μ²¨λΆ€νŒŒμΌ)       β”‚
               β”‚   - program_info (ν”„λ‘œκ·Έλž¨)    β”‚
               β”‚   - supply_projects (곡급)     β”‚
               β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                               β”‚
                               β–Ό
               β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
               β”‚  information_extract_with_db  β”‚
               β”‚   ───────────────────────────  β”‚
               β”‚   - Upstage API 호좜          β”‚
               β”‚   - PDF β†’ ꡬ쑰화 데이터        β”‚
               β”‚   - μ •κ·œν™”λœ ν…Œμ΄λΈ” μ €μž₯       β”‚
               β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                               β”‚
                               β–Ό
               β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
               β”‚        Apache Airflow         β”‚
               β”‚   ───────────────────────────  β”‚
               β”‚   - 4개 DAG 관리              β”‚
               β”‚   - μŠ€μΌ€μ€„ μžλ™ μ‹€ν–‰          β”‚
               β”‚   - λͺ¨λ‹ˆν„°λ§ & λ‘œκΉ…           β”‚
               β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

기술 μŠ€νƒ

ꡬ뢄 기술
μ›Œν¬ν”Œλ‘œμš° Apache Airflow 2.8.0
μ–Έμ–΄ Python 3.11
λ°μ΄ν„°λ² μ΄μŠ€ PostgreSQL (원격)
ORM SQLAlchemy
크둀링 (SH) BeautifulSoup4, requests
크둀링 (LH) Selenium, Chromium, ChromeDriver
파일 λ³€ν™˜ LibreOffice (soffice)
PDF 처리 pypdf
AI/ML Upstage Information Extract API
μ»¨ν…Œμ΄λ„ˆ Docker, Docker Compose

지원 곡사 및 μ²­μ•½ μœ ν˜•

SH 곡사 (μ„œμšΈμ£Όνƒλ„μ‹œκ³΅μ‚¬) - 9개 μœ ν˜•

  • κ΅­λ―Όκ³΅κ³΅μž„λŒ€μ£Όνƒ
  • λ„μ‹œν˜•μƒν™œμ£Όνƒ
  • λ§€μž…μž„λŒ€μ£Όνƒ
  • μž₯κΈ°μ•ˆμ‹¬μ£Όνƒ
  • μž₯기전세주택
  • μž₯기전세주택2(미리내집)
  • μ „μ„Έμž„λŒ€
  • μ²­λ…„μ•ˆμ‹¬μ£Όνƒ
  • 행볡주택

LH 곡사 (ν•œκ΅­ν† μ§€μ£Όνƒκ³΅μ‚¬) - 7개 μœ ν˜•

  • κ΅­λ―Όμž„λŒ€
  • κ³΅κ³΅μž„λŒ€
  • μ˜κ΅¬μž„λŒ€
  • 행볡주택
  • λ§€μž…μž„λŒ€
  • λ§€μž…μž„λŒ€μ£Όνƒ
  • ν†΅ν•©κ³΅κ³ μž„λŒ€

λΉ λ₯Έ μ‹œμž‘ (Docker)

1. ν•„μˆ˜ μš”κ΅¬μ‚¬ν•­

  • Docker 20.10 이상
  • Docker Compose 2.0 이상
  • 원격 PostgreSQL λ°μ΄ν„°λ² μ΄μŠ€

2. ν™˜κ²½ μ„€μ •

# .env 파일 생성
cp .env.example .env

# .env 파일 μˆ˜μ •
nano .env

3. Docker Compose둜 μ‹€ν–‰

# 이미지 λΉŒλ“œ 및 μ»¨ν…Œμ΄λ„ˆ μ‹œμž‘
docker-compose up -d

# 둜그 확인
docker-compose logs -f

# νŠΉμ • μ„œλΉ„μŠ€ 둜그만 확인
docker-compose logs -f airflow-scheduler

4. Airflow μ›Ή UI 접속

λΈŒλΌμš°μ €μ—μ„œ http://localhost:8081 접속

  • Username: admin (λ˜λŠ” .envμ—μ„œ μ„€μ •ν•œ κ°’)
  • Password: admin (λ˜λŠ” .envμ—μ„œ μ„€μ •ν•œ κ°’)

5. DAG μ‹€ν–‰

μ›Ή UIμ—μ„œ μ‹€ν–‰:

  1. μ›ν•˜λŠ” DAG μ°ΎκΈ° (예: sh_housing_pipeline_full)
  2. ν† κΈ€ λ²„νŠΌμ„ μΌœμ„œ ν™œμ„±ν™”
  3. "Trigger DAG" λ²„νŠΌ 클릭

CLI둜 μ‹€ν–‰:

# SH 전체 μˆ˜μ§‘
docker-compose exec airflow-scheduler airflow dags trigger sh_housing_pipeline_full

# LH 전체 μˆ˜μ§‘
docker-compose exec airflow-scheduler airflow dags trigger lh_housing_pipeline_full

# SH 증뢄 μˆ˜μ§‘
docker-compose exec airflow-scheduler airflow dags trigger sh_housing_pipeline_incremental

# LH 증뢄 μˆ˜μ§‘
docker-compose exec airflow-scheduler airflow dags trigger lh_housing_pipeline_incremental

6. μ»¨ν…Œμ΄λ„ˆ 관리

# μ»¨ν…Œμ΄λ„ˆ 쀑지
docker-compose down

# μ»¨ν…Œμ΄λ„ˆ μž¬μ‹œμž‘
docker-compose restart

# νŠΉμ • μ„œλΉ„μŠ€λ§Œ μž¬μ‹œμž‘
docker-compose restart airflow-scheduler

ν™˜κ²½ μ„€μ •

.env 파일 μ˜ˆμ‹œ

# μ• ν”Œλ¦¬μΌ€μ΄μ…˜ λ°μ΄ν„°λ² μ΄μŠ€ μ„€μ • (ν•„μˆ˜)
DB_HOST=your_remote_db_host
DB_PORT=5432
DB_NAME=housing_db
DB_USER=your_db_user
DB_PASSWORD=your_db_password

# Airflow 메타데이터 λ°μ΄ν„°λ² μ΄μŠ€ μ„€μ • (ν•„μˆ˜)
AIRFLOW_DB_HOST=your_remote_db_host
AIRFLOW_DB_PORT=5432
AIRFLOW_DB_NAME=airflow
AIRFLOW_DB_USER=your_db_user
AIRFLOW_DB_PASSWORD=your_db_password

# Upstage API ν‚€ (ν•„μˆ˜)
UPSTAGE_API_KEY=your_upstage_api_key_here

# Docker μ„€μ •
AIRFLOW_UID=50000
_AIRFLOW_WWW_USER_USERNAME=admin
_AIRFLOW_WWW_USER_PASSWORD=admin

# 파일 μ €μž₯ μ„€μ •
ATTACH_BASE_DIR=attachments
SAVE_JSON_BACKUP=false

# LibreOffice μ„€μ • (LH 크둀링용)
LIBREOFFICE_ENABLED=true
EXCEL_LAYOUT_SAFE_MODE=true

Airflow DAG κ°€μ΄λ“œ

DAG λͺ©λ‘

DAG 이름 λŒ€μƒ μ‹€ν–‰ 방식 μŠ€μΌ€μ€„ μš©λ„
sh_housing_pipeline_full SH μˆ˜λ™ - 졜초 전체 데이터 μˆ˜μ§‘
sh_housing_pipeline_incremental SH μžλ™ 맀일 09:00 일일 μ‹ κ·œ 곡고 μˆ˜μ§‘
lh_housing_pipeline_full LH μˆ˜λ™ - 졜초 전체 데이터 μˆ˜μ§‘
lh_housing_pipeline_incremental LH μžλ™ 맀일 09:30 일일 μ‹ κ·œ 곡고 μˆ˜μ§‘

SH vs LH νŒŒμ΄ν”„λΌμΈ 비ꡐ

ν•­λͺ© SH LH
크둀링 방식 BeautifulSoup (정적) Selenium (동적)
파일 ν˜•μ‹ PDF PDF + Excel
μ—‘μ…€ λ³€ν™˜ ν•΄λ‹Ή μ—†μŒ LibreOffice λ³€ν™˜
μ‹€ν–‰ μ‹œκ°„ 빠름 느림 (λΈŒλΌμš°μ € ꡬ동)
μž¬μ‹œλ„ 횟수 2회 1회

Task ꡬ쑰

init_database (DB μ΄ˆκΈ°ν™”)
    ↓
crawl_*_data (크둀링 & PDF λ‹€μš΄λ‘œλ“œ)
    ↓
extract_*_info (정보 μΆ”μΆœ & DB μ €μž₯)

μŠ€μΌ€μ€„ λ³€κ²½

dags/ ν΄λ”μ˜ DAG νŒŒμΌμ—μ„œ schedule_interval μˆ˜μ •:

# 맀일 μ˜€μ „ 9μ‹œ
schedule_interval='0 9 * * *'

# λ§€μ£Ό μ›”μš”μΌ μ˜€μ „ 9μ‹œ
schedule_interval='0 9 * * 1'

# λ§€μ£Ό μ›”/수/금 μ˜€μ „ 9μ‹œ
schedule_interval='0 9 * * 1,3,5'

둜컬 개발 ν™˜κ²½

Docker μ‚¬μš©μ„ ꢌμž₯ν•©λ‹ˆλ‹€. 둜컬 μ‹€ν–‰ μ‹œ μΆ”κ°€ μ„€μΉ˜κ°€ ν•„μš”ν•©λ‹ˆλ‹€.

ν•„μˆ˜ μš”κ΅¬μ‚¬ν•­

  • Python 3.8 이상
  • PostgreSQL 12 이상
  • Chromium + ChromeDriver (LH 크둀링용)
  • LibreOffice (LH μ—‘μ…€ λ³€ν™˜μš©)

μ„€μΉ˜ (macOS)

# Python μ˜μ‘΄μ„±
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt

# Chromium & ChromeDriver
brew install chromium
brew install chromedriver

# LibreOffice
brew install --cask libreoffice

μˆ˜λ™ μ‹€ν–‰

# λ°μ΄ν„°λ² μ΄μŠ€ μ΄ˆκΈ°ν™”
python database.py

# SH 크둀링
python sh_parsing_with_db.py

# LH 크둀링
python lh_parsing_with_db.py

# 정보 μΆ”μΆœ
python information_extract_with_db.py

ν”„λ‘œμ νŠΈ ꡬ쑰

.
β”œβ”€β”€ dags/                           # Airflow DAG 파일
β”‚   β”œβ”€β”€ sh_housing_pipeline_full.py
β”‚   β”œβ”€β”€ sh_housing_pipeline_incremental.py
β”‚   β”œβ”€β”€ lh_housing_pipeline_full.py
β”‚   └── lh_housing_pipeline_incremental.py
β”œβ”€β”€ scripts/                        # μœ ν‹Έλ¦¬ν‹° 슀크립트
β”‚   β”œβ”€β”€ check_db.py                 # DB μƒνƒœ 확인
β”‚   β”œβ”€β”€ check_airflow_db.py         # Airflow DB 확인
β”‚   β”œβ”€β”€ resets_db.py                # DB 리셋
β”‚   β”œβ”€β”€ migrate_pdf_to_minio.py     # MinIO λ§ˆμ΄κ·Έλ ˆμ΄μ…˜
β”‚   └── test_db_connection.py       # DB μ—°κ²° ν…ŒμŠ€νŠΈ
β”œβ”€β”€ attachments/                    # λ‹€μš΄λ‘œλ“œλœ 파일
β”‚   β”œβ”€β”€ SH/                         # SH 곡사 (μ²­μ•½μœ ν˜•λ³„ 폴더)
β”‚   └── LH/                         # LH 곡사 (μ²­μ•½μœ ν˜•λ³„ 폴더)
β”œβ”€β”€ schema/                         # JSON μŠ€ν‚€λ§ˆ
β”‚   └── schema.json
β”œβ”€β”€ logs/                           # Airflow μ‹€ν–‰ 둜그
β”œβ”€β”€ plugins/                        # Airflow μ»€μŠ€ν…€ ν”ŒλŸ¬κ·ΈμΈ
β”œβ”€β”€ config.py                       # ν™˜κ²½ μ„€μ •
β”œβ”€β”€ database.py                     # DB μ—°κ²° 관리
β”œβ”€β”€ models.py                       # SQLAlchemy ORM λͺ¨λΈ
β”œβ”€β”€ sh_parsing_with_db.py           # SH 크둀링 λͺ¨λ“ˆ
β”œβ”€β”€ lh_parsing_with_db.py           # LH 크둀링 λͺ¨λ“ˆ
β”œβ”€β”€ information_extract_with_db.py  # 정보 μΆ”μΆœ λͺ¨λ“ˆ
β”œβ”€β”€ Dockerfile                      # Docker 이미지 μ •μ˜
β”œβ”€β”€ docker-compose.yml              # μ»¨ν…Œμ΄λ„ˆ μ˜€μΌ€μŠ€νŠΈλ ˆμ΄μ…˜
β”œβ”€β”€ requirements.txt                # Python μ˜μ‘΄μ„±
└── README.md

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •