"""TourAPI 에 사진이 없는 주변 맛집에 네이버 이미지 검색으로 찾은 사진을 받아 둔다. ★ 왜 (2026-09-11, 사장님: "이미지가 없어?? 좀 가져와봐" · "다운로드 하던가") fetch_restaurants.py 가 붙인 23곳 중 11곳은 TourAPI(위치 목록·추가 이미지·키워드 검색)와 위키미디어 어디에도 사진이 없었다. 레일에 이름 활자 카드가 11장 섞였다. ★ ⚠ 이 사진들은 공공누리가 아니다. 대한민국 구석구석·군산시청·블로그·네이버 플레이스에 올라온 것이고 권리는 각 게시자에게 있다. **시연본에만 쓴다 — 제품 수집 파이프라인으로 옮기지 않는다.** 제품의 규칙은 그대로 공공누리 Type1·Type3 뿐이다(tour_api._COMMERCIAL_OK_LICENSES). ★ 한 장씩 눈으로 보고 골랐다 — 간판이 보이거나 게시물 제목에 그 가게 이름이 있는 것만. 이름만 같은 다른 집(거목아리랑 · 국일복아구)은 버렸다. 출처 주소는 restaurant-photos.json 에 남긴다. ★ 긴 변 1600px 로 줄인다 — 원본이 10MB 인 것도 있다. 작은 사진은 키우지 않는다. 실행: python3 fill_restaurant_photos.py (macOS `sips` 로 줄인다) 굽기(patch_stay.py)는 여기서 받아 둔 파일만 읽는다 — 사진이 없는 집에만 덧대고, TourAPI 사진이 있으면 그쪽이 먼저다. """ import hashlib import json import re import subprocess import urllib.request from pathlib import Path SP = Path(__file__).resolve().parent LIST = SP / "restaurant-photos.json" MAX_SIDE = 1600 photos = json.loads(LIST.read_text(encoding="utf-8")) for name, ph in photos.items(): file = hashlib.sha1(ph["url"].encode()).hexdigest()[:16] + ".jpg" path = SP / "img" / "mirror" / file if not path.exists(): src = path.with_suffix(".src") req = urllib.request.Request(ph["url"], headers={"User-Agent": "Mozilla/5.0", "Referer": "https://search.naver.com/"}) src.write_bytes(urllib.request.urlopen(req, timeout=30).read()) dims = subprocess.run(["sips", "-g", "pixelWidth", "-g", "pixelHeight", str(src)], capture_output=True, text=True, check=True).stdout side = max(int(v) for v in re.findall(r"pixel(?:Width|Height): (\d+)", dims)) cmd = ["sips", "-s", "format", "jpeg", "-s", "formatOptions", "80"] if side > MAX_SIDE: cmd += ["-Z", str(MAX_SIDE)] subprocess.run(cmd + [str(src), "--out", str(path)], capture_output=True, check=True) src.unlink() ph["file"] = file print(f" {name:<8} {path.stat().st_size // 1024:>5}KB {file}") LIST.write_text(json.dumps(photos, ensure_ascii=False, indent=1) + "\n", encoding="utf-8") print(f"restaurant-photos.json · {len(photos)}곳")