이번엔 모바일 어플리케이션을 하나 만들어 보고 있는데,
여기에 지도를 넣어보고 싶더라구요, 그래서 Flutter_map을 한번 사용해 보았습니다.
flutter_map | Flutter package
Flutter's №1 non-commercially aimed map client: it's easy-to-use, versatile, vendor-free, fully cross-platform, and 100% pure-Flutter
pub.dev
근데 여기서 제가 원하는 장소에 마커를 넣고 싶은데..... 그것까진 지원 안하는거 같네요..!

제가 가지고 있는 데이터는 아래와 같은데... 이걸 하나하나 찍을수도 없고;;
"서울 강북구 도봉로"
"서울 강서구 강서로"
....
지도 라이브러리들은 대부분 주소가 아니라 위도와 경도를 필요로 하거든요.
데이터가 몇 개면 구글 지도 켜서 하나씩 찾겠는데, 1,000개가 넘는 걸 어케함..!
그래서 이번글은 Python을 이용해서 이 주소들을 좌표로 자동 변환(Geocoding) 하는 방법을 정리해 보려 합니다.
국내 주소에 강한 Kakao API와 글로벌 표준인 Google API 두 가지 방법을 모두 준비했으니, 상황에 맞게 골라 쓰세요!
그럼 바로 시작! (KAKAO)
한국 주소를 변환할 때는 카카오 API가 가장 정확도가 높아서 많이 사용한다고 하더라구요,
무료 사용량도 넉넉해서 굳굳
우선 API키부터 발급해줍시다.
아래사이트로!
Kakao Developers
카카오 API를 활용하여 다양한 어플리케이션을 개발해 보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다.
developers.kakao.com

--> Kakao API 키 발급받기!
먼저 카카오 개발자 사이트에서 키를 받아야 합니다.
- Kakao Developers 접속 및 로그인
- [내 애플리케이션] -> [애플리케이션 추가하기] 클릭

3. 앱이 생성되면 해당 앱을 클릭해서 들어갑니다.
4. [비즈앱 등록]를 누르고, 여기서 [REST API 키]를 복사해서 사용합니다.

API키를 발급받는 부분은 그렇게 어렵지 않았어요
키가 많았는데 각각 아래의 상황에서 사용한다고 합니다.


우리는 REST API만 사용할꺼라서, REST API키!
.... REST API...란?
REST API는 클라이언트(요청하는 쪽)와 서버(응답하는 쪽)가 대화하는 규칙입니다.
서로 말이 통하려면 약속된 언어와 방식이 필요한데, 웹(Web) 세상에서는 REST라는 방식을 가장 많이 씁니다
다음은 코드!
저는 데이터가 다음과 같은 형식이였습니다.
{
"name": "한국이동----------",
"address": "서울 ---------",
"phone": "",
"wins": {....
},
"likes": 0,
"dislikes": 0,
"lat": 0,
"lng": 0
},
코드는 아래처럼!
처음은 API키와 내가 변환시킬 데이터,
import requests
import json
import os
import time
# ==========================================
# [설정] 본인의 카카오 REST API 키를 입력하세요
KAKAO_API_KEY = "여기에_발급받은_REST_API_키"
# ==========================================
# 파일 경로 설정 (자신의 환경에 맞게 수정)
BASE_DIR = os.getcwd()
STORES_FILE = os.path.join(BASE_DIR, 'assets', 'data', 'stores.json')
그리고 변환을 담당할 get_lat_lng_from_kakao 함수를 구성해주었습니다.
def get_lat_lng_from_kakao(query):
""" 카카오 로컬 API를 사용하여 주소를 좌표(lat, lng)로 변환 """
url = 'https://dapi.kakao.com/v2/local/search/address.json'
headers = {"Authorization": f"KakaoAK {KAKAO_API_KEY}"}
params = {"query": query}
try:
response = requests.get(url, headers=headers, params=params, timeout=5)
if response.status_code == 200:
documents = response.json().get('documents', [])
if documents:
address_info = documents[0]
return float(address_info['y']), float(address_info['x'])
return None, None
except Exception as e:
print(f"❌ 에러: {e}")
return None, None
이어서는 이 전 과정에 대한 update_coordinates함수를 구성해 주었습니다.
def update_coordinates():
with open(STORES_FILE, 'r', encoding='utf-8') as f:
stores_list = json.load(f)
print(f"🚀 총 {len(stores_list)}개의 데이터 작업을 시작합니다.")
updated_count = 0
for idx, store in enumerate(stores_list):
address = store.get('address', '')
if (store.get('lat', 0) != 0) or "dhlottery" in address:
continue
print(f"[{idx+1}] 검색: {store['name']}", end="")
lat, lng = get_lat_lng_from_kakao(address)
if lat is None:
clean_address = address.split('(')[0].strip()
if clean_address != address:
print(f" ➡️ 재시도('{clean_address}')", end="")
lat, lng = get_lat_lng_from_kakao(clean_address)
if lat and lng:
store['lat'] = lat
store['lng'] = lng
updated_count += 1
print(" ✅ 성공")
else:
print(" ⚠️ 실패")
time.sleep(0.1) # API 제한 고려
# 100개마다 중간 저장
if updated_count % 100 == 0:
with open(STORES_FILE, 'w', encoding='utf-8') as f:
json.dump(stores_list, f, ensure_ascii=False, indent=2)
# 최종 저장
with open(STORES_FILE, 'w', encoding='utf-8') as f:
json.dump(stores_list, f, ensure_ascii=False, indent=2)
print("🎉 모든 작업 완료!")
if __name__ == "__main__":
update_coordinates()
중복제거와, 각 lat,lng값에 찾아온 위도경도값을 저장해주는 코드!
굳...
하지만.... 300개정도 실패!

