noticias-cangrejo
Fetch and summarize recent news articles from GNews for any user-provided topic, then produce a Markdown digest with date, greeting, and top links.
Packaged view
This page reorganizes the original catalog entry around fit, installability, and workflow context first. The original raw source lives below.
Install command
npx @skill-hub/cli install openclaw-skills-noticias-cangrejo
Repository
Skill path: skills/davidk2yoyo/noticias-cangrejo
Fetch and summarize recent news articles from GNews for any user-provided topic, then produce a Markdown digest with date, greeting, and top links.
Open repositoryBest for
Primary workflow: Ship Full Stack.
Technical facets: Full Stack.
Target audience: everyone.
License: Unknown.
Original source
Catalog source: SkillHub Club.
Repository owner: openclaw.
This is still a mirrored public skill entry. Review the repository before installing into production workflows.
What it helps with
- Install noticias-cangrejo into Claude Code, Codex CLI, Gemini CLI, or OpenCode workflows
- Review https://github.com/openclaw/skills before adding noticias-cangrejo to shared team environments
- Use noticias-cangrejo for development workflows
Works across
Favorites: 0.
Sub-skills: 0.
Aggregator: No.
Original source / Raw SKILL.md
---
name: noticias-cangrejo
description: Fetch and summarize recent news articles from GNews for any user-provided topic, then produce a Markdown digest with date, greeting, and top links.
homepage: https://gnews.io/
metadata: {"clawdbot":{"emoji":"🦀","requires":{"env":["GNEWS_API_KEY"]}}}
---
# NoticiasCangrejo
Generate a Markdown news digest for any topic using the GNews API.
## When To Use
Use this skill when the user asks for recent news on any topic, such as politics, science, startups, health, finance, sports, or local events, and wants a concise, linkable summary.
## Environment Requirement
Set this environment variable before execution:
- `GNEWS_API_KEY`
## Workflow
1. Receive a topic from the user.
2. Validate that `GNEWS_API_KEY` exists.
3. Query GNews Search API for up to 20 articles using topic + language.
4. Compute relevance based on topic-word overlap against article title and description.
5. Keep the top 15 ranked articles.
6. Print Markdown output with:
- Date (`YYYY/MM/DD`)
- Greeting line in Spanish
- Topic line
- Numbered list of article title + URL
7. Optionally save output to a file with `--output`.
## Execution
Canonical OpenClaw execution is defined in `_meta.json` under `run`:
```bash
python3 scripts/fetch_news.py "<topic>"
```
Optional parameters:
- `--lang` (default: `en`)
- `--max-articles` (default: `20`)
- `--output` to write Markdown to a file
## Example Usage
```bash
export GNEWS_API_KEY="your_api_key_here"
python3 scripts/fetch_news.py "global markets" --lang en --max-articles 20 --output ./markets.md
```
---
## Referenced Files
> The following files are referenced in this skill and included for context.
### scripts/fetch_news.py
```python
#!/usr/bin/env python3
"""Fetch topic-based news from GNews and print a Markdown summary.
Dependency-free implementation using only Python standard library.
"""
from __future__ import annotations
import argparse
import datetime as dt
import json
import os
import socket
import sys
from typing import Any, Dict, List
from urllib import error, parse, request
GNEWS_ENDPOINT = "https://gnews.io/api/v4/search"
DEFAULT_LANG = "en"
DEFAULT_MAX_ARTICLES = 20
MAX_SELECTED_ARTICLES = 15
TIMEOUT_SECONDS = 20
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(
description="Fetch news for any topic from GNews and output a Markdown summary."
)
parser.add_argument("topic", help="Topic to search for (e.g., 'quantum computing').")
parser.add_argument("--lang", default=DEFAULT_LANG, help="Language code (default: en).")
parser.add_argument(
"--max-articles",
type=int,
default=DEFAULT_MAX_ARTICLES,
help="Maximum number of articles to request from API (default: 20).",
)
parser.add_argument(
"--output",
help="Optional output file path to save the Markdown summary.",
)
return parser.parse_args()
def get_api_key() -> str:
api_key = os.getenv("GNEWS_API_KEY", "").strip()
if not api_key:
raise RuntimeError(
"Missing GNEWS_API_KEY environment variable. "
"Set it before running this script."
)
return api_key
def _http_get_json(url: str, timeout: int) -> Dict[str, Any]:
req = request.Request(url=url, method="GET")
try:
with request.urlopen(req, timeout=timeout) as resp:
status = getattr(resp, "status", 200)
body_bytes = resp.read()
except error.HTTPError as exc:
if exc.code == 401:
raise RuntimeError(
"Unauthorized (401): invalid GNews API key. Verify GNEWS_API_KEY."
) from exc
if exc.code == 429:
raise RuntimeError(
"Rate limit reached (429): too many requests to GNews. Try again later."
) from exc
try:
detail = exc.read().decode("utf-8", errors="replace").strip()
except Exception:
detail = ""
raise RuntimeError(
f"GNews API error (status {exc.code}). Details: {detail or 'No details returned.'}"
) from exc
except error.URLError as exc:
reason = getattr(exc, "reason", None)
if isinstance(reason, socket.timeout):
raise RuntimeError(
"Request to GNews timed out. Please try again in a moment."
) from exc
raise RuntimeError(f"Network error while contacting GNews: {exc}") from exc
except socket.timeout as exc:
raise RuntimeError(
"Request to GNews timed out. Please try again in a moment."
) from exc
if status != 200:
detail = body_bytes.decode("utf-8", errors="replace").strip()
raise RuntimeError(
f"GNews API error (status {status}). Details: {detail or 'No details returned.'}"
)
try:
return json.loads(body_bytes.decode("utf-8"))
except json.JSONDecodeError as exc:
raise RuntimeError("GNews API returned invalid JSON.") from exc
def fetch_articles(topic: str, lang: str, max_articles: int, api_key: str) -> List[Dict[str, Any]]:
safe_max = max(1, min(max_articles, DEFAULT_MAX_ARTICLES))
params = {
"q": topic,
"lang": lang,
"max": str(safe_max),
"apikey": api_key,
}
url = f"{GNEWS_ENDPOINT}?{parse.urlencode(params)}"
payload = _http_get_json(url, timeout=TIMEOUT_SECONDS)
articles = payload.get("articles")
if not isinstance(articles, list):
raise RuntimeError("Unexpected GNews response format: 'articles' is missing or invalid.")
return articles
def relevance_score(article: Dict[str, Any], topic_terms: List[str]) -> int:
title = str(article.get("title") or "").lower()
description = str(article.get("description") or "").lower()
text = f"{title} {description}"
score = 0
for term in topic_terms:
if term in text:
score += 1
if title:
for term in topic_terms:
if term in title:
score += 1
return score
def select_top_articles(articles: List[Dict[str, Any]], topic: str) -> List[Dict[str, Any]]:
topic_terms = [term for term in topic.lower().split() if term]
ranked = sorted(
articles,
key=lambda item: (
relevance_score(item, topic_terms),
str(item.get("publishedAt") or ""),
),
reverse=True,
)
return ranked[:MAX_SELECTED_ARTICLES]
def render_markdown(topic: str, articles: List[Dict[str, Any]]) -> str:
today = dt.date.today().strftime("%Y/%m/%d")
lines = [
f"# {today}",
"",
f'Buenos dias, este es el resumen de NoticiasCangrejo para "{topic}" - {today}.',
"",
]
if not articles:
lines.append("No se encontraron articulos para este tema.")
return "\n".join(lines)
for idx, article in enumerate(articles, start=1):
title = str(article.get("title") or "Sin titulo").strip()
url = str(article.get("url") or "").strip()
if url:
lines.append(f"{idx}. [{title}]({url})")
else:
lines.append(f"{idx}. {title}")
return "\n".join(lines)
def main() -> int:
args = parse_args()
topic = args.topic.strip()
if not topic:
print("Error: Topic must not be empty.", file=sys.stderr)
return 1
try:
api_key = get_api_key()
articles = fetch_articles(topic, args.lang, args.max_articles, api_key)
top_articles = select_top_articles(articles, topic)
markdown = render_markdown(topic, top_articles)
except RuntimeError as exc:
print(f"Error: {exc}", file=sys.stderr)
return 1
print(markdown)
if args.output:
try:
with open(args.output, "w", encoding="utf-8") as handle:
handle.write(markdown + "\n")
except OSError as exc:
print(f"Error writing output file: {exc}", file=sys.stderr)
return 1
return 0
if __name__ == "__main__":
raise SystemExit(main())
```
---
## Skill Companion Files
> Additional files collected from the skill directory layout.
### README.md
```markdown
# NoticiasCangrejo
NoticiasCangrejo is an OpenClaw skill that fetches news from GNews (`gnews.io`) for any topic and outputs a Markdown summary of the top articles.
## Features
- Works with any topic provided by the user
- Uses GNews Search API
- Pulls up to 20 articles and returns the 15 most relevant
- Outputs clean Markdown with date, greeting, titles, and URLs
- Includes dashboard API key metadata for ClawHub/OpenClaw publishing
- No third-party Python packages required
## Installation
Install the skill from ClawHub or from its repository path. The packaged skill uses only:
- `SKILL.md`
- `README.md`
- `requirements.txt`
- `_meta.json`
- `scripts/fetch_news.py`
## Environment Variable Setup
Set your GNews API key:
```bash
export GNEWS_API_KEY="your_api_key_here"
```
Do not commit real API keys to source control.
## Canonical Run Command
The canonical command is defined in `_meta.json` (`run`):
```bash
python3 scripts/fetch_news.py "<topic>"
```
## CLI Usage
Basic:
```bash
python3 scripts/fetch_news.py "space exploration"
```
Custom language and result size:
```bash
python3 scripts/fetch_news.py "renewable energy" --lang en --max-articles 20
```
Save summary to a file:
```bash
python3 scripts/fetch_news.py "cybersecurity" --output ./cybersecurity-news.md
```
## OpenClaw Usage
When this skill is installed, ask for a topic summary, for example:
- "Usa noticias-cangrejo para Terpel Colombia"
- "Resume las noticias sobre Formula 1"
The skill reads `GNEWS_API_KEY` from dashboard/environment configuration and returns Markdown output.
## Publishing Notes (ClawHub)
- Skill folder name is slug-friendly: `noticias-cangrejo`
- `_meta.json` defines explicit `run` behavior for packaged installs
- No hardcoded API credentials are included
- Runtime is dependency-free (standard library only)
```
### _meta.json
```json
{
"owner": "davidk2yoyo",
"slug": "noticias-cangrejo",
"displayName": "Noticias Cangrejo",
"latest": {
"version": "1.0.4",
"publishedAt": 1771121962677,
"commit": "https://github.com/openclaw/skills/commit/0739014caee49ecfb8a8bf69e04302d266e18ce5"
},
"history": []
}
```
### scripts/__init__.py
```python
"""NoticiasCangrejo scripts package."""
```