본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 06. 26. 00:44

Python과 Swiss Ephemeris를 사용하여 무료 점성술 시나스트리 계산기를 만든 방법

요약

Python과 Swiss Ephemeris를 활용하여 무료 점성술 시나스트리 계산기를 구축한 과정을 다룹니다. Flask, Kerykeion, GeoNames API 등을 사용한 기술 스택과 타임존 처리 및 SVG 렌더링 구현 방법을 설명합니다.

핵심 포인트

  • Swiss Ephemeris 기반의 Python 라이브러리 Kerykeion 활용
  • IANA 타임존과 zoneinfo를 이용한 정확한 UTC 변환 처리
  • YAML 설정을 통한 점성술 로직 및 가중치 관리
  • svgwrite를 이용한 커스텀 이중 차트 휠 렌더링 구현
  • 개인정보 보호를 위한 Stateless 설계 원칙 적용

파트너가 우리의 점성술적 궁합을 확인해 달라고 요청했을 때, 저는 모든 개발자가 그렇듯 기존 도구를 사용하는 대신 직접 도구를 만들었습니다.

그 결과물은 Coppiastrale입니다. 이는 Python과 실제 에페메리스 (Ephemeris) 데이터를 사용하여 구축된 커플을 위한 무료 시나스트리 (Synastry) 및 네이탈 차트 (Natal chart) 계산기입니다. 제가 배운 점들을 소개합니다.

시나스트리 (Synastry)란 무엇인가?
시나스트리는 궁합을 평가하기 위해 두 개의 출생 차트를 비교하는 점성술 기법입니다. 두 개의 네이탈 차트 (Natal charts)를 겹쳐 놓고, 한 사람의 행성과 다른 사람의 행성 사이에 형성되는 기하학적 각도 (Aspects) — 컨junction (Conjunctions), 어포지션 (Oppositions), 트라인 (Trines), 스퀘어 (Squares) 등을 분석합니다.

기술 스택 (The stack)
Flask (SSR, SPA가 아님 — SEO가 핵심 요구 사항이었음)
Kerykeion — pyswisseph (Swiss Ephemeris)를 래핑한 Python 라이브러리
GeoNames API — 출생지 → 위도/경도 + IANA 타임존
svgwrite — 차트 휠 (Chart wheels) 렌더링용
SQLite + SQLAlchemy — 유료 플로우에만 사용, 무료 계산기는 어떠한 개인 식별 정보 (PII)도 저장하지 않음
핵심 제약 사항: 무료 도구는 완전히 상태가 없는 (Stateless) 방식이어야 했습니다. 사용자 계정 없음, 저장된 출생 데이터 없음, 최소한의 세션 참조를 제외한 쿠키 없음.

가장 어려웠던 부분: 타임존 (Timezone) 처리
Swiss Ephemeris는 UTC를 필요로 합니다. 사용자는 도시 이름과 현지 시간을 제공합니다. 까다로운 부분은 이를 정확하게 변환하는 것인데, 특히 일광 절약 시간제 (DST) 규칙이 달랐던 과거의 날짜의 경우 더욱 그렇습니다.

GeoNames는 실제 IANA 타임존 식별자 (예: Europe/Rome)를 반환하며, 이를 pytz 또는 zoneinfo로 전달합니다. 처음에는 UTC 오프셋을 직접 반환하는 더 간단한 지오코더 (Geocoder)를 사용했는데, 이로 인해 여러 국가에서 1970년 이전 출생자에 대한 차트 계산이 잘못되는 문제가 발생했습니다. IANA + zoneinfo로 전환하여 이 문제를 해결했습니다.

from zoneinfo import ZoneInfo
from datetime import datetime

def to_utc(date_str, time_str, iana_tz):
local_dt = datetime.strptime(f"{date_str} {time_str}", "%Y-%m-%d %H:%M")
local_dt = local_dt.replace(tzinfo=ZoneInfo(iana_tz))
return local_dt.astimezone(ZoneInfo("UTC"))

시나스트리 (Synastry) 점수 산정
각 상호 위상 (inter-aspect)은 YAML 설정 파일로부터 기본 점수를 부여받습니다 (예: 금성과의 합 (conjunction) = 높음, 토성과의 사각 (square) = 낮음 등). 그 다음, 비점성가들에게 직관적으로 느껴질 수 있도록 모든 값을 0~100 사이의 척도로 압축하는 시그모이드 정규화 (sigmoid normalization)를 적용합니다.

가중치는 DB가 아닌 버전 관리되는 YAML 파일에 저장되므로, 스키마 마이그레이션 (schema migration) 없이도 점성술 로직을 미세 조정할 수 있습니다.

SVG 차트 렌더링
Kerykeion은 기본적으로 SVG 휠을 생성할 수 있지만, 저는 시나스트리를 위한 커스텀 이중 휠 레이아웃(내부 휠 = 인물 A, 외부 휠 = 인물 B, 관련 행성 간의 선)이 필요했습니다. 결국 svgwrite를 사용하여 Kerykeion의 기본 기하학적 구조 위에 프로그래밍 방식으로 오버레이를 그리는 방식을 선택했습니다.

가장 까다로운 부분은 두 행성이 서로 3° 이내에 있을 때, 겹치지 않으면서 정확한 각도에 행성 글리프 (planet glyphs)를 배치하는 것이었습니다. 저는 라벨을 방사형 바깥쪽으로 밀어내는 충돌 감지 (collision-detection) 단계를 추가했습니다.

제품의 해자로서의 SEO
무료 계산기는 SEO를 위한 미끼입니다. 이 앱은 약 365개의 인덱싱 가능한 페이지를 생성합니다: 78개의 정전적 사인 쌍 궁합 (canonical sign-pair compatibility) 페이지, 72개의 사인 내 행성 (planet-in-sign) 페이지, 12개의 사인 프로필, 144개의 태양×상승점 (Sun×Ascendant) 조합 — 이 모든 페이지에는 구조화된 데이터 (BreadcrumbList, Article, FAQPage 스키마)가 포함되어 있습니다.

Flask SSR (Server-Side Rendering) 방식이므로, 이 모든 내용은 JavaScript 렌더링 없이도 크롤링이 가능합니다.

다르게 했을 점
대용량 페이로드 (payload)를 위해 Flask 세션을 사용하지 마세요. 쿠키는 최대 4KB로 제한됩니다. 저는 전체 차트 JSON을 localStorage에 저장하고 세션에는 가벼운 참조값만 유지합니다. 차트 데이터가 소리 없이 잘리기 시작한 후에야 뼈아픈 경험을 통해 이를 배웠습니다.

시간대 (timezone)의 예외 케이스를 조기에 테스트하세요. 2006년 이전의 인디애나주 출생 사례(당시에는 일광 절약 시간제(DST)를 적용하지 않음)에 대한 테스트를 작성해 보세요. 그 테스트를 통과한다면 아마 괜찮을 것입니다.

직접 시도해 보시고 의견을 남겨주세요!

계산기는 coppiastrale.it에서 실제로 작동 중입니다 (인터페이스는 이탈리아어이지만, 계산 로직은 누구에게나 적용됩니다). 에페메리스 (Ephemeris) 스택이나 점수 산정 알고리즘 (Scoring algorithm)에 대해 궁금한 점이 있다면 기꺼이 답변해 드리겠습니다.

AI 자동 생성 콘텐츠

본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0