Skip to content

[Bug]: PruningContentFilter cuts inline spans out of sentences it keeps (e.g. "renamed Tokyo (lit. '')") #2417

Open

Description

@siosig

crawl4ai version

0.9.4 (reproduced). PruningContentFilter (crawl4ai/content_filter_strategy.py) is unchanged in v0.9.5 and on main (checked 2026-10-19).

Expected Behavior

When PruningContentFilter keeps a paragraph, the words inside that paragraph stay. A filter that removes a whole block is expected; a kept sentence with words missing from its middle is not.

Current Behavior

A <span> whose content is another element, such as a span around a link or a span around a span, is removed from a paragraph that is otherwise kept. Wikipedia marks up glosses and native-script names this way, so on https://en.wikipedia.org/wiki/Tokyo fit_markdown reads:

the city was renamed Tokyo (lit. '')

The source HTML is (<abbr>lit.</abbr> ... <span class="gloss-text"><a href="...">Eastern Capital</a></span> ...).

In the snippet below, plain spans, <strong>, <em> and links placed directly in the paragraph are kept; only the nested spans are lost.

My reading of the cause: _prune_tree scores every descendant element as if it were a block, and the score includes text density (text length over markup length) and link density. A short span whose only content is another element has little text against its markup, because the inner element's tags count as markup too. When the inner element is a link, the link density is also 1. Either way the span scores under the threshold and is removed.

Is this reproducible?

Yes

Inputs Causing the Bug

HTML with short nested inline spans inside a paragraph, for example https://en.wikipedia.org/wiki/Tokyo.

Steps to Reproduce

  1. Run the snippet below.
  2. Compare the default output with the paragraphs in HTML.

Code snippets

import asyncio
from crawl4ai import AsyncWebCrawler, CrawlerRunConfig, CacheMode, DefaultMarkdownGenerator, PruningContentFilter

HTML = """<html><body><article>
<p>After the <a href="/wiki/Meiji_Restoration">Meiji Restoration</a> (1868), the imperial capital in <a href="/wiki/Kyoto">Kyoto</a> was moved to Edo, and the city was renamed Tokyo (<abbr title="literal translation">lit.</abbr> <span class="gloss-quot">'</span><span class="gloss-text"><a href="/wiki/Capital_of_Japan">Eastern Capital</a></span><span class="gloss-quot">'</span>). The city was greatly damaged by the 1923 earthquake and rebuilt in the following decades.</p>
<p>Tokyo (<span title="Japanese-language text"><span lang="ja">東京</span></span>) is the capital of Japan and one of the most populous cities in the world, with a population of about fourteen million.</p>
<p>The museum near the harbour holds <span>old maps</span> of the bay, <strong>ship models</strong> and <em>letters</em> written by the first merchants who settled on the northern quay.</p>
</article></body></html>"""

async def main():
    async with AsyncWebCrawler() as crawler:
        for name, flt in [("default", PruningContentFilter()), ("preserve_tags=['span']", PruningContentFilter(preserve_tags=["span"]))]:
            config = CrawlerRunConfig(cache_mode=CacheMode.BYPASS, markdown_generator=DefaultMarkdownGenerator(content_filter=flt))
            result = await crawler.arun("raw:" + HTML, config=config)
            print(f"--- {name}")
            print(result.markdown.fit_markdown)

asyncio.run(main())

Output on 0.9.4:

--- default
After the [Meiji Restoration](/wiki/Meiji_Restoration) (1868), the imperial capital in [Kyoto](/wiki/Kyoto) was moved to Edo, and the city was renamed Tokyo (lit. ''). The city was greatly damaged by the 1923 earthquake and rebuilt in the following decades.
Tokyo () is the capital of Japan and one of the most populous cities in the world, with a population of about fourteen million.
The museum near the harbour holds old maps of the bay, **ship models** and _letters_ written by the first merchants who settled on the northern quay.
  *[lit.]: literal translation

--- preserve_tags=['span']
After the [Meiji Restoration](/wiki/Meiji_Restoration) (1868), the imperial capital in [Kyoto](/wiki/Kyoto) was moved to Edo, and the city was renamed Tokyo (lit. '[Eastern Capital](/wiki/Capital_of_Japan)'). The city was greatly damaged by the 1923 earthquake and rebuilt in the following decades.
Tokyo (東京) is the capital of Japan and one of the most populous cities in the world, with a population of about fourteen million.
The museum near the harbour holds old maps of the bay, **ship models** and _letters_ written by the first merchants who settled on the northern quay.
  *[lit.]: literal translation

Workaround and suggestion

preserve_tags=["span"] fixes it: a preserved element is kept whole and not scored. On the Tokyo page it grows fit_markdown by about 2% (139,263 to 141,985 characters), so it does not let noticeably more noise through. Lowering the threshold, the workaround discussed in #582, applies to the whole page instead.

Since a filter that keeps a block should keep the block's words, a possible fix is to stop scoring inline (phrasing) elements on their own and let them follow their nearest block ancestor. Making span part of the default preserve_tags would cover the cases above with a smaller change.

#582 reported a similar symptom for <a> and <strong> and was closed after tuning the threshold. This report is narrower: the kept sentence itself is left with holes.

OS

Debian GNU/Linux 12 (bookworm), in the official unclecode/crawl4ai:0.9.4 Docker image

Python version

3.12.14

Error logs & Screenshots (if applicable)

None.

Activity

  1. siva23367 commented on Oct 19, 2026

    @siva23367

    I would like to fix this issue, please assign it to me @siosig

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    🐞 BugSomething isn't working🩺 Needs TriageNeeds attention of maintainers

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions