
Danawa Price Search
Compare Korean retail prices on Danawa during product or competitor research without leaving your agent session.
Overview
Danawa Price Search is an agent skill for the Idea phase that queries Danawa for product listings and seller offers for Korean price comparison.
Install
npx skills add https://github.com/nomadamas/k-skill --skill danawa-price-searchWhat is this skill?
- Three CLI modes: search, offers (by product code), and compare with configurable limits
- Read-only HTML fetch and parse via BeautifulSoup against Danawa listing pages
- Structured JSON-oriented workflow for Hermes-style agent price lookups
- Korean locale headers and query encoding for reliable Danawa requests
- Three subcommands: search, offers, compare
Adoption & trust: 651 installs on skills.sh; 5.4k GitHub stars; 3/3 security scanners passed (skills.sh audits).
What problem does it solve?
You need current Korean retail price ranges for a product name or code but do not want ad-hoc scraping or copy-paste from comparison sites.
Who is it for?
Solo builders researching Korean consumer electronics or ecommerce pricing with a scriptable, read-only Danawa workflow.
Skip if: Teams that need official APIs, non-Korean markets, purchase automation, or production-grade scraping compliance review out of the box.
When should I use this skill?
You need Danawa search results, per-product seller offers, or a combined search-and-offers compare pass for Korean pricing research.
What do I get? / Deliverables
After running search, offers, or compare, you get normalized listing and offer data your agent can cite while scoping or validating a build.
- Structured search and offer data from Danawa CLI output
- Compared product shortlists with multiple mall offers
Recommended Skills
Journey fit
Price and offer discovery belongs in early research before you commit to what to build or how to price it. Danawa search and compare output directly supports market and competitor pricing research shelves in Idea.
How it compares
Use for targeted Danawa lookups instead of generic web-search price guesses that lack mall-level offer detail.
Common Questions / FAQ
Who is danawa-price-search for?
Indie builders and agent workflows (e.g. Hermes) that compare Korean retail prices during research or validation.
When should I use danawa-price-search?
During Idea research when comparing SKUs, during Validate pricing checks for hardware or consumer goods, or whenever you need Danawa search, offers, or compare output in JSON-friendly form.
Is danawa-price-search safe to install?
It performs read-only HTTP fetches to Danawa; review the Security Audits panel on this page and respect site terms before automating requests.
SKILL.md
READMESKILL.md - Danawa Price Search
#!/usr/bin/env python3 """Read-only Danawa search/price comparison helper for Hermes. Usage: python scripts/danawa_search.py search "에어팟 프로 2세대" --limit 8 python scripts/danawa_search.py offers 28208783 --limit 10 python scripts/danawa_search.py compare "에어팟 프로 2세대" --limit 5 --offers 5 """ from __future__ import annotations import argparse import json import re import sys import time import urllib.parse import urllib.request from html import unescape from typing import Any, Dict, List, Optional try: from bs4 import BeautifulSoup except ImportError as exc: # pragma: no cover - environment guard raise SystemExit("beautifulsoup4 is required: python -m pip install beautifulsoup4") from exc UA = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 Chrome/121 Safari/537.36" def fetch(url: str, *, method: str = "GET", data: Optional[dict] = None, referer: Optional[str] = None) -> str: headers = { "User-Agent": UA, "Accept-Language": "ko-KR,ko;q=0.9,en;q=0.8", } body = None if data is not None: body = urllib.parse.urlencode(data).encode("utf-8") headers["Content-Type"] = "application/x-www-form-urlencoded; charset=UTF-8" headers["X-Requested-With"] = "XMLHttpRequest" if referer: headers["Referer"] = referer req = urllib.request.Request(url, data=body, headers=headers, method=method) with urllib.request.urlopen(req, timeout=25) as resp: return resp.read().decode("utf-8", "replace") def soup_for(html: str) -> BeautifulSoup: return BeautifulSoup(html, "html.parser") def clean_text(s: Optional[str]) -> Optional[str]: if s is None: return None return " ".join(unescape(s).split()) def parse_int(s: Optional[str]) -> Optional[int]: if not s: return None digits = re.sub(r"\D", "", s) return int(digits) if digits else None def abs_url(url: Optional[str]) -> Optional[str]: if not url: return None if url.startswith("//"): return "https:" + url if url.startswith("/"): return "https://prod.danawa.com" + url return url def search(query: str, limit: int = 10) -> Dict[str, Any]: url = "https://search.danawa.com/dsearch.php?query=" + urllib.parse.quote(query) html = fetch(url) soup = soup_for(html) items: List[Dict[str, Any]] = [] for li in soup.select("li.prod_item"): pid = (li.get("id") or "").replace("productItem", "") or None name_el = li.select_one(".prod_name a") or li.select_one("p.prod_name a") or li.select_one('a[name="productName"]') if not name_el: continue name = clean_text(name_el.get_text(" ", strip=True)) link = abs_url(name_el.get("href")) min_input = li.select_one(f"#min_price_{pid}") if pid else None price = parse_int(min_input.get("value") if min_input else None) if price is None: price_el = li.select_one(".price_sect strong") or li.select_one(".prod_pricelist strong") price = parse_int(price_el.get_text() if price_el else None) img = li.select_one(".thumb_image img") image = abs_url((img.get("data-original") or img.get("src")) if img else None) mall_el = li.select_one(".prod_pricelist .memory_sect") or li.select_one(".meta_item") spec = " / ".join(clean_text(e.get_text(" ", strip=True)) or "" for e in li.select(".spec_list a, .spec_list span")[:10]) items.append( { "pcode": pid, "title": name, "price": price, "price_text": f"{price:,}원" if price else None, "mall_text": clean_text(mall_el.get_text(" ", strip=True)) if mall_el else None, "url": link, "image_url": image, "spec": spec[:300] if spec else None, } ) if len(items) >= limit: break return {"query": query, "source_url": url, "count"