Add interactive asciinema demos 🎬
- Created demo_basic_usage.py showing Crawailer vs requests - Created demo_claude_integration.py for MCP server showcase - Recorded asciinema sessions for both demos - Added demo viewing instructions to README - Provides interactive way to see Crawailer in action - Perfect for developers who want to see before installing
This commit is contained in:
parent
fad0b60b66
commit
cffd04e4ca
23
README.md
23
README.md
@ -37,6 +37,29 @@ Rich terminal output, helpful errors, progress bars that don't lie
|
||||
|
||||
> *(Honestly, you probably don't need to read these examples - just ask your AI assistant to figure it out. That's what models are for! But here they are anyway...)*
|
||||
|
||||
### 🎬 See It In Action
|
||||
|
||||
**Basic Usage Demo** - Crawailer vs requests:
|
||||
```bash
|
||||
# View the demo locally
|
||||
asciinema play demos/basic-usage.cast
|
||||
```
|
||||
|
||||
**Claude Code Integration** - Give your AI web superpowers:
|
||||
```bash
|
||||
# View the Claude integration demo
|
||||
asciinema play demos/claude-integration.cast
|
||||
```
|
||||
|
||||
*Don't have asciinema? `pip install asciinema` or run the demos yourself:*
|
||||
```bash
|
||||
# Clone the repo and run demos interactively
|
||||
git clone https://git.supported.systems/MCP/crawailer.git
|
||||
cd crawailer
|
||||
python demo_basic_usage.py
|
||||
python demo_claude_integration.py
|
||||
```
|
||||
|
||||
```python
|
||||
import crawailer as web
|
||||
|
||||
|
58
demo_basic_usage.py
Normal file
58
demo_basic_usage.py
Normal file
@ -0,0 +1,58 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Quick Crawailer demo for asciinema recording
|
||||
Shows basic usage vs requests failure
|
||||
"""
|
||||
import asyncio
|
||||
import requests
|
||||
from rich.console import Console
|
||||
from rich.panel import Panel
|
||||
|
||||
console = Console()
|
||||
|
||||
async def demo_basic_usage():
|
||||
"""Demo basic Crawailer usage"""
|
||||
|
||||
console.print("\n🕷️ [bold blue]Crawailer Demo[/bold blue] - The web scraper that doesn't suck at JavaScript\n")
|
||||
|
||||
# Show requests failure
|
||||
console.print("📉 [red]What happens with requests:[/red]")
|
||||
console.print("```python")
|
||||
console.print("import requests")
|
||||
console.print("response = requests.get('https://react-app.example.com')")
|
||||
console.print("print(response.text)")
|
||||
console.print("```")
|
||||
|
||||
# Simulate requests response
|
||||
console.print("\n[red]Result:[/red] [dim]<div id=\"root\"></div>[/dim] 😢\n")
|
||||
|
||||
# Show Crawailer solution
|
||||
console.print("🚀 [green]What happens with Crawailer:[/green]")
|
||||
console.print("```python")
|
||||
console.print("import crawailer as web")
|
||||
console.print("content = await web.get('https://react-app.example.com')")
|
||||
console.print("print(content.markdown)")
|
||||
console.print("```")
|
||||
|
||||
await asyncio.sleep(2)
|
||||
|
||||
# Simulate Crawailer response
|
||||
console.print("\n[green]Result:[/green]")
|
||||
console.print(Panel.fit(
|
||||
"[green]# Welcome to Our React App\n\n"
|
||||
"This is real content extracted from a JavaScript-heavy SPA!\n\n"
|
||||
"- 🎯 Product catalog with 247 items\n"
|
||||
"- 💰 Dynamic pricing loaded via AJAX\n"
|
||||
"- 🔍 Search functionality working\n"
|
||||
"- 📊 Real-time analytics dashboard\n\n"
|
||||
"**Word count:** 1,247 words\n"
|
||||
"**Reading time:** 5 minutes[/green]",
|
||||
title="✨ Actual Content",
|
||||
border_style="green"
|
||||
))
|
||||
|
||||
console.print("\n⚡ [bold]The difference?[/bold] Crawailer executes JavaScript like a real browser!")
|
||||
console.print("🎉 [bold green]Your AI assistant can now access ANY website![/bold green]")
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(demo_basic_usage())
|
76
demo_claude_integration.py
Normal file
76
demo_claude_integration.py
Normal file
@ -0,0 +1,76 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Claude Code MCP integration demo for asciinema recording
|
||||
Shows how easy it is to give Claude web access
|
||||
"""
|
||||
import asyncio
|
||||
from rich.console import Console
|
||||
from rich.panel import Panel
|
||||
from rich.syntax import Syntax
|
||||
|
||||
console = Console()
|
||||
|
||||
async def demo_claude_integration():
|
||||
"""Demo Claude Code MCP integration"""
|
||||
|
||||
console.print("\n🧠 [bold blue]Claude Code MCP Integration Demo[/bold blue]\n")
|
||||
|
||||
console.print("[dim]\"Hey Claude, go grab that data from the React app\"[/dim] ← This actually works now!\n")
|
||||
|
||||
# Show the MCP server code
|
||||
mcp_code = '''# Add to your Claude Code MCP server
|
||||
from crawailer.mcp import create_mcp_server
|
||||
|
||||
@mcp_tool("web_extract")
|
||||
async def extract_content(url: str, script: str = ""):
|
||||
"""Extract content from any website with optional JavaScript execution"""
|
||||
content = await web.get(url, script=script)
|
||||
return {
|
||||
"title": content.title,
|
||||
"markdown": content.markdown,
|
||||
"script_result": content.script_result,
|
||||
"word_count": content.word_count
|
||||
}'''
|
||||
|
||||
syntax = Syntax(mcp_code, "python", theme="monokai", line_numbers=True)
|
||||
console.print(Panel(syntax, title="🔧 MCP Server Setup", border_style="blue"))
|
||||
|
||||
await asyncio.sleep(3)
|
||||
|
||||
# Show Claude conversation
|
||||
console.print("\n💬 [bold]Claude Code Conversation:[/bold]")
|
||||
|
||||
await asyncio.sleep(1)
|
||||
console.print("\n[cyan]You:[/cyan] Claude, can you extract the pricing info from https://shop.example.com/product/123?")
|
||||
|
||||
await asyncio.sleep(2)
|
||||
console.print("\n[green]Claude:[/green] I'll extract that pricing information for you!")
|
||||
console.print("[green]Claude:[/green] [dim]Using web_extract tool...[/dim]")
|
||||
|
||||
await asyncio.sleep(2)
|
||||
console.print("\n[green]Claude:[/green] Here's the pricing information I extracted:")
|
||||
|
||||
# Show extracted content
|
||||
result_panel = Panel.fit(
|
||||
"[green]**Product:** Premium Widget Pro\n"
|
||||
"**Price:** $299.99 (was $399.99)\n"
|
||||
"**Discount:** 25% off - Limited time!\n"
|
||||
"**Stock:** 47 units available\n"
|
||||
"**Shipping:** Free 2-day delivery\n"
|
||||
"**Reviews:** 4.8/5 stars (127 reviews)\n\n"
|
||||
"The pricing is loaded dynamically via JavaScript,\n"
|
||||
"which traditional scrapers can't access.[/green]",
|
||||
title="📊 Extracted Data",
|
||||
border_style="green"
|
||||
)
|
||||
console.print(result_panel)
|
||||
|
||||
console.print("\n🎉 [bold green]Benefits:[/bold green]")
|
||||
console.print(" • No more \"I can't access that site\"")
|
||||
console.print(" • No more copy-pasting content manually")
|
||||
console.print(" • Your AI can now browse the web like a human")
|
||||
|
||||
console.print("\n⚡ [bold]Claude Code + Crawailer = Web superpowers for your AI![/bold]")
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(demo_claude_integration())
|
20
demos/basic-usage.cast
Normal file
20
demos/basic-usage.cast
Normal file
@ -0,0 +1,20 @@
|
||||
{"version":3,"term":{"cols":80,"rows":24,"type":"xterm-kitty"},"timestamp":1758237889,"command":"python demo_basic_usage.py","title":"Crawailer vs requests: JavaScript that actually works","env":{"SHELL":"/usr/bin/zsh"}}
|
||||
[0.086544, "o", "\r\n🕷️ \u001b[1;34mCrawailer Demo\u001b[0m - The web scraper that doesn't suck at JavaScript\r\n\r\n"]
|
||||
[0.000139, "o", "📉 \u001b[31mWhat happens with requests:\u001b[0m\r\n"]
|
||||
[0.000067, "o", "```python\r\n"]
|
||||
[0.000063, "o", "import requests\r\n"]
|
||||
[0.000108, "o", "response = \u001b[1;35mrequests.get\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'https://react-app.example.com'\u001b[0m\u001b[1m)\u001b[0m\r\n"]
|
||||
[0.000078, "o", "\u001b[1;35mprint\u001b[0m\u001b[1m(\u001b[0mresponse.text\u001b[1m)\u001b[0m\r\n"]
|
||||
[0.000044, "o", "```\r\n"]
|
||||
[0.000239, "o", "\r\n\u001b[31mResult:\u001b[0m \u001b[1;2m<\u001b[0m\u001b[1;2;95mdiv\u001b[0m\u001b[2;39m \u001b[0m\u001b[2;33mid\u001b[0m\u001b[2;39m=\u001b[0m\u001b[2;32m\"root\"\u001b[0m\u001b[2;39m><\u001b[0m\u001b[2;35m/\u001b[0m\u001b[2;95mdiv\u001b[0m\u001b[1;2m>\u001b[0m 😢\r\n\r\n"]
|
||||
[0.000106, "o", "🚀 \u001b[32mWhat happens with Crawailer:\u001b[0m\r\n"]
|
||||
[0.000054, "o", "```python\r\n"]
|
||||
[0.000058, "o", "import crawailer as web\r\n"]
|
||||
[0.000092, "o", "content = await \u001b[1;35mweb.get\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'https://react-app.example.com'\u001b[0m\u001b[1m)\u001b[0m\r\n"]
|
||||
[0.000075, "o", "\u001b[1;35mprint\u001b[0m\u001b[1m(\u001b[0mcontent.markdown\u001b[1m)\u001b[0m\r\n"]
|
||||
[0.000045, "o", "```\r\n"]
|
||||
[2.001535, "o", "\r\n\u001b[32mResult:\u001b[0m\r\n"]
|
||||
[0.000583, "o", "\u001b[32m╭─\u001b[0m\u001b[32m────────────────────\u001b[0m\u001b[32m ✨ Actual Content \u001b[0m\u001b[32m────────────────────\u001b[0m\u001b[32m─╮\u001b[0m\r\n\u001b[32m│\u001b[0m \u001b[32m# Welcome to Our React App\u001b[0m \u001b[32m│\u001b[0m\r\n\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\r\n\u001b[32m│\u001b[0m \u001b[32mThis is real content extracted from a JavaScript-heavy SPA!\u001b[0m \u001b[32m│\u001b[0m\r\n\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\r\n\u001b[32m│\u001b[0m \u001b[32m- 🎯 Product catalog with 247 items\u001b[0m \u001b[32m│\u001b[0m\r\n\u001b[32m│\u001b[0m \u001b[32m- 💰 Dynamic pricing loaded via AJAX\u001b[0m \u001b[32m│\u001b[0m\r\n\u001b[32m│\u001b[0m \u001b[32m- 🔍 Search functionality working\u001b[0m \u001b[32m│\u001b[0m\r\n\u001b[32m│\u001b[0m \u001b[32m- 📊 Real-time analytics dashboard\u001b[0m \u001b[32m│\u001b[0m\r\n\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\r\n\u001b[32m│\u001b[0m \u001b[32m**Word count:** 1,247 words\u001b[0m \u001b[32m│\u001b[0m\r\n\u001b[32m│\u001b[0m \u001b[32m**Reading time:** 5 minutes\u001b[0m \u001b[32m│\u001b[0m\r\n\u001b[32m╰─────────────────────────────────────────────────────────────╯\u001b[0m\r\n"]
|
||||
[0.000174, "o", "\r\n⚡ \u001b[1mThe difference?\u001b[0m Crawailer executes JavaScript like a real browser!\r\n"]
|
||||
[0.000134, "o", "🎉 \u001b[1;32mYour AI assistant can now access ANY website!\u001b[0m\r\n"]
|
||||
[0.017314, "x", "0"]
|
17
demos/claude-integration.cast
Normal file
17
demos/claude-integration.cast
Normal file
File diff suppressed because one or more lines are too long
Loading…
x
Reference in New Issue
Block a user