agent-instructions
Use when writing project instructions for a coding agent (CLAUDE.md, AGENTS.md, or equivalent). Covers what belongs in them, what does not, structure, and…
Use when extracting data from web pages. Covers choosing between an API, static parsing, and a browser, handling JavaScript-rendered content, resilient selectors, rate limiting, and scraping responsibly.
$ npx -y skills add nimadorostkar/Claude-Skills-collection --skill web-data-extraction --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/web-data-extractionContext preview
The summary Claude sees to decide when to auto-load this skill.
Use when extracting data from web pages. Covers choosing between an API, static parsing, and a browser, handling JavaScript-rendered content, resilient selectors, rate limiting, and scraping responsibly.
name: web-data-extraction description: Use when extracting data from web pages. Covers choosing between an API, static parsing, and a browser, handling JavaScript-rendered content, resilient selectors, rate limiting, and scraping responsibly. metadata: category: productivity version: 1.0.0 tags: [scraping, extraction, html, browser, automation]
Get structured data out of web pages reliably. The two questions that determine the entire approach are whether an API exists, and whether the content is rendered by JavaScript — and both are answered in under a minute.
1. **Look for an API first** — Check the documentation, then check the network tab. Very often the page itself calls a JSON endpoint, and that endpoint is stable, structured, and far easier to use than the HTML. 2. **Determine whether the content is in the HTML** — `curl` the URL and search for the data. If it is absent, the page renders it with JavaScript and static parsing will return nothing, forever, with no error. 3. **Choose the tool accordingly** — Static HTML: an HTTP client and a parser. JavaScript-rendered: a headless browser. Do not use a browser when you do not need one; it is fifty times slower. 4. **Write resilient selectors** — Anchor on stable attributes (`data-*`, an id, a semantic element), not on a generated class name that changes with every deploy. 5. **Be polite** — Rate limit, identify yourself, respect `robots.txt`, and cache. A scraper that hammers a site is both rude and likely to be blocked. 6. **Validate the output** — A scraper that silently returns zero rows because the page changed is worse than one that crashes.
**The check that determines everything:**
# Is the data in the HTML, or is it rendered by JavaScript? curl -s "https://example.com/products" | grep -c "product-title" # 0 -> The content is not in the HTML. It is rendered client-side. A static # parser will return nothing and will not tell you why. You need a browser # — OR, better, find the API the page itself is calling. # 24 -> The content is there. Parse it statically; it is 50x faster.
**Find the API the page calls, rather than scraping the page:**
// In the browser's network tab, filter by Fetch/XHR. Very frequently:
// GET /api/v2/products?page=1&limit=24
// -> {"products": [{"id": ..., "title": ..., "price_cents": ...}], "total": 480}
//
// This is structured, paginated, stable, and 100x cheaper to consume than
// parsing the rendered HTML. It is also far less likely to break, because the
// site's own frontend depends on it.**A scraper that fails loudly:**
async def extract_products(html: str, url: str) -> list[Product]:
tree = HTMLParser(html)
# Anchor on data attributes and semantic structure, not on generated class
# names like ".css-1x7f9ka" that change on every deploy.
cards = tree.css("[data-testid='product-card']")
if not cards:
# This is the critical branch. A scraper that returns [] when the page
# structure changes will quietly produce an empty dataset for weeks.
raise StructureChanged(
f"No product cards found at {url}. The selector "
f"[data-testid='product-card'] matched nothing. The page structure "
f"has probably changed — do not treat this as 'no products'."
)
products = []
for card in cards:
title = card.css_first("[data-testid='title']")
price = card.css_first("[data-testid='price']")
if title is None or price is None:
logger.warning("card_missing_fields", extra={"url": url, "html": card.html[:200]})
continue
products.append(Product(
title=title.text(strip=True),
price_cents=parse_price(price.text(strip=True)),
url=urljoin(url, card.css_first("a").attributes["href"]),
))
return productsA curated library of 137 production-grade skills for Claude and other AI coding agents. Every skill follows one structure, speaks with one voice, and earns its place by changing what the agent does.
Repo: nimadorostkar/Claude-Skills-collection
Use when writing project instructions for a coding agent (CLAUDE.md, AGENTS.md, or equivalent). Covers what belongs in them, what does not, structure, and…
Use when an agent needs state that survives a session or a context compaction. Covers what to persist, file-based memory, structuring notes for retrieval, and…
Use when automating agent behavior with lifecycle hooks. Covers hook events, deterministic enforcement of rules the model should not be trusted to remember,…
Use when packaging skills, commands, hooks, and MCP servers into a distributable plugin. Covers manifest structure, bundling, versioning, testing, and…
Use when writing a new skill for an AI agent. Covers scoping, description writing for reliable triggering, progressive disclosure, and the difference between a…
Use when reviewing or improving an existing agent skill. Covers triggering accuracy, content quality, redundancy with the base model, and measuring whether the…