delivery-tracking
送り状番号をもとにCJ대한통운と우체국の荷物を公式キャリアエンドポイントで追跡し、後から他の配送業者へも拡張できるキャリアアダプター構造でワークフローを管理します。
description の原文を見る
Track CJ대한통운 and 우체국 parcels by invoice number with official carrier endpoints, and structure the workflow around a carrier adapter that can grow to more couriers later.
SKILL.md 本文
配送追跡
このスキルが行うこと
CJ대한통운と우체국の公式照会サーフェスを使用して、送状番号で現在の配送状態を照会する。
- CJ大韓通運: 公式配送照会ページが公開しているJSONエンドポイントを使用
- 郵便局: 公式配送照会ページが使用しているHTMLエンドポイントを使用
- 結果を共通形式(配送業者 / 送状番号 / 現在の状態 / 最近のイベント)に簡潔にまとめる
使用する場合
- 「CJ大韓通運の送状を確認してほしい」
- 「郵便局の荷物は今どこにあるか」
- 「この送状番号が配送完了か確認してほしい」
- 「配送業者別の照会ロジックを後で追加できるように整理してほしい」
使用しない場合
- 注文番号のみがあり送状番号がない場合
- 荷物の予約/返品受付まで直接行う必要がある場合
- 非公式統合配送照会サービスで迂回したい場合
前提条件
- インターネット接続
python3curl- オプション:
jq
入力
- 配送業者識別子:
cjまたはepost - 送状番号
- CJ大韓通運: 数字10桁または12桁
- 郵便局: 数字13桁
キャリアアダプタールール
このスキルは配送業者別のロジックをキャリアアダプタ単位で分割する。
新しい配送業者を追加する場合は、以下のフィールドを最初に定義する。
carrier id: 例)cj,epostvalidator: 送状番号桁数/パターンentrypoint: 公式照会進入URLtransport: JSON API / HTMLフォーム / CLIのどれを使うかparser: どのフィールドまたはテーブルから状態を抽出するかstatus map: 各配送業者の元の状態コードを共通状態にどのように変換するかretry policy: timeout/retry規則
現在のアダプタは以下の2つだ。
| キャリアアダプタ | 公式進入 | transport | validator | パーサーの焦点 |
|---|---|---|---|---|
cj | https://www.cjlogistics.com/ko/tool/parcel/tracking | ページGET + tracking-detail POST JSON | 10桁または12桁の数字 | parcelDetailResultMap.resultList |
epost | https://service.epost.go.kr/trace.RetrieveRegiPrclDeliv.postal?sid1= | フォームPOST HTML | 13桁の数字 | 基本情報 table_col + 詳細 processTable |
ワークフロー
0. まず入力を正規化する
- 配送業者名を
cj/epostのいずれかに正規化する。 - 送状番号からスペースと
-を削除する。 - 桁数検証が最初に失敗する場合は照会を送信しない。
1. CJ大韓通運: 公式JSONフロー
公式進入ページから _csrf を読み、その値を tracking-detail POSTに一緒に送信する。
- 進入ページ:
https://www.cjlogistics.com/ko/tool/parcel/tracking - 詳細エンドポイント:
https://www.cjlogistics.com/ko/tool/parcel/tracking-detail - 必須フィールド:
_csrf,paramInvcNo
基本的な例は curl で _csrf とcookieを保持し、PythonはJSON整理にのみ使用する。
tmp_body="$(mktemp)"
tmp_cookie="$(mktemp)"
tmp_json="$(mktemp)"
invoice="1234567890" # 公式ページのプレースホルダー的な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 sys
text = open(sys.argv[1], encoding="utf-8", errors="ignore").read()
print(re.search(r'name="_csrf" value="([^"]+)"', text).group(1))
PY
)"
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"
python3 - <<'PY' "$tmp_json"
import json
import sys
payload = json.load(open(sys.argv[1], encoding="utf-8"))
events = payload["parcelDetailResultMap"]["resultList"]
if not events:
raise SystemExit("조회 결과가 없습니다.")
status_map = {
"11": "상품인수",
"21": "상품이동중",
"41": "상품이동중",
"42": "배송지도착",
"44": "상품이동중",
"82": "배송출발",
"91": "배달완료",
}
latest = events[-1]
normalized_events = [
{
"timestamp": event.get("dTime"),
"location": event.get("regBranNm"),
"status_code": event.get("crgSt"),
"status": status_map.get(event.get("crgSt"), event.get("scanNm") or "알수없음"),
}
for event in events
]
print(json.dumps({
"carrier": "cj",
"invoice": payload["parcelDetailResultMap"]["paramInvcNo"],
"status_code": latest.get("crgSt"),
"status": status_map.get(latest.get("crgSt"), latest.get("scanNm") or "알수없음"),
"timestamp": latest.get("dTime"),
"location": latest.get("regBranNm"),
"event_count": len(events),
"recent_events": normalized_events[-min(3, len(normalized_events)):],
}, ensure_ascii=False, indent=2))
PY
rm -f "$tmp_body" "$tmp_cookie" "$tmp_json"
CJ公開出力例
以下の値は2026-03-27基準のliveSmoke test(1234567890)で確認した正規化結果である。
{
"carrier": "cj",
"invoice": "1234567890",
"status_code": "91",
"status": "배달완료",
"timestamp": "2026-03-21 12:22:13",
"location": "경기광주오포",
"event_count": 3,
"recent_events": [
{
"timestamp": "2026-03-10 03:01:45",
"location": "청원HUB",
"status_code": "44",
"status": "상품이동중"
},
{
"timestamp": "2026-03-21 10:53:19",
"location": "경기광주오포",
"status_code": "82",
"status": "배송출발"
},
{
"timestamp": "2026-03-21 12:22:13",
"location": "경기광주오포",
"status_code": "91",
"status": "배달완료"
}
]
}
追加のsmoke testには 000000000000 も使用できる。
CJ応答では parcelResultMap.resultList が空でも parcelDetailResultMap.resultList 側にイベントが入ることがあるため、詳細イベント配列を優先する。公開例は共通結果スキーマ(carrier, invoice, status, timestamp, location, event_count, recent_events, オプション status_code)に合わせて非識別フィールドのみを保持し、担当者名・連絡先が混在する可能性のある crgNm 元のテキストはそのまま表示しない。
2. 郵便局: 公式HTMLフロー
郵便局の公式entry pageは trace.RetrieveDomRigiTraceList.comm に sid1 をPOSTする構造だ。
- 進入ページ:
https://service.epost.go.kr/trace.RetrieveRegiPrclDeliv.postal?sid1= - 実際の照会エンドポイント:
https://service.epost.go.kr/trace.RetrieveDomRigiTraceList.comm - 必須フィールド:
sid1
郵便局はローカルPython HTTPクライアントより curl --http1.1 --tls-max 1.2 パスがより安定しているため、その組み合わせを基本例として使用する。
tmp_html="$(mktemp)"
python3 - <<'PY' "$tmp_html"
import html
import json
import re
import subprocess
import sys
invoice = "1234567890123" # 公式ページのプレースホルダー的なsmoke-test値
output_path = sys.argv[1]
cmd = [
"curl",
"--http1.1",
"--tls-max",
"1.2",
"--silent",
"--show-error",
"--location",
"--retry",
"3",
"--retry-all-errors",
"--retry-delay",
"1",
"--max-time",
"30",
"-o",
output_path,
"-d",
f"sid1={invoice}",
"https://service.epost.go.kr/trace.RetrieveDomRigiTraceList.comm",
]
subprocess.run(cmd, check=True)
page = open(output_path, encoding="utf-8", errors="ignore").read()
summary = re.search(
r"<th scope=\"row\">(?P<tracking>[^<]+)</th>.*?"
r"<td>(?P<sender>.*?)</td>.*?"
r"<td>(?P<receiver>.*?)</td>.*?"
r"<td>(?P<delivered_to>.*?)</td>.*?"
r"<td>(?P<kind>.*?)</td>.*?"
r"<td>(?P<result>.*?)</td>",
page,
re.S,
)
if not summary:
raise SystemExit("기본정보 테이블을 찾지 못했습니다.")
def clean(raw: str) -> str:
text = re.sub(r"<[^>]+>", " ", raw)
return " ".join(html.unescape(text).split())
def clean_location(raw: str) -> str:
text = clean(raw)
return re.sub(r"\s*(TEL\s*:?\s*)?\d{2,4}[.\-]\d{3,4}[.\-]\d{4}", "", text).strip()
events = re.findall(
r"<tr>\s*<td>(\d{4}\.\d{2}\.\d{2})</td>\s*"
r"<td>(\d{2}:\d{2})</td>\s*"
r"<td>(.*?)</td>\s*"
r"<td>\s*<span class=\"evtnm\">(.*?)</span>(.*?)</td>\s*</tr>",
page,
re.S,
)
normalized_events = [
{
"timestamp": f"{day} {time_}",
"location": clean_location(location),
"status": clean(status),
}
for day, time_, location, status, _detail in events
]
latest_event = normalized_events[-1] if normalized_events else None
print(json.dumps({
"carrier": "epost",
"invoice": clean(summary.group("tracking")),
"status": clean(summary.group("result")),
"timestamp": latest_event["timestamp"] if latest_event else None,
"location": latest_event["location"] if latest_event else None,
"event_count": len(normalized_events),
"recent_events": normalized_events[-min(3, len(normalized_events)):],
}, ensure_ascii=False, indent=2))
PY
rm -f "$tmp_html"
郵便局公開出力例
以下の値は2026-03-27基準のliveSmoke test(1234567890123)で確認した正規化結果である。
{
"carrier": "epost",
"invoice": "1234567890123",
"status": "배달완료",
"timestamp": "2025.12.04 15:13",
"location": "제주우편집중국",
"event_count": 2,
"recent_events": [
{
"timestamp": "2025.12.04 15:13",
"location": "제주우편집중국",
"status": "배달준비"
},
{
"timestamp": "2025.12.04 15:13",
"location": "제주우편집중국",
"status": "배달완료"
}
]
}
郵便局の基本情報テーブルは 登録番号, 送信者/受け取り日付, 受信者, 受け取り人/配送日付, 処理区分, 配送結果 の順序を使用し、詳細イベントは processTable 以下の 日付 / 時間 / 発生局 / 処理状況 行を読むとよい。公開例はCJと同じ共通結果スキーマ(carrier, invoice, status, timestamp, location, event_count, recent_events)に合わせて配送状態に必要な値のみを保持し、イベントlocationに混在する可能性のある TEL 番号フラグメントも削除した上で、受け取り人/詳細メモ元のテキストはそのまま公開しない。
3. 人間向けに正規化する
応答元のテキストをそのまま貼り付けず、以下の共通結果スキーマで要約する。
共通結果スキーマ
carrier: 配送業者識別子 (cjまたはepost)invoice: 正規化された送状番号status: 現在の配送状態timestamp: 最後のイベント時刻location: 最後のイベント位置event_count: 全イベント数recent_events: 最近の最大3つのイベントリストstatus_code: 必要な場合のみ保持する元の状態コード (現在はCJ例でのみ使用)
4. リトライとフォールバックポリシー
- 桁数エラーの場合は直ちに停止し、正しい形式を再度受け取る。
- CJは
_csrfを再取得した後、もう一度試みる。 - 郵便局は
curl --retry 3 --retry-all-errors --retry-delay 1を保持する。 - 他の配送業者に迂回しない。
完了条件
- 配送業者と送状番号が正しく識別されている
- 現在の状態と最近のイベントが整理されている
- どの公式サーフェスを使用したかを説明できる
- 他の配送業者拡張時にどのキャリアアダプタフィールドを追加する必要があるか記述されている
障害モード
- CJ:
_csrf抽出失敗またはtracking-detail応答スキーマ変更 - CJ: 送状番号の長さが10桁または12桁ではない
- 郵便局:
sid1が13桁ではない - 郵便局: HTMLマークアップ変更によりテーブル抽出ルールが破壊される
- 郵便局:
curlなしで他のクライアントで接続する場合、timeout/reset発生
注記
- 照会型スキルである。
- 基本サーフェスは公式キャリアエンドポイントのみを使用する。
- 他の配送業者の追加は、新しいキャリアアダプタ1つを同じ形式で追加する方式で拡張する。
ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- nomadamas
- リポジトリ
- nomadamas/k-skill
- ライセンス
- MIT
- 最終更新
- 不明
Source: https://github.com/nomadamas/k-skill / ライセンス: MIT
関連スキル
3-statement-model
3種類の財務諸表テンプレート(損益計算書、貸借対照表、キャッシュフロー計算書)を作成・記入・完成させることができます。モデルテンプレートの記入、既存のモデル枠組みの完成、財務モデルへのデータ入力、部分的に完成した損益/貸借/キャッシュフロー枠組みの完成、または既存テンプレート構造内での統合財務諸表の連携に対応しています。3種類の財務モデルテンプレートの記入、完成、またはデータ入力に関するご依頼で自動的に機能します。
strategic-decision
CEO・経営層向けの戦略的意思決定支援です。前提条件に異議を唱え、問題を診断し、確実な戦略を設計できます。4つのモード(AGGRESSIVE:大きな夢を見る、SELECTIVE:基盤を維持しつつ有望な拡張を厳選、DIAGNOSTIC:最大限の厳密性、VALIDATION:本質に絞る)を備えています。創業者、経営幹部、プロダクトリーダーが製品開発、成長戦略、市場戦略、技術選定、リソース配分に関する戦略的判断が必要な場面で活用できます。
value-realization
エンドユーザーが製品アイデアから明確な価値を感じるかどうかを分析します。以下の場面で活用できます:製品コンセプトの議論、機能の評価、製品改善の方向性提示、マーケティング戦略の企画、導入・継続率の問題分析、コピーが価値を伝えているかの検証、機能と利用シーンの対応付け、または製品方向性・ポジショニング・エンドユーザーの需要の有無が不確かな場合(例:「これは良いアイデアか」「この製品をどう思うか」「ユーザーは必要とするか」「この機能は何に役立つのか」「機能の価値をどう説明するか」「このコピーをどう思うか」「利用シーンを作成する手助けが欲しい」「ユーザーが継続利用しない理由は何か」「どうポジショニングすべきか」)。
creating-financial-models
このスキルは、投資判断に必要な高度な財務モデリング機能を提供します。DCF分析、感度分析、モンテカルロシミュレーション、シナリオプランニングなど、複数の分析手法を組み合わせることで、より正確で信頼性の高い財務予測が可能になります。
pestel-analysis
政治的、経済的、社会的、技術的、環境的、法的な外部要因を分析します。市場環境の変化が製品、ロードマップ、または戦略に大きな影響を与える可能性がある場合に活用できます。
chemical_safety_assessment
化学安全性評価 - 化学物質の安全性を評価します。PubChemの化合物情報、FDAの医薬品データ、ADMET予測、ChEMBLの構造警告を活用します。このスキルを使用することで、化合物名から一般情報を取得したり、医薬品名から警告および注意事項を取得したり、分子のADMETを予測したり、化合物の構造警告を検出したりできます。4つのSCPサーバーから4つのツールを統合しています。