algo-seo-crawl
實作涵蓋探索、抓取、解析、儲存的網頁爬蟲
中文翻譯
---
name: "algo-seo-crawl"
description: "實作網頁爬蟲 pipeline,涵蓋 URL 探索、抓取、解析和儲存。當使用者需要建立網站爬蟲、稽核網站結構、或有系統地蒐集網頁資料時使用,即使他們說的是「爬網站」、「爬所有頁面」或「網站稽核蜘蛛」也一樣。"
metadata:
category: "WP-35 SEO 演算法"
tags: ["seo", "web-crawler", "scraping", "site-audit"]
---
# 網頁爬蟲(Web Crawler)
## 概述
網頁爬蟲透過探索 URL、抓取內容、解析 HTML 和儲存結果,有系統地走訪網頁。使用 BFS 或以優先順序為基礎的 frontier 管理。效能受 I/O 限制,通常卡在禮貌性限制(politeness),而不是運算。
## 何時使用
**觸發條件:**
- 要建立網站稽核工具,探索所有頁面及其連結結構
- 要大規模地從網站蒐集結構化資料
- 要為 SEO 分析繪製網站架構
**何時不要用:**
- 只需要單一個 API 端點的資料時(直接用 HTTP client)
- sitemap.xml 已提供所有需要的 URL 時(改為解析 sitemap)
## 演算法
```
鐵律:遵守 robots.txt 和速率限制
爬蟲「必須」:
1. 在爬任何路徑之前,先解析並遵守 robots.txt
2. 強制執行 crawl-delay(沒指定時預設 1 秒)
3. 用具描述性的 User-Agent 表明自己的身分
無視這些既不道德,也會讓你的 IP 被封鎖。
```
### 階段 1:輸入驗證
解析種子 URL,替每個網域抓取並解析 robots.txt,設定爬取範圍(同網域、子網域或跨網域)。
**關卡:** 種子 URL 有效、robots.txt 規則已載入、範圍已定義。
### 階段 2:核心演算法
1. 用種子 URL 初始化 URL frontier(優先佇列或 FIFO)
2. 取出 URL,檢查:沒造訪過、robots.txt 允許、在範圍內
3. 抓取頁面,附帶逾時和重試邏輯,並遵守 crawl-delay
4. 解析 HTML:擷取連結(正規化、去重)、擷取內容/metadata
5. 把探索到的 URL 放進佇列,儲存解析後的資料
6. 重複直到 frontier 清空或達到上限
### 階段 3:驗證
檢查:爬取紀錄裡沒有違反 robots.txt、沒有儲存重複的頁面、所有探索到的 URL 都有交代。
**關卡:** 爬取在範圍內完成、維持了禮貌性。
### 階段 4:輸出
回傳網站地圖,包含頁面、連結圖和擷取到的 metadata。
## 輸出格式
```json
{
"pages": [{"url": "...", "status": 200, "title": "...", "links_out": 15, "depth": 2}],
"metadata": {"pages_crawled": 500, "errors": 12, "duration_seconds": 300, "domain": "example.com"}
}
```
## 範例
### 輸入輸出範例
**輸入:** 種子:"https://example.com"、max_depth: 2、max_pages: 100
**預期:** 爬取樹,首頁在深度 0,連結頁面在深度 1-2,並遵守 robots.txt
### 邊界情況
| 輸入 | 預期 | 原因 |
|-------|----------|-----|
| robots.txt 不允許 / | 爬到零個頁面 | 必須遵守完全禁止 |
| 重新導向迴圈 | 5 次重新導向後停止 | 避免無限迴圈 |
| Soft 404(200 但是是錯誤頁面) | 標記為 soft 404 | 光看狀態碼不夠 |
## 常見陷阱
- **URL 正規化**:`http://Example.COM/path/` 和 `http://example.com/path` 是同一個 URL。要正規化:host 轉小寫、移除預設 port、移除結尾斜線、排序 query 參數。
- **JavaScript 渲染的內容**:基本的 HTTP 抓取會漏掉 JS 渲染的內容。SPA 要用 headless browser(Playwright/Puppeteer)。
- **陷阱偵測**:日曆頁面、URL 裡的 session ID 和無限分頁,都會造成爬蟲陷阱。要設定最大深度和 URL 模式限制。
- **自我限速**:平行抓取卻沒有每個網域的速率限制,會壓垮小型伺服器。要用每個網域的 semaphore。
- **字元編碼**:不是所有頁面都是 UTF-8。要從 HTTP header 和 meta 標籤偵測編碼,不行時再退回字元集偵測函式庫。
## 參考資料
- URL 正規化的規則(RFC 3986),見 `references/url-normalization.md`
- 分散式爬取架構,見 `references/distributed-crawl.md`英文原文
---
name: "algo-seo-crawl"
description: "Implement a web crawler pipeline covering URL discovery, fetching, parsing, and storage. Use this skill when the user needs to build a site crawler, audit website structure, or collect web data systematically — even if they say 'scrape a website', 'crawl all pages', or 'site audit spider'."
metadata:
category: "WP-35 SEO 演算法"
tags: ["seo", "web-crawler", "scraping", "site-audit"]
---
# Web Crawler
## Overview
A web crawler systematically traverses web pages by discovering URLs, fetching content, parsing HTML, and storing results. Uses BFS or priority-based frontier management. Performance is I/O-bound, typically limited by politeness constraints rather than compute.
## When to Use
**Trigger conditions:**
- Building a site audit tool to discover all pages and their link structure
- Collecting structured data from websites at scale
- Mapping site architecture for SEO analysis
**When NOT to use:**
- When you need data from a single API endpoint (use HTTP client directly)
- When a sitemap.xml provides all needed URLs (parse sitemap instead)
## Algorithm
```
IRON LAW: Respect robots.txt and Rate Limits
A crawler MUST:
1. Parse and obey robots.txt before crawling any path
2. Enforce crawl-delay (default 1s if unspecified)
3. Identify itself with a descriptive User-Agent
Ignoring these is unethical and will get your IP blocked.
```
### Phase 1: Input Validation
Parse seed URLs, fetch and parse robots.txt for each domain, set crawl scope (same-domain, subdomain, or cross-domain).
**Gate:** Valid seed URLs, robots.txt rules loaded, scope defined.
### Phase 2: Core Algorithm
1. Initialize URL frontier with seed URLs (priority queue or FIFO)
2. Dequeue URL, check: not visited, allowed by robots.txt, within scope
3. Fetch page with timeout and retry logic, respect crawl-delay
4. Parse HTML: extract links (normalize, deduplicate), extract content/metadata
5. Enqueue discovered URLs, store parsed data
6. Repeat until frontier empty or limit reached
### Phase 3: Verification
Check: no robots.txt violations in crawl log, no duplicate pages stored, all discovered URLs accounted for.
**Gate:** Crawl completed within scope, politeness maintained.
### Phase 4: Output
Return site map with pages, link graph, and extracted metadata.
## Output Format
```json
{
"pages": [{"url": "...", "status": 200, "title": "...", "links_out": 15, "depth": 2}],
"metadata": {"pages_crawled": 500, "errors": 12, "duration_seconds": 300, "domain": "example.com"}
}
```
## Examples
### Sample I/O
**Input:** Seed: "https://example.com", max_depth: 2, max_pages: 100
**Expected:** Crawl tree with homepage at depth 0, linked pages at depth 1-2, respecting robots.txt
### Edge Cases
| Input | Expected | Why |
|-------|----------|-----|
| robots.txt disallows / | Zero pages crawled | Must respect full disallow |
| Redirect loop | Stop after 5 redirects | Prevent infinite loop |
| Soft 404 (200 with error page) | Flag as soft 404 | Status code alone is insufficient |
## Gotchas
- **URL normalization**: `http://Example.COM/path/` and `http://example.com/path` are the same URL. Normalize: lowercase host, remove default port, remove trailing slash, sort query params.
- **JavaScript-rendered content**: A basic HTTP fetch misses JS-rendered content. Use headless browser (Playwright/Puppeteer) for SPAs.
- **Trap detection**: Calendar pages, session IDs in URLs, and infinite pagination create crawler traps. Set max depth and URL pattern limits.
- **Rate limiting yourself**: Parallel fetching without per-domain rate limiting will overwhelm small servers. Use per-domain semaphores.
- **Character encoding**: Not all pages are UTF-8. Detect encoding from HTTP headers and meta tags; fall back to charset detection libraries.
## References
- For URL normalization rules (RFC 3986), see `references/url-normalization.md`
- For distributed crawling architecture, see `references/distributed-crawl.md`