Skip to content

Add Cloudflare Puppeteer scraper + Tavily fallback for article extraction#39

Merged
vtempest merged 1 commit into
masterfrom
claude/scraper-cloudflare-qwksearch-7di3to
Jul 6, 2026
Merged

Add Cloudflare Puppeteer scraper + Tavily fallback for article extraction#39
vtempest merged 1 commit into
masterfrom
claude/scraper-cloudflare-qwksearch-7di3to

Conversation

@vtempest

@vtempest vtempest commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator

Summary

Implements a bounded fallback chain for article extraction that prioritizes JavaScript-aware rendering over plain HTTP fetching. The new extraction pipeline uses the Cloudflare Puppeteer scraper (8s deadline) as the primary path, falls back to Tavily extract API when the scraper times out or returns challenge pages, and finally falls back to direct in-process extraction as a last resort.

Key Changes

  • New scrape-url.ts module: Provides two main extraction functions:

    • extractArticleViaScraper(): Renders URLs through the Cloudflare Puppeteer scraper worker with an 8-second deadline, detects bot-challenge interstitials (Cloudflare, Datadome, AP News), and extracts content via readability. Never throws—returns { error } on failure.
    • extractViaTavily(): Fallback extraction via Tavily's extract API when the scraper is unavailable or times out. Converts Tavily's markdown-like raw_content to HTML and builds APA-style citations.
  • Updated /api/doc/article route: Implements the three-tier extraction fallback:

    1. Cloudflare Puppeteer scraper (8s deadline)
    2. Tavily extract API (when scraper fails/times out)
    3. Direct in-process extractContent() (last resort)

    Each tier logs its decision and reason for advancing to the next tier, enabling observability of which extraction path succeeds.

  • Updated scraper client configuration: Changed default scraper endpoint from https://scraper.qwksearch.workers.dev to https://proxy.qwksearch.com and added AbortSignal support for deadline enforcement.

  • Updated url-to-html.ts: Migrated scraper requests from POST with JSON body to GET with query-string parameters to match the deployed worker's API.

  • Enhanced test coverage: Added tests for scraper and Tavily extraction paths, with mocks that default to "unavailable" so existing tests exercise the extractContent fallback.

Notable Implementation Details

  • Challenge page detection: Checks rendered HTML for markers like "Just a moment...", "Verifying you are human", and "Attention Required! | Cloudflare" to identify bot-protection interstitials and trigger fallback.
  • Word count calculation: Strips HTML tags and counts whitespace-separated tokens for consistent word count across all extraction paths.
  • Citation building: Generates APA-style citations with author, date, title, source, and URL, mirroring the format used by the in-process extractor.
  • Graceful degradation: All extraction functions return { error } instead of throwing, allowing the route to cleanly decide whether to advance to the next tier without try-catch complexity.

https://claude.ai/code/session_01PZnQTSy6fHh8Y6naPkxYrC

…traction with 8s bound + Tavily fallback

Wire the deployed Cloudflare Puppeteer scraper (proxy.qwksearch.com) into the
qwksearch-web /api/doc/article extraction path so JavaScript-heavy and lightly
bot-protected pages render before readability extraction.

Fresh extraction now uses a bounded fallback chain:
  1. Cloudflare Puppeteer scraper, 8s deadline (renders + readability)
  2. Tavily extract API (when the scraper times out or returns a challenge page)
  3. In-process ai-research-agent extraction (last resort)

- lib/scraper/scrape-url.ts: new extractArticleViaScraper (8s AbortController
  deadline, challenge-page detection, citation/word-count enrichment) and
  extractViaTavily fallback.
- cloudflare-scraper-client.ts: default to proxy.qwksearch.com and call the
  worker over GET with query params (the deployed worker rejects POST with
  error 1101); add AbortSignal support to bound requests.
- api/doc/article/route.ts: primary scraper -> Tavily -> extractContent chain,
  each tier returning {error} instead of throwing.
- extract-webpage url-to-html.ts: point scrapeCloudflare at proxy.qwksearch.com
  over GET for consistency.
- Tests: mock the scraper + Tavily helpers; add scraper-success and
  Tavily-fallback cases.

Verified end-to-end: Wikipedia articles extract via the scraper in 3-5s
(1394 and 1895 words); heavily-protected AP News aborts at the 8s deadline and
advances to the Tavily fallback.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PZnQTSy6fHh8Y6naPkxYrC
@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
qwksearch 8337c45 Commit Preview URL

Branch Preview URL
Jul 06 2026, 09:42 AM

@vtempest vtempest merged commit 2d2796f into master Jul 6, 2026
2 of 3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants