diff --git a/crawl4ai/html2text/__init__.py b/crawl4ai/html2text/__init__.py
index ff39fb211..7184c7da0 100644
--- a/crawl4ai/html2text/__init__.py
+++ b/crawl4ai/html2text/__init__.py
@@ -1119,17 +1119,17 @@ def handle_tag(self, tag, attrs, start):
if self.preserve_depth == 0:
self.current_preserved_tag = tag
self.preserved_content = []
- # Format opening tag with attributes
- attr_str = "".join(
- f' {k}="{v}"' for k, v in attrs.items() if v is not None
- )
- self.preserved_content.append(f"<{tag}{attr_str}>")
+ # Record nested preserved tags as well as the outer block.
+ attr_str = "".join(
+ f' {k}="{v}"' for k, v in attrs.items() if v is not None
+ )
+ self.preserved_content.append(f"<{tag}{attr_str}>")
self.preserve_depth += 1
return
else:
+ self.preserved_content.append(f"{tag}>")
self.preserve_depth -= 1
if self.preserve_depth == 0:
- self.preserved_content.append(f"{tag}>")
# Output the preserved HTML block with proper spacing
preserved_html = "".join(self.preserved_content)
self.o("\n" + preserved_html + "\n")
diff --git a/tests/unit/test_markdown_preserved_tags.py b/tests/unit/test_markdown_preserved_tags.py
new file mode 100644
index 000000000..6bff13cf3
--- /dev/null
+++ b/tests/unit/test_markdown_preserved_tags.py
@@ -0,0 +1,46 @@
+"""Regression tests for nested tags preserved during Markdown generation."""
+
+import pytest
+
+from crawl4ai import DefaultMarkdownGenerator
+
+
+@pytest.mark.parametrize(
+ ("html", "preserve_tags"),
+ [
+ (
+ '
',
+ ["div"],
+ ),
+ (
+ '',
+ ["section", "div"],
+ ),
+ (
+ "",
+ ["table"],
+ ),
+ (
+ '",
+ ["div"],
+ ),
+ (
+ 'outerinnerend
',
+ ["div"],
+ ),
+ (
+ 'one
two
',
+ ["div"],
+ ),
+ ],
+ ids=["same-tag", "mixed-tags", "nested-table", "three-levels", "child", "siblings"],
+)
+def test_markdown_preserves_nested_html_tags(html, preserve_tags):
+ generator = DefaultMarkdownGenerator(options={"preserve_tags": preserve_tags})
+
+ result = generator.generate_markdown(html, citations=False)
+
+ # Preserved blocks gain separating newlines, but retain their HTML structure.
+ assert result.raw_markdown.strip().replace("\n", "") == html