[Bug]: preserve_tags/preserve_classes are a no-op for excluded tags (aside, nav, footer, header, form)
Los mantenedores suelen responder en 1 día
@Battleplus ya está trabajando en esto.
Desde el 22/8/2026.
Evaluación
- Dificultad
- 3/5
- Tiempo estimado
- 1-2 días
- Aptitud para principiantes
- 78/100
Línea de trabajo
Start in content_filter_strategy.py, especially filter_content(), _remove_unwanted_tags(), and _is_preserved(). Run the provided HTML snippet without a browser or network, then trace how excluded tags are removed before preservation is checked. Done means preserve_tags and preserve_classes retain matching aside content while the default still excludes it.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
crawl4ai version
0.9.2
Expected Behavior
PruningContentFilter(preserve_tags=["aside"]) should keep <aside> content in fit_markdown.
#1900 added these options as an escape hatch for content the fit pipeline treats as boilerplate but the user knows is real content.
Same for preserve_classes=["related"] on an <aside class="related">.
Current Behavior
Both options are silently ignored for every tag in excluded_tags (content_filter_strategy.py:101-110): nav, footer, header, aside, script, style, form, iframe, noscript.
filter_content() removes those tags before pruning ever runs:
self._remove_unwanted_tags(soup) # content_filter_strategy.py:664, decomposes aside
body = soup.find("body")
self._prune_tree(body) # :668, the only place _is_preserved() is consulted
_remove_unwanted_tags decomposes by tag name and never consults the whitelist:
def _remove_unwanted_tags(self, soup): # :685
"""Removes unwanted tags"""
for tag in self.excluded_tags:
for element in soup.find_all(tag):
element.decompose()
By the time _is_preserved() (:691) is reached, the node is gone from the tree.
The filter raises nothing and logs nothing.
excluded_tags is hardcoded in RelevantContentFilter.__init__, not a constructor argument, so the only workaround is mutating the instance attribute (f.excluded_tags.discard("aside")).
Is this reproducible?
Yes
Inputs Causing the Bug
- URL(s): none needed, filter_content() takes an HTML string directly
- Settings used: PruningContentFilter(preserve_tags=["aside"])
- Input data: any HTML with an <aside> holding real content
Steps to Reproduce
1. Run the snippet below (no browser, no network).
2. All three cases print "aside kept: False".
3. Expected: True for the preserve_tags and preserve_classes cases.
Code snippets
from crawl4ai.content_filter_strategy import PruningContentFilter
html = (
"<html><body>"
"<article><p>" + "Main article body with plenty of words to pass the pruning threshold easily. " * 8 + "</p></article>"
'<aside class="related"><h2>Related reading</h2><p>'
+ "This sidebar note is real content the author wrote and wants kept. " * 8
+ "</p></aside>"
"</body></html>"
)
for kwargs in ({}, {"preserve_tags": ["aside"]}, {"preserve_classes": ["related"]}):
out = " ".join(PruningContentFilter(**kwargs).filter_content(html))
print(kwargs, "-> aside kept:", "Related reading" in out)
# 0.9.2 / develop @ 2d8f673:
# {} -> aside kept: False # correct, that's the default
# {'preserve_tags': ['aside']} -> aside kept: False # BUG
# {'preserve_classes': ['related']} -> aside kept: False # BUG
OS
macOS
Python version
3.12
Browser
N/A
Browser version
No response
Error logs & Screenshots (if applicable)
No response
- Lenguaje dominante
- Python
- Estrellas
- 85.4k
- Forks
- 8.9k
- Merge medio
- 5 d 7 h
- PR fusionados (30 d)
- 23
Preparar el entorno
- Incluye un Dockerfile o un archivo de Docker Compose
- Tiene una plantilla de pull request
- Leer la guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de unclecode/crawl4ai
-
[Bug]: Text after an inline <link>, <meta>, <style> or <noscript> is dropped from cleaned_html and markdownPosiblemente ocupada Un pull request vinculado a esta issue está abierto o ya se fusionó. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 85/100
unclecode/crawl4ai#2416 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
[Bug]: Since 0.9.1, Linux launches chrome-headless-shell instead of ChromiumPosiblemente ocupada Un pull request vinculado a esta issue está abierto o ya se fusionó. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
unclecode/crawl4ai#2382 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
[Bug]: BestFirstCrawlingStrategy fetches a full batch past max_pagesPosiblemente ocupada Un pull request vinculado a esta issue está abierto o ya se fusionó. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 74/100
unclecode/crawl4ai#2381 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
[Bug]: CrawlerRunConfig.clone() drops fallback_fetch_function, so deep crawls never use itPosiblemente ocupada @siva23367 la tomó hoy. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
unclecode/crawl4ai#2379 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
[Bug]: Docker memory guard reads host RAM when no container limit is set — cgroup v2 "max" defeats get_container_memory_percentPosiblemente ocupada @Battleplus la tomó hace 57 días. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
unclecode/crawl4ai#2123 · 1 comentario ·
Los mantenedores suelen responder en 1 día
Todos los issues de unclecode/crawl4ai
Issues similares
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 74/100
eclipse-score/inc_someip_gateway#356 ·
Los mantenedores suelen responder en 2 días
-
[BUG]: `GitHubRestAdapter.check_user_permission` and `has_write_access` raise `TypeError` (missing `params`), silently disabling the inactivity lifecyclePosiblemente ocupada @tarunagnihotri534 la tomó hoy. Abiertobug
Dificultad 2/5 1-3 horas Aptitud para principiantes 67/100
AOSSIE-Org/Gitcord-GithubDiscordBot#167 · 1 comentario ·
Los mantenedores suelen responder en 2 días
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 77/100
mihai-vlc/sublime-jsfmt#56 ·
-
comp/cli comp/plugins P2 type/bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 75/100
NousResearch/hermes-agent#141917 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
Dificultad 1/5 Menos de una hora Aptitud para principiantes 78/100
riscv/riscv-opcodes#441 ·