Spaces:
Sleeping
Sleeping
| # -*- coding: utf-8 -*- | |
| import asyncio | |
| import httpx | |
| import json | |
| import os | |
| from typing import Dict, Any, List | |
| async def check_url_live(client: httpx.AsyncClient, code: str, url: str, semaphore: asyncio.Semaphore) -> Dict[str, Any]: | |
| """๋จ์ผ URL์ ๋ํด ์ธ๋งํฌ์ด ์ ์ด ํ์ HEAD ์์ฒญ์ ๋น๋๊ธฐ ์คํํฉ๋๋ค.""" | |
| async with semaphore: | |
| try: | |
| # HEAD ์์ฒญ์ผ๋ก ๋์ญํญ์ ์ ์ฝํ๊ณ ์ ์ํ ์๋ต ์ฝ๋๋ง ๊ฒ์ฌ | |
| response = await client.head(url, timeout=5.0, follow_redirects=True) | |
| status_code = response.status_code | |
| is_live = (200 <= status_code < 400) | |
| return {"code": code, "url": url, "is_live": is_live, "status": status_code} | |
| except httpx.HTTPError as e: | |
| return {"code": code, "url": url, "is_live": False, "status": "HTTPError", "error": str(e)} | |
| except Exception as e: | |
| return {"code": code, "url": url, "is_live": False, "status": "Error", "error": str(e)} | |
| async def run_mappings_purification(mappings_filepath: str, output_filepath: str): | |
| """mappings.json์ ๋ก๋ํ๊ณ ์์กด ์ฌ๋ถ๋ฅผ ์ ์ ๊ฒ์ฌํ์ฌ ๊นจ์ง ๋งํฌ๊ฐ ์ ๊ฑฐ๋ ๋ฌด๊ฒฐ์ฑ ๋งต์ ์ ์ฅํฉ๋๋ค.""" | |
| if not os.path.exists(mappings_filepath): | |
| print(f"์ค๋ฅ: ๋งคํ ํ์ผ์ด ์์ต๋๋ค. ({mappings_filepath})") | |
| return | |
| with open(mappings_filepath, 'r', encoding='utf-8') as f: | |
| data = json.load(f) | |
| url_mapping = data.get("url_mapping", {}) | |
| if not url_mapping: | |
| print("์ ํํ url_mapping ํ๋๊ฐ ๋น์ด ์์ต๋๋ค.") | |
| return | |
| print(f"์ด {len(url_mapping)}๊ฐ์ ์ถ์ URL ๋น๋๊ธฐ ์์กด ์ฌ๋ถ ์ ์ ๊ฒ์ฆ ์์...") | |
| # ์๋์ฐ ํ๊ฒฝ ์์ผ ๊ณผ๋ถํ ๋ฐ ์๋ฒ ์ฐจ๋จ ๋ฐฉ์ง๋ฅผ ์ํ ๋์์ฑ ์ ์ ์ด (Semaphore 20 ์ ํ) | |
| semaphore = asyncio.Semaphore(20) | |
| # ๋ชจ๋ฐ์ผ ํด๋ผ์ด์ธํธ User-Agent๋ฅผ ์ค์ ํ์ฌ ๋ด ์ฐจ๋จ ์ฐํ | |
| headers = { | |
| "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" | |
| } | |
| cleaned_url_mapping = {} | |
| verified_count = 0 | |
| dead_count = 0 | |
| async with httpx.AsyncClient(headers=headers, verify=False) as client: | |
| tasks = [] | |
| for code, url in url_mapping.items(): | |
| tasks.append(check_url_live(client, code, url, semaphore)) | |
| # ๋น๋๊ธฐ ๋ณ๋ ฌ ๋๊ธฐ ๋ฐ ํ๋ก๊ทธ๋์ค ํธ๋ํน | |
| results = await asyncio.gather(*tasks) | |
| for res in results: | |
| code = res["code"] | |
| url = res["url"] | |
| if res["is_live"]: | |
| cleaned_url_mapping[code] = url | |
| verified_count += 1 | |
| else: | |
| dead_count += 1 | |
| # [๊ฐ์ ์] ๊นจ์ง ๋งํฌ๋ ๊ณต์ KCSC ๋ฉ์ธ ๊ฒ์ ํ์ด์ง ๋ฑ์ ์์ ์ง๋๋ก ํฌ์๋ฉ ์ฌ๋งคํ | |
| cleaned_url_mapping[code] = "https://www.kcsc.re.kr/Standard/Portal" | |
| # ์๋ณธ ํ์ผ ๋ฐฑ์ ๋ฐ ์ ํ๋ mappings_clean.json ์ ์ฅ | |
| data["url_mapping"] = cleaned_url_mapping | |
| # ํต๊ณ ๋ฐ ๋ฆฌํฉํ ๋ง ์ ๋ณด ์ ์ฌ ์ ์์ธ ๋ฐฉ์ง ์์ ์กฐ์น | |
| if "metadata" not in data: | |
| data["metadata"] = {} | |
| if "statistics" not in data["metadata"]: | |
| data["metadata"]["statistics"] = {} | |
| data["metadata"]["statistics"]["verified_urls"] = verified_count | |
| data["metadata"]["statistics"]["estimated_urls"] = len(url_mapping) - verified_count | |
| data["metadata"]["last_purified"] = "" | |
| # ๋ก์ปฌ ์๊ฐ ๋๋ timezone ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ฐ๋น์ง ์์ด ๋ฌด๋ํ API๋ก๋ถํฐ ์๊ฐ์ ๋ฐ๊ฑฐ๋ ๋ก์ปฌ ์๊ฐ์ผ๋ก ์ฒ๋ฆฌ | |
| try: | |
| response = httpx.get("http://worldtimeapi.org/api/ip", timeout=3.0) | |
| data["metadata"]["last_purified"] = response.json().get("datetime", "") | |
| except Exception: | |
| import datetime | |
| data["metadata"]["last_purified"] = datetime.datetime.now().isoformat() | |
| with open(output_filepath, 'w', encoding='utf-8') as f: | |
| json.dump(data, f, ensure_ascii=False, indent=2) | |
| print(f"\n===== Mappings ์ ํ ์๋ฃ ์์ฝ =====") | |
| print(f" * ๊ฒ์ฆ ์์กดํ ์ ํจ URL : {verified_count} ๊ฐ") | |
| print(f" * ๊นจ์ง ์ถ์ URL ์ฐํ : {dead_count} ๊ฐ (์์ ์ฃผ์๋ก ๋ฆฌ๋ค์ด๋ ํธ ์๋ฃ)") | |
| print(f" * ์ ํ๋ ๋งคํ ์ ์ฅ ์๋ฃ : {output_filepath}") | |