[Bug]: After a streamed deep crawl is stopped early, the next deep crawl returns only the start page
メンテナーはふだん 3 日以内に返信
評価
調査の方向性
Start at DeepCrawlDecorator, where the deep_crawl_active ContextVar is set to True, and at the finally in its stream wrapper that resets it. Run the reproduction script in the issue: a full crawl, a crawl stopped after two pages, then a third crawl that should return six pages but returns one. Done means the third crawl is no longer treated as nested. Pull request #2386 already targets this, so check it before starting.
索引モデルが issue の本文から書いたものです。
説明
crawl4ai version
0.9.5 (same on 0.9.0)
Expected Behavior
Every crawler.arun(url, config) with a deep_crawl_strategy and stream=True runs a deep crawl, including after a previous streamed deep crawl was stopped early.
Current Behavior
If the caller stops iterating a streamed deep crawl (break), the next deep crawl from the same task returns only the start page.
DeepCrawlDecorator sets the deep_crawl_active ContextVar to True and resets it in the finally of the stream wrapper. When the caller leaves the stream without closing it, that finally runs later, when the generator is garbage-collected, in another context. The flag stays True in the caller's context, so the next arun() is treated as a nested call and falls through to a single-page crawl. The same happens if the stream is consumed from another task (for example asyncio.create_task(anext(stream))): the reset only reaches that task's copy of the context.
Is this reproducible?
Yes
Code snippets
import asyncio
from aiohttp import web
from crawl4ai import AsyncWebCrawler, CrawlerRunConfig
from crawl4ai.deep_crawling import BFSDeepCrawlStrategy
PAGES = 5
async def handle(request):
links = "".join(f'<a href="/p{i}">p{i}</a>' for i in range(PAGES)) if request.path == "/" else ""
return web.Response(text=f"<html><body>{links}<p>{'text ' * 200}</p></body></html>", content_type="text/html")
async def deep_crawl(crawler, url, stop_after=None):
config = CrawlerRunConfig(deep_crawl_strategy=BFSDeepCrawlStrategy(max_depth=1), stream=True)
pages = []
async for result in await crawler.arun(url, config=config):
pages.append(result.url)
if stop_after and len(pages) == stop_after:
break # e.g. the caller restarts the crawl with another browser config
return pages
async def main():
app = web.Application()
app.router.add_get("/{tail:.*}", handle)
runner = web.AppRunner(app)
await runner.setup()
await web.TCPSite(runner, "127.0.0.1", 8765).start()
url = "http://127.0.0.1:8765/"
async with AsyncWebCrawler() as crawler:
print("full crawl:", len(await deep_crawl(crawler, url))) # 6
print("stopped early:", len(await deep_crawl(crawler, url, stop_after=2))) # 2
print("next crawl:", len(await deep_crawl(crawler, url))) # 1, expected 6
await runner.cleanup()
asyncio.run(main())
Suggested fix
Reset the flag as soon as deep_crawl_strategy.arun() has returned the stream, with the token from set(), instead of in the stream's finally. The strategies' own batches already run with deep_crawl_strategy=None, so the guard is not needed while the stream is consumed. Callers can work around it by closing the stream in their own task (async with contextlib.aclosing(stream)).
- 主要言語
- Python
- スター
- 85.9k
- フォーク
- 8.9k
- 平均マージ
- 5日 6時間
- マージ済み PR(30日)
- 24
環境構築
- Dockerfile または Docker Compose ファイルあり
- プルリクエストのテンプレートあり
- コントリビューションガイドを読む
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
unclecode/crawl4ai のほかの issue
-
[Bug]: Text after an inline <link>, <meta>, <style> or <noscript> is dropped from cleaned_html and markdown対応中かも このイシューにリンクされたプルリクエストがオープン中、またはマージ済みです。 オープン🐞 Bug 🩺 Needs Triage
難易度 2/5 1〜3時間 初心者へのやさしさ 85/100
unclecode/crawl4ai#2416 · コメント 1 件 ·
メンテナーはふだん 3 日以内に返信
-
[Bug]: Since 0.9.1, Linux launches chrome-headless-shell instead of Chromium対応中かも このイシューにリンクされたプルリクエストがオープン中、またはマージ済みです。 オープン🐞 Bug 🩺 Needs Triage
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
unclecode/crawl4ai#2382 · コメント 1 件 ·
メンテナーはふだん 3 日以内に返信
-
[Bug]: BestFirstCrawlingStrategy fetches a full batch past max_pages対応中かも このイシューにリンクされたプルリクエストがオープン中、またはマージ済みです。 オープン🐞 Bug 🩺 Needs Triage
難易度 2/5 1〜3時間 初心者へのやさしさ 74/100
unclecode/crawl4ai#2381 · コメント 1 件 ·
メンテナーはふだん 3 日以内に返信
-
[Bug]: CrawlerRunConfig.clone() drops fallback_fetch_function, so deep crawls never use it対応中かも @siva23367 が 2 日前に担当しました。 オープン🐞 Bug 🩺 Needs Triage
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
unclecode/crawl4ai#2379 · コメント 1 件 ·
メンテナーはふだん 3 日以内に返信
-
[Bug]: Docker memory guard reads host RAM when no container limit is set — cgroup v2 "max" defeats get_container_memory_percent対応中かも @Battleplus が 58 日前に担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
unclecode/crawl4ai#2123 · コメント 1 件 ·
メンテナーはふだん 3 日以内に返信
unclecode/crawl4ai の issue をすべて見る
似ている issue
-
難易度 1/5 1時間未満 初心者へのやさしさ 80/100
521xueweihan/HelloGitHub#4063 ·
-
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
-
難易度 2/5 1〜3時間 初心者へのやさしさ 62/100
Vanilla-OS/apx-gui#112 ·
-
Devstral and Voxtral: section 5 fails in us-east-1 with 400 "Model does not support audio modality"オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 76/100
aws-samples/sample-per-model-bedrock#409 ·
メンテナーはふだん 1 日以内に返信
-
DuckDB 2.0 breaks to_pyarrow_batches対応中かも @DG47 が今日担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 76/100
ibis-project/ibis#12196 ·
メンテナーはふだん 1 日以内に返信