
Visit Webpage
- 6 installs
- 217 repo stars
- Updated August 2, 2026
- pasky/pi-amplike
Helps with ai & agent building tasks during AI-assisted development.
About
visit-webpage is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- visit-webpage
- AI & Agent Building
- AI-coding skill
Visit Webpage by the numbers
- 6 all-time installs (skills.sh)
- Ranked #12,825 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
npx skills add https://github.com/pasky/pi-amplike --skill visit-webpageAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 6 |
|---|---|
| repo stars | ★ 217 |
| Last updated | August 2, 2026 |
| Repository | pasky/pi-amplike ↗ |
What it does
Helps with ai & agent building tasks during AI-assisted development.
Files
Visit Webpage
Fetch and extract readable content from web pages as markdown, or download images. Handles JavaScript-rendered content via Jina Reader service.
Setup
Optionally get a Jina API key for higher rate limits: 1. Create an account at https://jina.ai/ 2. Get your API key from the dashboard 3. Add to your shell profile (~/.profile or ~/.zprofile for zsh):
export JINA_API_KEY="your-api-key-here"Without an API key, the service works with rate limits.
Usage
{baseDir}/visit.py <url>Examples
# Read an article (returns markdown)
{baseDir}/visit.py https://example.com/article
# Fetch documentation
{baseDir}/visit.py https://docs.python.org/3/library/asyncio.html
# Download an image (auto-detected by content-type)
{baseDir}/visit.py https://example.com/image.png
# Then use read tool to view: read /tmp/visit-image-xxx.pngOutput
For HTML pages: Returns markdown content to stdout.
For images: Downloads the image to a temp file and prints the path. Use the read tool to view it. Supports PNG, JPEG, GIF, and WebP formats.
Features
- Extracts main content from HTML pages
- Converts HTML to clean markdown
- Handles JavaScript-rendered pages via Jina Reader
- Auto-detects and downloads images to temp files
- Retries on rate limiting (HTTP 451)
- 5MB max image size limit
When to Use
- Reading articles, blog posts, or documentation
- Extracting content from search results
- Downloading images from URLs (then use
readto view) - Following links found during web search
#!/usr/bin/env python3
"""Visit webpage and extract content as markdown, or download images."""
import os
import re
import sys
import tempfile
import time
import urllib.request
from urllib.error import HTTPError, URLError
MAX_IMAGE_SIZE = 5 * 1024 * 1024 # 5MB
MAX_CONTENT_LENGTH = 100000 # 100KB text limit
TIMEOUT = 60
RETRY_DELAYS = [0, 30, 90]
IMAGE_EXTENSIONS = {
"image/png": ".png",
"image/jpeg": ".jpg",
"image/gif": ".gif",
"image/webp": ".webp",
}
def get_headers(include_jina_auth: bool = False) -> dict[str, str]:
"""Build request headers."""
headers = {"User-Agent": "pi-skill/1.0"}
api_key = os.environ.get("JINA_API_KEY")
if include_jina_auth and api_key:
headers["Authorization"] = f"Bearer {api_key}"
return headers
def check_content_type(url: str) -> str | None:
"""Check URL content type via HEAD request. Returns content-type or None on error."""
req = urllib.request.Request(url, method="HEAD", headers=get_headers())
try:
with urllib.request.urlopen(req, timeout=TIMEOUT) as response:
return response.headers.get("Content-Type", "").lower().split(";")[0]
except (HTTPError, URLError):
return None
def download_image(url: str) -> str:
"""Download image and save to temp file. Returns file path."""
req = urllib.request.Request(url, headers=get_headers())
with urllib.request.urlopen(req, timeout=TIMEOUT) as response:
content_type = response.headers.get("Content-Type", "").lower().split(";")[0]
if content_type not in IMAGE_EXTENSIONS:
raise ValueError(f"Unsupported image type: {content_type}")
content_length = response.headers.get("Content-Length")
if content_length and int(content_length) > MAX_IMAGE_SIZE:
raise ValueError(f"Image too large: {content_length} bytes (max {MAX_IMAGE_SIZE})")
data = response.read()
if len(data) > MAX_IMAGE_SIZE:
raise ValueError(f"Image too large: {len(data)} bytes (max {MAX_IMAGE_SIZE})")
ext = IMAGE_EXTENSIONS[content_type]
# Create temp file with appropriate extension
fd, filepath = tempfile.mkstemp(suffix=ext, prefix="visit-image-")
os.write(fd, data)
os.close(fd)
return filepath
def fetch_webpage(url: str) -> str:
"""Fetch webpage content via Jina Reader with retries."""
jina_url = f"https://r.jina.ai/{url}"
headers = get_headers(include_jina_auth=True)
last_error = None
for i, delay in enumerate(RETRY_DELAYS):
if delay > 0:
print(f"Waiting {delay}s before retry {i+1}/{len(RETRY_DELAYS)}...", file=sys.stderr)
time.sleep(delay)
req = urllib.request.Request(jina_url, headers=headers)
try:
with urllib.request.urlopen(req, timeout=TIMEOUT) as response:
content = response.read().decode("utf-8", errors="replace")
# Clean up multiple line breaks
content = re.sub(r"\n{3,}", "\n\n", content)
# Truncate if too long
if len(content) > MAX_CONTENT_LENGTH:
content = content[:MAX_CONTENT_LENGTH] + "\n\n..._Content truncated_..."
return content
except HTTPError as e:
last_error = e
if e.code in (451, 500, 502, 503, 504) and i < len(RETRY_DELAYS) - 1:
print(f"HTTP {e.code}, will retry...", file=sys.stderr)
continue
raise
except URLError as e:
last_error = e
if i < len(RETRY_DELAYS) - 1:
print(f"Network error: {e.reason}, will retry...", file=sys.stderr)
continue
raise
raise last_error or RuntimeError("Failed after retries")
def main():
if len(sys.argv) < 2:
print("Usage: visit.py <url>")
print()
print("Fetches a webpage and extracts its content as markdown,")
print("or downloads images to a temp file.")
print()
print("Environment:")
print(" JINA_API_KEY Optional. Your Jina API key for higher rate limits.")
print()
print("Examples:")
print(" visit.py https://example.com/article")
print(" visit.py https://example.com/image.png")
sys.exit(1)
url = sys.argv[1]
# Validate URL
if not url.startswith(("http://", "https://")):
print("Error: URL must start with http:// or https://", file=sys.stderr)
sys.exit(1)
try:
# Check content type first
content_type = check_content_type(url)
if content_type and content_type.startswith("image/"):
# Handle image - download to temp and print path (like browser-screenshot.js)
filepath = download_image(url)
print(filepath)
else:
# Handle webpage
content = fetch_webpage(url)
print(f"## Content from {url}")
print()
print(content)
except HTTPError as e:
print(f"Error: HTTP {e.code} - {e.reason}", file=sys.stderr)
sys.exit(1)
except URLError as e:
print(f"Error: {e.reason}", file=sys.stderr)
sys.exit(1)
except ValueError as e:
print(f"Error: {e}", file=sys.stderr)
sys.exit(1)
except Exception as e:
print(f"Error: {e}", file=sys.stderr)
sys.exit(1)
if __name__ == "__main__":
main()