返回 Skills
nomadamas/k-skill· MIT 内容可用

fsc-corporate-info

금융위원회 기업기본정보(법인 개요)를 공공데이터포털 API(k-skill-proxy 경유)로 조회한다. 법인명으로 대표자·설립일·업종 등 법인 개요를 확인하고, 응답에 사업자번호가 있으면 입력 번호와 교차검증한다.

安装

与 skills.sh 相同的 Command / Prompt 安装方式


name: fsc-corporate-info description: 금융위원회 기업기본정보(법인 개요)를 공공데이터포털 API(k-skill-proxy 경유)로 조회한다. 법인명으로 대표자·설립일·업종 등 법인 개요를 확인하고, 응답에 사업자번호가 있으면 입력 번호와 교차검증한다. license: MIT metadata: category: business locale: ko-KR phase: v1

금융위 기업기본정보(법인 개요) 조회

What this skill does

공공데이터포털의 금융위원회_기업기본정보 서비스(data.go.kr 15043184, getCorpOutline_V2)를 k-skill-proxy 경유로 호출해 법인 개요를 조회한다.

  • 법인명(corpNm) 기준 후보 목록: 대표자·설립일·업종 등 upstream 필드 원문
  • 사업자번호 교차검증: 응답 item에 bzno가 있으면 입력 사업자번호와 정확 일치하는 후보를 분리한다 (bzno가 없으면 교차검증 불가 사실을 그대로 표기)

이 API의 검색 파라미터는 crno(법인등록번호 13자리)/corpNm(법인명)뿐이라 사업자번호 단독 조회가 불가하다. 법인명으로 조회한다.

Design principles

  • 점수·등급·해석 라벨을 만들지 않는다. upstream 사실 + 출처만 담는다.
  • crno(법인등록번호)는 사업자등록번호와 별개 번호임을 혼동하지 않는다.

When to use

  • "이 법인 대표자·설립일·업종 개요 확인해줘"
  • "법인명으로 기업 기본정보 조회해줘"

Prerequisites

  • 인터넷 연결, python3
  • scripts/fsc_corporate_info.py helper
  • hosted/self-host k-skill-proxy/v1/fsc/corp-outline route 접근 가능

Credential requirements

  • 사용자 측 필수 시크릿 없음.
  • KSKILL_PROXY_BASE_URL — self-host 프록시를 쓸 때만 설정. 비우면 hosted https://k-skill-proxy.nomadamas.org 사용.
  • DATA_GO_KR_API_KEY 는 프록시 운영 서버 환경에만 둔다. 공공데이터포털에서 금융위원회_기업기본정보 활용신청이 되어 있어야 한다.

Inputs

  • --name: 법인명(corpNm) — 필수
  • --b-no: 사업자등록번호. 응답에 bzno가 있을 때 교차검증에만 쓰인다.

CLI examples

python3 fsc-corporate-info/scripts/fsc_corporate_info.py \
  --name "삼성전자" --b-no 124-81-00998

Failure modes

  • 400 bad_request: 법인명을 주지 않음.
  • 503 upstream_not_configured: 프록시 서버에 DATA_GO_KR_API_KEY 없음.
  • 502 upstream_forbidden: 프록시 키가 15043184에 활용신청되지 않음.
  • 빈 결과: 법인명 불일치 — 표기를 바꿔 재시도.

Official surfaces

附带文件

scripts/fsc_corporate_info.py
"""FSC corporate-outline lookup via k-skill-proxy.

The proxy holds DATA_GO_KR_API_KEY server-side; this helper only builds the
query and reads the structured response. No user secret is required.
"""

from __future__ import annotations

import argparse
import json
import os
import re
import sys
import urllib.error
import urllib.parse
import urllib.request
from typing import Any

PROXY_BASE_URL_ENV_VAR = "KSKILL_PROXY_BASE_URL"
DEFAULT_PROXY_BASE_URL = "https://k-skill-proxy.nomadamas.org"
PROXY_DOWN_MSG = "설정된 k-skill-proxy 서버가 응답하지 않습니다. 잠시 후 재시도하거나 운영자에게 문의하세요."
PROXY_KEY_NOT_CONFIGURED_MSG = "k-skill-proxy에 필요한 API 키가 설정되어 있지 않습니다. 운영자에게 문의하세요."
ROUTE = "/v1/fsc/corp-outline"


