Repository navigation
fix(pdf): keep PDF URI links in ScrapingResult.links (#2374) - #2375
Merged
Merged
Conversation
PDFContentScrapingStrategy.scrap() built links as {"urls": [{"url", "page"}]},
but ScrapingResult.links is a Links model with only internal/external lists
of Link items keyed by href, so pydantic dropped the unknown key and every
URI annotation the PDF processor extracted was lost while success=True.
Build Links directly: classify each target against the PDF URL's domain the
way the HTML scraper does (a local PDF has no domain, so its absolute links
are external), resolve relative targets against a remote PDF URL, and report
each target once. Update the PDF parsing docs to describe the shape.
ntohidi
approved these changes
Oct 20, 2026
ntohidi
left a comment
Collaborator
There was a problem hiding this comment.
Thanks @Hugo-DDT, this looks good. Putting the links into Links with the same domain helpers the HTML scraper uses is the right fix, and keeping Link unchanged means HTML results stay the same. Tests pass on my side too. Dropping the page number is fine for now. Approving.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #2374
PDFContentScrapingStrategy.scrap()collected the PDF's URI annotations aslinks = {"urls": [{"url": ..., "page": ...}]}and passed that toScrapingResult.ScrapingResult.linksis aLinksmodel with onlyinternal/externallists ofLinkitems (keyed byhref), so pydantic dropped the unknownurlskey. The processor found the links, the result saidsuccess=True, andlinkscame back empty.The strategy now builds
Linksitself:get_base_domain/is_external_urlhelpers the HTML scraper uses. A local PDF has no domain, so all of its absolute links areexternal;mailto:etc. stay external as in HTML.Linkhas no page field, so the page number is not kept on the link. I left the sharedLinkmodel alone so HTML results don't change shape; the page is still visible incleaned_html(data-pagedivs). I'm happy to add a page field in a follow-up if you'd like one.Before / after with the issue's repro (one-page PDF, one URI annotation):
List of files changed and why
crawl4ai/processors/pdf/__init__.py: add_build_links()and use it inscrap()in place of the{"urls": [...]}dict.tests/unit/test_pdf_scraping_links_2374.py: regression tests on generated PDFs (pypdf only, no network): a local PDF's link survives as external; a remote PDF URL splits same-domain vs other-domain /mailto:links and dedupes a target repeated on two pages; the links survivemodel_dump()(whatarunputs onCrawlResult.links).docs/md_v2/advanced/pdf-parsing.md: the docs describedlinks["urls"]; describelinks.internal/links.externalinstead.How Has This Been Tested?
pytest tests/unit/test_pdf_scraping_links_2374.py: 3 failed ondevelop(2efcccc), 3 passed with the fix.pytest tests/unit/test_pdf_download_limits.py tests/unit/test_pdf_html_escaping.py tests/unit/test_pdf_page_number_race.py tests/unit/test_crawl_result_default_shape.py: pass.pytest tests/unit: 202 passed, 6 skipped; the 6 failures intest_browser_tls_sandbox_flags.pyfail the same way ondevelopwithout this change (no browser in my environment).ruff check --select Fclean on the changed files; new test file formatted with black.Checklist: