Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Web Scraping

Examples of web scraping and data extraction with AetherShell.

Basic Page Fetching

# Fetch a page
let page = http_get "https://example.com"
echo page.status     # 200
echo page.ok         # true

# Extract text content
let text = web_html_to_text page.body
echo text

Scraping with Selectors

# Scrape article titles
let titles = web_scrape "https://news.ycombinator.com" "a.storylink"
titles | take 10 | each(fn(t) => echo t.text)

API-Based Scraping

# GitHub repository stats
let repos = ["rust-lang/rust", "tokio-rs/tokio", "serde-rs/serde"]

repos | map(fn(repo) => {
  let data = web_json_get "https://api.github.com/repos/${repo}"
  {
    name: data.full_name,
    stars: data.stargazers_count,
    forks: data.forks_count,
    language: data.language
  }
}) | sort_by "stars" "desc"

Content Extraction

HTML to Markdown

let html = (http_get "https://blog.example.com/post/1").body
let md = web_html_to_markdown html
file_write "post.md" md

Extract Emails

let page = (http_get "https://example.com/contact").body
let emails = web_extract_emails page
echo emails   # ["info@example.com", "support@example.com"]
let links = web_scrape "https://example.com" "a[href]"
links | map(fn(a) => a.href) | where(fn(h) => starts_with h "https://") | unique

Download Pipeline

# Download multiple files
let urls = [
  "https://data.example.com/dataset1.csv",
  "https://data.example.com/dataset2.csv",
  "https://data.example.com/dataset3.csv"
]

mkdir "downloads"
urls | each(fn(url) => {
  let filename = last(split(url, "/"))
  echo "Downloading ${filename}..."
  web_download url "downloads/${filename}"
})

URL Health Checking

let urls = cat "urls.txt" | split "\n" | where(fn(u) => len(u) > 0)

let results = urls | map(fn(url) => {
  let check = web_check_url url
  { url: url, status: check.status, ok: check.reachable }
})

# Report broken links
let broken = results | where(fn(r) => !r.ok)
echo "${len broken} broken links found:"
broken | each(fn(r) => echo "  ✗ ${r.url} (${r.status})")

Paginated API

# Fetch all pages from a paginated API
let all_items = []
let page = 1
let has_more = true

# Note: AetherShell supports while loops via recursion
let fetch_page = fn(page, acc) => {
  let data = web_json_get "https://api.example.com/items?page=${page}&limit=100"
  let items = concat acc data.items
  if len(data.items) == 100 {
    fetch_page (page + 1) items
  } else {
    items
  }
}

let all_items = fetch_page 1 []
echo "Total items: ${len all_items}"

RSS Feed Parsing

let feed = (http_get "https://blog.example.com/feed.xml").body
let items = web_xpath feed "//item"

items | take 5 | map(fn(item) => {
  {
    title: web_xpath item "title/text()",
    link: web_xpath item "link/text()",
    date: web_xpath item "pubDate/text()"
  }
})