class ApiError(RuntimeError):
    def __init__(self, message: str, *, status_code: int | None = None):
        super().__init__(message)
        self.status_code = status_code


def _text_or_none(value: Any) -> str | None:
    if value is None:
        return None
    text = str(value).strip()
    return text or None


def resolve_proxy_base_url(explicit: str | None = None, env: dict[str, str] | None = None) -> str:
    env = os.environ if env is None else env
    candidate = _text_or_none(explicit or env.get(PROXY_BASE_URL_ENV_VAR))
    if candidate and candidate.casefold() in {"off", "false", "0", "disable", "disabled", "none"}:
        raise ValueError("KSKILL_PROXY_BASE_URL 가 비활성화되어 있습니다.")
    if candidate and candidate != "replace-me":
        return candidate.rstrip("/")
    return DEFAULT_PROXY_BASE_URL


def read_json_response(request: urllib.request.Request) -> dict[str, Any]:
    try:
        with urllib.request.urlopen(request, timeout=30) as response:
            try:
                payload = json.loads(response.read().decode("utf-8"))
            except json.JSONDecodeError as error:
                raise ApiError("fsc corp-outline proxy returned invalid JSON.") from error
            if not isinstance(payload, dict):
                raise ApiError("fsc corp-outline proxy returned a non-object JSON payload.")
            return payload
    except urllib.error.HTTPError as error:
        body = error.read().decode("utf-8", errors="replace")
        try:
            payload = json.loads(body)
        except json.JSONDecodeError:
            payload = None
        if error.code == 503 and isinstance(payload, dict) and payload.get("error") == "upstream_not_configured":
            raise ApiError(PROXY_KEY_NOT_CONFIGURED_MSG, status_code=error.code) from error
        if isinstance(payload, dict) and payload.get("message"):
            raise ApiError(str(payload["message"]), status_code=error.code) from error
        raise ApiError(f"fsc corp-outline proxy request failed with HTTP {error.code}", status_code=error.code) from error
    except urllib.error.URLError as error:
        raise ApiError(f"{PROXY_DOWN_MSG} (상세: {error.reason})") from error


def query_corp_outline(name: str, b_no: str | None = None, *, base_url: str | None = None,
                       read_json: Any = read_json_response) -> dict[str, Any]:
    name = _text_or_none(name)
    if not name:
        raise ValueError("법인명(corpNm)을 입력하세요. 이 API는 사업자번호 단독 조회가 불가합니다.")
    params = {"name": name}
    if _text_or_none(b_no):
        digits = re.sub(r"\D", "", str(b_no))
        if not re.fullmatch(r"\d{10}", digits):
            raise ValueError("사업자등록번호는 숫자 10자리여야 합니다 (하이픈 허용).")
        params["b_no"] = digits
    url = f"{resolve_proxy_base_url(base_url)}{ROUTE}?{urllib.parse.urlencode(params)}"
    request = urllib.request.Request(url, headers={
        "Accept": "application/json",
        "User-Agent": "k-skill-fsc-corporate-info/1.0",
    }, method="GET")
    return read_json(request)


def build_parser() -> argparse.ArgumentParser:
    parser = argparse.ArgumentParser(description="금융위 기업기본정보(법인 개요) 조회 (k-skill-proxy 경유)")
    parser.add_argument("--name", required=True, help="법인명(corpNm) — 필수")
    parser.add_argument("--b-no", help="사업자등록번호 — 응답에 bzno가 있을 때 교차검증에만 사용")
    parser.add_argument("--proxy-base-url")
    return parser


def main(argv: list[str] | None = None) -> int:
    args = build_parser().parse_args(argv)
    try:
        result = query_corp_outline(args.name, args.b_no, base_url=args.proxy_base_url)
        print(json.dumps(result, ensure_ascii=False, indent=2))
        return 0
    except (ValueError, ApiError) as error:
        print(json.dumps({"error": str(error)}, ensure_ascii=False, indent=2), file=sys.stderr)
        return 1


if __name__ == "__main__":
    raise SystemExit(main())
    fsc-corporate-info | Prompt Minder