-
Alo 재입고 알림봇 개발_1Dev🚀 2025. 9. 13. 15:20
🌱 개발 배경
- 평소에 사고 싶었던 상품인 Alo Yoga 'Seamless Delight High Neck Bra – White Heather / L'의 수시 재입고 타이밍을 놓치기 쉬워서, 자동 알림이 필요했다..🥹
- Alo는 Shopify 기반이라(공식 사이트가 Shopify Plus), 각 상품에 대해 변형(variant) 재고 여부를 공개 JSON으로 확인할 수 있음.(상품 상세 URL이 https://www.aloyoga.com/products/상품핸들?variant=숫자 형태 → 이건 Shopify 기본 패턴)
- 즉, L 사이즈(variant id: 43774160568500)가 available인지 바로 체크→ 텔레그램으로 알림 보내기 흐름이 깔끔해진다.
- /products/상품핸들.js로 요청을 보내면 상품 데이터를 JSON으로 내려주는 것도 Shopify 특징 중 하나.
👉 Alo 사이트가 Shopify라는 걸 확인했기 때문에 재고 크롤링 접근을 Shopify 방식으로 설계할 수 있었음.- 체크 방식 1: Shopify의 공개 JSON(/products/<handle>.js)에서 해당 variant의 available 플래그 확인
- 체크 방식 2(백업): 상품 페이지 HTML에서 “Out Of Stock!” 등 UI 신호로 보조 판별 (테마 변경 시 대비)
- 상태 변화(품절→구매가능 / 구매가능→품절) 시 텔레그램 알림 발송
🌟 판별 전략
1. Shopify 공개 상품 JSON
- https://www.aloyoga.com/ko-kr/products/.js
- variants[].id, variants[].available로 품절/구매가능 판별.
- Shopify JSON 응답에는 보통 이런 정보가 포함됨:
{ "id": 43774160568500, "title": "White Heather / L", "available": false }- 여기서 id = Variant ID, available = true/false → 이 값으로 바로 재고 상태를 확인할 수 있음.
- 하지만 JSON 요청이 차단(403)될 때가 있어서, 백업 방법으로 HTML을 파싱하는 fallback 로직도 추가:
- “품절”, “Sold Out” 같은 텍스트 탐색
- "Add to Cart" 버튼이 disabled인지 확인
- meta 태그 og:availability 값 (instock/oos) 확인
2. HTML 보조 판별 (fallback)
API 요청이 차단될 수 있으므로 BeautifulSoup를 활용해 HTML을 파싱하는 보조 로직도 구현했다. BeautifulSoup는 파이썬의 HTML 파싱 라이브러리로, DOM 트리를 탐색해 "품절" 텍스트나 버튼 상태 등을 쉽게 확인할 수 있다.
- 403 등으로 JSON이 막히면 페이지 HTML을 파싱해서 판별:
- script[type="application/ld+json"]의 offers.availability → InStock/OutOfStock
- 본문 텍스트에 Out of stock, Sold out, 품절, 재고 없음 등 키워드
- “Add to Bag/Add to Cart/장바구니 담기” 버튼의 disabled 여부
✔️ 코드 스니펫 (핵심 BeautifulSoup 로직)
from bs4 import BeautifulSoup import json, requests html = requests.get(product_url, headers=HEADERS, timeout=20).text soup = BeautifulSoup(html, "html.parser") text = soup.get_text(" ").lower() # 1) ld+json → availability for tag in soup.find_all("script", type="application/ld+json"): try: data = json.loads(tag.string or "{}") except Exception: continue arr = data if isinstance(data, list) else [data] for d in arr: if isinstance(d, dict): offers = d.get("offers") if isinstance(offers, dict): avail = str(offers.get("availability", "")).lower() if "instock" in avail: # InStock available = True if "outofstock" in avail: # OutOfStock available = False # 2) 텍스트 신호 if any(sig in text for sig in ["out of stock", "sold out", "품절", "재고 없음"]): available = False📍시행착오
- 403 Forbidden: GitHub Actions IP 대역이 막히는 경우가 많다 → 브라우저 User-Agent/Referer 헤더, 재시도(백오프), HTML fallback, 마지막으로 텍스트 프록시(r.jina.ai) 로 우회.
- 경로 인식 실수: Actions는 .github/workflows/*.yml 경로에 있어야 탭에 뜬다.
- 초기 알림: 최초 실행 때는 이전 상태가 없으므로 baseline 알림(현재 상태)이 1회 발송된다. 이후에는 상태 변화 시에만 알림.
반응형'Dev🚀' 카테고리의 다른 글
맥북 Self-hosted GitHub Actions Runner 설정 후 오류 수습..🧨 | (모든 파일 손상/인식 불가, iCloud 동기화 이상 문제) (0) 2025.09.16 Alo 재입고 알림봇 개발_5(Self-hosted runner) (0) 2025.09.13 Alo 재입고 알림봇 개발_4(HTML fallback 보강) (0) 2025.09.13 Alo 재입고 알림봇 개발_3 (0) 2025.09.13 Alo 재입고 알림봇 개발_2 (0) 2025.09.13