Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 16 additions & 3 deletions crawl4ai/async_webcrawler.py
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,7 @@ async def arun(
_block_reason = ""
_done = False
crawl_result = None
_is_pdf_response = False
_crawl_stats = {
"attempts": 0,
"retries": 0,
Expand Down Expand Up @@ -458,6 +459,13 @@ async def arun(

async_response = await self.crawler_strategy.crawl(
url, config=config)
_is_pdf_response = any(
key.lower() == "content-type"
and "application/pdf" in str(value).lower()
for key, value in (
async_response.response_headers or {}
).items()
)

html = sanitize_input_encode(async_response.html)
screenshot_data = async_response.screenshot
Expand Down Expand Up @@ -505,7 +513,7 @@ async def arun(

# Check if blocked (skip for raw: URLs —
# caller-provided content, anti-bot N/A)
if _is_raw_url:
if _is_raw_url or _is_pdf_response:
_blocked = False
_block_reason = ""
else:
Expand Down Expand Up @@ -625,7 +633,12 @@ async def arun(
# empty by design, and is_blocked() would misread "0 bytes
# html" as a block.
_has_download = bool(getattr(crawl_result, "downloaded_files", None))
if not _fallback_succeeded and not _is_raw_url and not _has_download:
if (
not _fallback_succeeded
and not _is_raw_url
and not _has_download
and not _is_pdf_response
):
_blocked, _block_reason = is_blocked(
crawl_result.status_code, crawl_result.html or "")
if _blocked:
Expand Down Expand Up @@ -1246,4 +1259,4 @@ async def amap_domain(
config or DomainMapperConfig(**kwargs) if kwargs else DomainMapperConfig()
)

return await self._domain_mapper.scan(domain, mapper_config)
return await self._domain_mapper.scan(domain, mapper_config)
30 changes: 30 additions & 0 deletions tests/test_issue_2135_pdf_antibot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import pytest

from crawl4ai import AsyncWebCrawler, CacheMode, CrawlerRunConfig, CrawlResult
from crawl4ai.processors.pdf import PDFCrawlerStrategy


@pytest.mark.asyncio
async def test_pdf_response_skips_antibot_retries_and_fallback():
fallback_calls = []

async def process_html(url, html, **kwargs):
return CrawlResult(url=url, html=html, success=True, status_code=200)

async def fallback(url):
fallback_calls.append(url)
return "<html>fallback</html>"

crawler = AsyncWebCrawler(crawler_strategy=PDFCrawlerStrategy())
crawler.aprocess_html = process_html
result = await crawler.arun(
"https://example.com/document.pdf",
config=CrawlerRunConfig(
cache_mode=CacheMode.BYPASS,
max_retries=1,
fallback_fetch_function=fallback,
),
)
assert result.success
assert result.crawl_stats["attempts"] == 1
assert fallback_calls == []