← 返回 Day 191 正文

Day 191 · 图解

Day 191 · 图解

1. 引擎数据流

flowchart TD S[种子 URL] --> N[normalize] N -->|None| DROP[丢弃] N -->|规范 URL| S1{seen?} S1 -->|是| DROP S1 -->|否| Q[Frontier deque] Q --> R{robots?} R -->|Disallow| REL[release 预算] --> Q R -->|Allow| T[TokenBucket.acquire] T --> H[HTTP GET] H -->|2xx| P[Parser] H -->|4xx| F[(failures)] H -->|5xx/429| RT{attempt < 4} RT -->|是| BJ[full jitter] --> T RT -->|否| F P --> DB[(pages UPSERT)] P --> Q
flowchart TD
    S[种子 URL] --> N[normalize]
    N -->|None| DROP[丢弃]
    N -->|规范 URL| S1{seen?}
    S1 -->|是| DROP
    S1 -->|否| Q[Frontier deque]
    Q --> R{robots?}
    R -->|Disallow| REL[release 预算] --> Q
    R -->|Allow| T[TokenBucket.acquire]
    T --> H[HTTP GET]
    H -->|2xx| P[Parser]
    H -->|4xx| F[(failures)]
    H -->|5xx/429| RT{attempt < 4}
    RT -->|是| BJ[full jitter] --> T
    RT -->|否| F
    P --> DB[(pages UPSERT)]
    P --> Q

2. 令牌桶:正确 vs 错误

正确:capacity=1,全局共享
worker1 ─┐
worker2 ─┼─► [tokens] ─► 放行间隔 1/rate
workerN ─┘     ▲
               └── 锁内预扣,锁外 sleep

实测 rate=20:20.16 req/s(+0.8%)
错误:每 worker 一个 sleep
worker1 ── sleep(1/rate) ──► fetch
worker2 ── sleep(1/rate) ──► fetch   ← 并行,互不约束
workerN ── sleep(1/rate) ──► fetch

实测 rate=20, 8 worker:117.77 req/s(+489%)

3. 桶容量对短任务的影响

capacity = rate (错)          capacity = 1 (对)

 60 ┤██████                    1 ┤█
    │      ╲                      │ ╲
  0 ┤       ██████             0 ┤  █ █ █ █ ──►
    0s      1s   2s              0s  1s  2s

120 页 @60/s:1.004s(119.55 rps)   120 页 @60/s:1.988s(60.4 rps)

4. 重试状态机

stateDiagram-v2 [*] --> Pending Pending --> OK: 2xx Pending --> Permanent: 4xx Pending --> Retryable: 5xx / 429 / timeout Retryable --> Backoff: attempt < 4 Backoff --> Pending: sleep(random(0, ceiling)) Retryable --> Failed: attempt = 4 Permanent --> Failed OK --> [*] Failed --> [*]
stateDiagram-v2
    [*] --> Pending
    Pending --> OK: 2xx
    Pending --> Permanent: 4xx
    Pending --> Retryable: 5xx / 429 / timeout
    Retryable --> Backoff: attempt < 4
    Backoff --> Pending: sleep(random(0, ceiling))
    Retryable --> Failed: attempt = 4
    Permanent --> Failed
    OK --> [*]
    Failed --> [*]

5. 断点续爬

全量 URL 集合 A = {1,2,3,...,45}
已落库集合 B = SELECT url FROM pages
待抓 = A - B

第一次运行:|A|=45, |B|=0  → todo=45, new_rows=45
第二次运行:|A|=45, |B|=45 → todo=0

6. 分层与后续插槽

            Day 191(今天)        Day 192–195
Frontier    deque + seen      →  Redis 队列 / 优先级
Fetcher     urllib + 桶       →  代理池 / 浏览器渲染
Parser      href + title      →  JS 解析 / NLP 归类
Pipeline    title/len         →  清洗 / 结构化
Sink        SQLite UPSERT     →  Postgres / ES