아마 여기서는 괄호나 컴마 등 특수문자때문에 못찾은 것들일것 같긴한데....
이럴때 사용할 수 있는건 구글!
그럼 다시 시작! (GOOGLE)
구글에서는 이럴때 Geocoding API라는 서비스를 사용할 수 있더라구요,
Fluter_map말고 얘쓰면 모든게 해결되지만... 전 돈이 흑흑

그래서 위도경도만 반환받을때 사용해주겠습니다. (이정도는 무료인듯...? 하네여)
일단 클라우드를 처음시작하시면, 아마 프로젝트 만들기가뜰텐데, 만드시

이렇게 만들어졌으면 상단에서 검색

api 사용을 눌러주시면 되는데 아마, 결제관련 등록을 해야 사용할 수 있는...
위도와 경도정도면 유료로 결제안되니까, 그냥 해주시면 아마 바로 api key가 나올겁니다.
그거 들고 코드로 ㄱㄱ!
# ==========================================
GOOGLE_API_KEY = "여기에_구글_API_키"
# ==========================================
def get_lat_lng_from_google(query):
""" 구글 Geocoding API를 사용하여 주소를 좌표로 변환 """
url = "https://maps.googleapis.com/maps/api/geocode/json"
# 구글은 헤더가 아니라 params에 key를 넣습니다.
params = {
"address": query,
"key": GOOGLE_API_KEY,
"language": "ko" # 한국어 결과 우선
}
try:
response = requests.get(url, params=params, timeout=5)
if response.status_code == 200:
result = response.json()
# 결과가 있는지 확인 ('OK' 상태이고 결과 리스트가 비어있지 않아야 함)
if result.get('status') == 'OK' and result.get('results'):
location = result['results'][0]['geometry']['location']
return float(location['lat']), float(location['lng'])
else:
return None, None
else:
print(f"❌ API 요청 실패: {response.status_code}")
return None, None
except Exception as e:
print(f"❌ 에러 발생: {e}")
return None, None
코드는 위의 카카오 코드 전체에서 get_lat_lng_from_kakao 함수를 지우고,
이 get_lat_lng_from_google 함수를 넣은 뒤 호출 부분만 바꿔주면 끝!
저처럼 중복제거 코드가 필요하다면
아래로...
히
import requests
import json
import os
import time
# ==========================================
# [설정] 본인의 Google Maps API 키를 입력하세요
GOOGLE_API_KEY = "mine"
# ==========================================
# --- 파일 경로 설정 ---
BASE_DIR = os.getcwd()
DATA_DIR = os.path.join(BASE_DIR, 'assets', 'data')
STORES_FILE = os.path.join(DATA_DIR, 'stores.json')
def clean_address_string(address):
"""
주소 정제 로직:
1. '(' 뒷부분 제거
2. ',' 뒷부분 제거
3. 앞뒤 공백 제거
"""
# '(' 기준으로 자르고 첫 번째 부분 선택
addr = address.split('(')[0]
# ',' 기준으로 자르고 첫 번째 부분 선택
addr = addr.split(',')[0]
return addr.strip()
def get_lat_lng_google(address):
"""
Google Geocoding API를 사용하여 주소를 좌표로 변환
"""
base_url = "https://maps.googleapis.com/maps/api/geocode/json"
params = {
"address": address,
"key": GOOGLE_API_KEY,
"language": "ko" # 한국어 결과 우선
}
try:
response = requests.get(base_url, params=params, timeout=10)
if response.status_code == 200:
result = response.json()
if result['status'] == 'OK':
location = result['results'][0]['geometry']['location']
return location['lat'], location['lng']
else:
# ZERO_RESULTS, OVER_QUERY_LIMIT 등
# print(f" API 상태: {result['status']}")
return None, None
else:
print(f"❌ HTTP 요청 실패: {response.status_code}")
return None, None
except Exception as e:
print(f"❌ 에러 발생: {e}")
return None, None
def update_missing_coordinates():
print("🚀 Google Maps API로 누락된 좌표 보완을 시작합니다...")
if not os.path.exists(STORES_FILE):
print(f"❌ {STORES_FILE} 파일이 없습니다.")
return
# 1. 파일 읽기
with open(STORES_FILE, 'r', encoding='utf-8') as f:
stores_list = json.load(f)
total_count = len(stores_list)
updated_count = 0
skipped_count = 0 # 이미 있거나 온라인이라 건너뛴 것
failed_count = 0
print(f"📊 총 {total_count}개의 데이터를 스캔합니다.")
# 2. 순회
for idx, store in enumerate(stores_list):
address = store.get('address', '')
current_lat = store.get('lat', 0.0)
current_lng = store.get('lng', 0.0)
# [조건 1] 온라인 판매점 제외
if "dhlottery.co.kr" in address or "동행복권" in address:
skipped_count += 1
continue
# [조건 2] 이미 좌표가 있는 경우 건너뜀 (0.0이 아닌 경우)
if current_lat != 0.0 and current_lng != 0.0:
skipped_count += 1
continue
# --- 여기서부터는 좌표가 없는(0.0) 데이터입니다 ---
# [정제] 주소 클리닝 (괄호, 콤마 제거)
clean_addr = clean_address_string(address)
print(f"[{idx+1}/{total_count}] 보완 시도: {clean_addr} (원본: {address}) ... ", end="")
lat, lng = get_lat_lng_google(clean_addr)
if lat is not None and lng is not None:
store['lat'] = lat
store['lng'] = lng
updated_count += 1
print(f"✅ 성공 ({lat}, {lng})")
else:
failed_count += 1
print(f"⚠️ 실패")
# Google API도 짧은 시간 과다 요청 시 제한될 수 있음
time.sleep(0.1)
# 중간 저장 (데이터 보호)
if updated_count > 0 and updated_count % 50 == 0:
with open(STORES_FILE, 'w', encoding='utf-8') as f:
json.dump(stores_list, f, ensure_ascii=False, indent=2)
print(" 💾 중간 저장 완료")
# 3. 최종 저장
with open(STORES_FILE, 'w', encoding='utf-8') as f:
json.dump(stores_list, f, ensure_ascii=False, indent=2)
print("\n" + "="*50)
print(f"🎉 작업 완료!")
print(f" - 총 스캔: {total_count}")
print(f" - 신규 성공: {updated_count}")
print(f" - 건너뜀(기존존재/온라인): {skipped_count}")
print(f" - 최종 실패: {failed_count}")
print(f" - 파일 저장: {STORES_FILE}")
print("="*50)
if __name__ == "__main__":
if GOOGLE_API_KEY == "YOUR_GOOGLE_MAPS_API_KEY":
print("❌ 오류: GOOGLE_API_KEY 변수에 실제 키를 입력해주세요.")
else:
update_missing_coordinates()
굳

여기까지 위도경도.... 반환받기 끝!
이제 좌표 데이터도 준비되었으니, 마커만 만들러 가면 되겠네여
틀린점이 있다면 댓 달아주세요!

'나의 공부공부 > 2025 쌓아가는 나의 지식~' 카테고리의 다른 글
| [App 개발] Android Studio 및 Flutte 환경 구축 (0) | 2025.12.30 |
|---|---|
| [Error] 안티그래비티(Antigravity) UTF-8 오류 해결 (0) | 2025.12.29 |
| [구글 검색] 구글 서치 콘솔 페이지 색인 생성 자동화 (Python) (6) | 2025.11.25 |
| [Python] OpenGL을 이용한 BVH 모션 파일 시각화 + 모션 트라젝토리 (0) | 2025.11.10 |
| [Python] OpenGL에서의 카메라 이동 및 상호작용 구현 (0) | 2025.11.07 |