mirror of
https://github.com/NomaDamas/k-skill.git
synced 2026-06-24 02:04:11 +00:00
Keep parcel-tracking guidance aligned with the verified carrier flows
The delivery-tracking skill already existed on feature/#4, but the CJ example still documented a naive Python HTTP path. This follow-up switches the documented CJ flow to the verified curl+cookie+_csrf sequence, then tightens the surrounding docs so the shipped scope and future carrier-extension story stay consistent. Constraint: CJ tracking-detail rejects naive direct HTTP calls without preserved session state Constraint: Must keep the existing feature/#4 PR against dev accurate without widening scope Rejected: Keep the urllib-only CJ example | live smoke test returned 403 and contradicted the docs Confidence: high Scope-risk: narrow Directive: Re-run live carrier smoke tests before changing documented transport steps for CJ or 우체국 Tested: npm run ci; live CJ curl+cookie+_csrf verification for 1234567890; live 우체국 curl verification for 1234567890123 Not-tested: Real non-placeholder customer waybills
This commit is contained in:
parent
4a4ab95541
commit
3c6a7d2e51
5 changed files with 71 additions and 48 deletions
|
|
@ -24,7 +24,7 @@ Claude code, codex, opencode 등 각종 코딩 에이전트 지원합니다.
|
|||
| 로또 당첨 확인 | 최신 회차, 특정 회차, 번호 대조 | 불필요 | [로또 결과 가이드](docs/features/lotto-results.md) |
|
||||
| HWP 문서 처리 | `.hwp` → JSON/Markdown/HTML 변환, 이미지 추출, 배치 처리, Windows 직접 제어 선택 | 불필요 | [HWP 문서 처리 가이드](docs/features/hwp.md) |
|
||||
| 우편번호 검색 | 주소 키워드로 공식 우체국 우편번호 조회 | 불필요 | [우편번호 검색 가이드](docs/features/zipcode-search.md) |
|
||||
| 택배 배송조회 | CJ대한통운·우체국 공식 표면으로 배송 상태 조회 | 불필요 | [택배 배송조회 가이드](docs/features/delivery-tracking.md) |
|
||||
| 택배 배송조회 | CJ대한통운·우체국 공식 표면으로 배송 상태를 조회하고, carrier adapter 규칙으로 추가 택배사 확장을 준비 | 불필요 | [택배 배송조회 가이드](docs/features/delivery-tracking.md) |
|
||||
|
||||
> 참고: **KTX 예매는 현재 작동하지 않습니다.**
|
||||
|
||||
|
|
|
|||
|
|
@ -82,36 +82,40 @@ CJ대한통운과 우체국 공식 조회 표면을 사용해 송장 번호로
|
|||
- 상세 endpoint: `https://www.cjlogistics.com/ko/tool/parcel/tracking-detail`
|
||||
- 필수 필드: `_csrf`, `paramInvcNo`
|
||||
|
||||
기본 예시는 Python 표준 라이브러리만 사용한다.
|
||||
기본 예시는 `curl` 로 `_csrf` 와 cookie를 유지하고, Python은 JSON 정리에만 쓴다.
|
||||
|
||||
```bash
|
||||
python3 - <<'PY'
|
||||
import json
|
||||
tmp_body="$(mktemp)"
|
||||
tmp_cookie="$(mktemp)"
|
||||
tmp_json="$(mktemp)"
|
||||
invoice="1234567890" # 공식 페이지 placeholder 성격의 smoke-test 값
|
||||
|
||||
curl -sS -L -c "$tmp_cookie" \
|
||||
"https://www.cjlogistics.com/ko/tool/parcel/tracking" \
|
||||
-o "$tmp_body"
|
||||
|
||||
csrf="$(python3 - <<'PY' "$tmp_body"
|
||||
import re
|
||||
import urllib.parse
|
||||
import urllib.request
|
||||
import sys
|
||||
|
||||
invoice = "1234567890" # 공식 페이지 placeholder 성격의 smoke-test 값
|
||||
landing = urllib.request.urlopen(
|
||||
"https://www.cjlogistics.com/ko/tool/parcel/tracking",
|
||||
timeout=20,
|
||||
).read().decode("utf-8", "ignore")
|
||||
csrf = re.search(r'name="_csrf" value="([^"]+)"', landing).group(1)
|
||||
text = open(sys.argv[1], encoding="utf-8", errors="ignore").read()
|
||||
print(re.search(r'name="_csrf" value="([^"]+)"', text).group(1))
|
||||
PY
|
||||
)"
|
||||
|
||||
payload = urllib.parse.urlencode({
|
||||
"_csrf": csrf,
|
||||
"paramInvcNo": invoice,
|
||||
}).encode()
|
||||
curl -sS -L -b "$tmp_cookie" \
|
||||
-H "Content-Type: application/x-www-form-urlencoded; charset=UTF-8" \
|
||||
--data-urlencode "_csrf=$csrf" \
|
||||
--data-urlencode "paramInvcNo=$invoice" \
|
||||
"https://www.cjlogistics.com/ko/tool/parcel/tracking-detail" \
|
||||
-o "$tmp_json"
|
||||
|
||||
request = urllib.request.Request(
|
||||
"https://www.cjlogistics.com/ko/tool/parcel/tracking-detail",
|
||||
data=payload,
|
||||
headers={"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"},
|
||||
)
|
||||
response = urllib.request.urlopen(request, timeout=20)
|
||||
data = json.loads(response.read().decode("utf-8"))
|
||||
python3 - <<'PY' "$tmp_json"
|
||||
import json
|
||||
import sys
|
||||
|
||||
events = data["parcelDetailResultMap"]["resultList"]
|
||||
payload = json.load(open(sys.argv[1], encoding="utf-8"))
|
||||
events = payload["parcelDetailResultMap"]["resultList"]
|
||||
if not events:
|
||||
raise SystemExit("조회 결과가 없습니다.")
|
||||
|
||||
|
|
@ -128,7 +132,7 @@ status_map = {
|
|||
latest = events[-1]
|
||||
print(json.dumps({
|
||||
"carrier": "cj",
|
||||
"invoice": invoice,
|
||||
"invoice": payload["parcelDetailResultMap"]["paramInvcNo"],
|
||||
"status_code": latest.get("crgSt"),
|
||||
"status": status_map.get(latest.get("crgSt"), latest.get("scanNm") or "알수없음"),
|
||||
"timestamp": latest.get("dTime"),
|
||||
|
|
@ -137,6 +141,8 @@ print(json.dumps({
|
|||
"event_count": len(events),
|
||||
}, ensure_ascii=False, indent=2))
|
||||
PY
|
||||
|
||||
rm -f "$tmp_body" "$tmp_cookie" "$tmp_json"
|
||||
```
|
||||
|
||||
추가 smoke test 로는 `000000000000` 도 사용할 수 있다.
|
||||
|
|
|
|||
|
|
@ -37,28 +37,38 @@
|
|||
- 파라미터: `_csrf`, `paramInvcNo`
|
||||
|
||||
```bash
|
||||
python3 - <<'PY'
|
||||
import json
|
||||
tmp_body="$(mktemp)"
|
||||
tmp_cookie="$(mktemp)"
|
||||
tmp_json="$(mktemp)"
|
||||
invoice="1234567890"
|
||||
|
||||
curl -sS -L -c "$tmp_cookie" \
|
||||
"https://www.cjlogistics.com/ko/tool/parcel/tracking" \
|
||||
-o "$tmp_body"
|
||||
|
||||
csrf="$(python3 - <<'PY' "$tmp_body"
|
||||
import re
|
||||
import urllib.parse
|
||||
import urllib.request
|
||||
import sys
|
||||
text = open(sys.argv[1], encoding="utf-8", errors="ignore").read()
|
||||
print(re.search(r'name="_csrf" value="([^"]+)"', text).group(1))
|
||||
PY
|
||||
)"
|
||||
|
||||
invoice = "1234567890"
|
||||
landing = urllib.request.urlopen(
|
||||
"https://www.cjlogistics.com/ko/tool/parcel/tracking",
|
||||
timeout=20,
|
||||
).read().decode("utf-8", "ignore")
|
||||
csrf = re.search(r'name="_csrf" value="([^"]+)"', landing).group(1)
|
||||
curl -sS -L -b "$tmp_cookie" \
|
||||
-H "Content-Type: application/x-www-form-urlencoded; charset=UTF-8" \
|
||||
--data-urlencode "_csrf=$csrf" \
|
||||
--data-urlencode "paramInvcNo=$invoice" \
|
||||
"https://www.cjlogistics.com/ko/tool/parcel/tracking-detail" \
|
||||
-o "$tmp_json"
|
||||
|
||||
body = urllib.parse.urlencode({"_csrf": csrf, "paramInvcNo": invoice}).encode()
|
||||
request = urllib.request.Request(
|
||||
"https://www.cjlogistics.com/ko/tool/parcel/tracking-detail",
|
||||
data=body,
|
||||
headers={"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"},
|
||||
)
|
||||
payload = json.loads(urllib.request.urlopen(request, timeout=20).read().decode("utf-8"))
|
||||
python3 - <<'PY' "$tmp_json"
|
||||
import json
|
||||
import sys
|
||||
payload = json.load(open(sys.argv[1], encoding="utf-8"))
|
||||
print(json.dumps(payload["parcelDetailResultMap"]["resultList"][-1], ensure_ascii=False, indent=2))
|
||||
PY
|
||||
|
||||
rm -f "$tmp_body" "$tmp_cookie" "$tmp_json"
|
||||
```
|
||||
|
||||
CJ는 JSON 응답이므로 `parcelDetailResultMap.resultList` 를 기준으로 상태를 읽는 편이 가장 안정적이다.
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
- 로또 당첨번호
|
||||
- 서울 지하철 도착 정보
|
||||
- 우편번호 검색
|
||||
- 택배 배송조회 스킬 출시
|
||||
- 택배 배송조회 스킬 출시 (CJ대한통운 / 우체국)
|
||||
|
||||
## v1.5 candidates
|
||||
|
||||
|
|
@ -56,6 +56,11 @@
|
|||
- 장점: 사전 접수, 주변 병원 찾기, 지금 문 연 병원 찾기 흐름이 명확하다
|
||||
- 이유: 실사용 가치가 높고 특히 부모층 체감이 크다
|
||||
|
||||
#### 택배 예약 / 추가 택배사 확장
|
||||
|
||||
- 장점: 기본 배송조회는 `delivery-tracking` 으로 선출시했고, 다음 단계는 예약/반품/추가 택배사 확장으로 자연스럽게 이어진다
|
||||
- 이유: 한국 생활에서 반복 빈도가 높은 작업이라 조회 다음 액션까지 묶을 가치가 크다
|
||||
|
||||
#### 미세먼지/황사/대기질 알림
|
||||
|
||||
- 장점: 오늘/내일/모레 대기정보와 예보, 하루 4회 수준의 예보 갱신 같은 한국형 수요에 잘 맞는다
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@
|
|||
- 서울특별시 지하철 실시간 도착정보: https://www.data.go.kr/data/15058052/openapi.do
|
||||
- 우체국 도로명주소 검색: https://parcel.epost.go.kr/parcel/comm/zipcode/comm_newzipcd_list.jsp
|
||||
- CJ대한통운 배송조회: https://www.cjlogistics.com/ko/tool/parcel/tracking
|
||||
- CJ대한통운 배송상세 JSON: https://www.cjlogistics.com/ko/tool/parcel/tracking-detail
|
||||
- 우체국 배송조회: https://service.epost.go.kr/trace.RetrieveRegiPrclDeliv.postal?sid1=
|
||||
- 우체국 배송상세 HTML: https://service.epost.go.kr/trace.RetrieveDomRigiTraceList.comm
|
||||
- SOPS docs: https://getsops.io/docs/
|
||||
- age: https://github.com/FiloSottile/age
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue