HTML 요소 및 페이지 부분을 C#에서 PDF로 변환하는 방법
IronPDF는 특정 HTML 요소를 대상으로 하는 내장 SelectElement 또는 SelectCss 메서드를 제공하지 않습니다. ChromePdfRenderer는 전체 HTML 문서(전체 페이지, 전체 URL, 전체 HTML 문자열)를 렌더링합니다. 페이지의 특정 섹션에서 PDF를 생성하기 위해 JavaScript DOM 조작, CSS 주입, 서버 측 HTML 조각 추출 또는 JS 타겟팅으로 URL 렌더링 중 하나의 방법을 사용하여 대상 요소를 렌더링 전에 분리합니다.
각 접근법은 다른 제약에 맞습니다. JavaScript DOM 격리는 URL 또는 전체 페이지를 렌더링할 때 대상 외의 모든 것을 제거해야 할 때 작동합니다. CSS 주입은 DOM을 변경하지 않고 불필요한 콘텐츠를 숨깁니다. 서버 측 추출은 원시 HTML에 액세스할 수 있을 때 가장 깨끗한 결과를 제공합니다. JS 타겟팅을 사용한 URL 렌더링은 소스 HTML을 사용할 수 없는 라이브 대시보드 및 타사 페이지를 처리합니다.
무료 30일 체험판 시작하기를 통해 모든 네 가지 방법을 테스트하세요.
빠른 시작: 특정 HTML 요소를 PDF로 추출하기
JavaScript DOM 격리 및 WaitFor를 사용하여 CSS 선택자로 요소를 지정하고, 해당 부분만 PDF로 렌더링합니다.
-
NuGet 패키지 관리자를 사용하여 https://www.nuget.org/packages/IronPdf 설치하기
PM > Install-Package IronPdf -
다음 코드 조각을 복사하여 실행하세요.
using IronPdf; var renderer = new ChromePdfRenderer(); renderer.RenderingOptions.EnableJavaScript = true; renderer.RenderingOptions.JavaScript = @" var target = document.querySelector('#invoice-summary'); document.body.innerHTML = target.outerHTML; "; renderer.RenderingOptions.WaitFor.HtmlQuerySelector("#invoice-summary", 10000); var pdf = renderer.RenderHtmlAsPdf(fullPageHtml); pdf.SaveAs("invoice-summary.pdf"); -
실제 운영 환경에서 테스트할 수 있도록 배포하세요.
무료 체험판으로 오늘 프로젝트에서 IronPDF 사용 시작하기
최소 워크플로 (3단계)
- NuGet을 통해
IronPdf설치:Install-Package IronPdf ChromePdfRenderOptions.JavaScript을 구성하여 대상 요소를 분리하고,WaitFor을 구성하여 해당 요소가 존재하는지 확인하십시오.RenderHtmlAsPdf()또는RenderUrlAsPdf()호출 — PDF에는 분리된 콘텐츠만 포함되어 있습니다
JavaScript DOM 조작으로 요소를 어떻게 격리하나요?
ChromePdfRenderOptions.JavaScript 속성은 HTML이 로드된 후, PDF가 렌더링되기 전에 실행되는 JavaScript 문자열을 받아들입니다. document.body.innerHTML을 대상 요소의 outerHTML으로 대체함으로써, 렌더링된 페이지에서 나머지 모든 내용을 제거합니다. 이것이 가장 다용도로 활용 가능한 접근 방식입니다. RenderHtmlAsPdf()와 RenderUrlAsPdf() 모두에서 작동합니다.
WaitFor.HtmlQuerySelector() 메서드는 JavaScript가 실행되기 전에 대상 요소가 DOM에 존재하는지 확인합니다. 이는 비동기 콘텐츠가 있는 페이지 — React 컴포넌트, Angular 템플릿, API 구동 데이터가 초기 페이지 로드 후 채워지는 경우 — 에 중요합니다.
using IronPdf;
string fullPageHtml = @"
<html>
<body>
<header><h1>Acme Corp Invoice</h1></header>
<nav>Navigation links...</nav>
<div id='invoice-summary'>
<h2>Invoice #12345</h2>
<table>
<tr><td>Widget A</td><td>$49.99</td></tr>
<tr><td>Widget B</td><td>$29.99</td></tr>
<tr><td><strong>Total</strong></td><td><strong>$79.98</strong></td></tr>
</table>
</div>
<footer>Footer content...</footer>
</body>
</html>";
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.EnableJavaScript = true;
// Replace the body with only the target element
renderer.RenderingOptions.JavaScript = @"
var el = document.querySelector('#invoice-summary');
if (el) {
document.body.innerHTML = el.outerHTML;
}
";
// Wait for the target element to exist before JS executes
renderer.RenderingOptions.WaitFor.HtmlQuerySelector("#invoice-summary", 10000);
PdfDocument pdf = renderer.RenderHtmlAsPdf(fullPageHtml);
pdf.SaveAs("invoice-summary-only.pdf");
using IronPdf;
string fullPageHtml = @"
<html>
<body>
<header><h1>Acme Corp Invoice</h1></header>
<nav>Navigation links...</nav>
<div id='invoice-summary'>
<h2>Invoice #12345</h2>
<table>
<tr><td>Widget A</td><td>$49.99</td></tr>
<tr><td>Widget B</td><td>$29.99</td></tr>
<tr><td><strong>Total</strong></td><td><strong>$79.98</strong></td></tr>
</table>
</div>
<footer>Footer content...</footer>
</body>
</html>";
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.EnableJavaScript = true;
// Replace the body with only the target element
renderer.RenderingOptions.JavaScript = @"
var el = document.querySelector('#invoice-summary');
if (el) {
document.body.innerHTML = el.outerHTML;
}
";
// Wait for the target element to exist before JS executes
renderer.RenderingOptions.WaitFor.HtmlQuerySelector("#invoice-summary", 10000);
PdfDocument pdf = renderer.RenderHtmlAsPdf(fullPageHtml);
pdf.SaveAs("invoice-summary-only.pdf");
Imports IronPdf
Dim fullPageHtml As String = "
<html>
<body>
<header><h1>Acme Corp Invoice</h1></header>
<nav>Navigation links...</nav>
<div id='invoice-summary'>
<h2>Invoice #12345</h2>
<table>
<tr><td>Widget A</td><td>$49.99</td></tr>
<tr><td>Widget B</td><td>$29.99</td></tr>
<tr><td><strong>Total</strong></td><td><strong>$79.98</strong></td></tr>
</table>
</div>
<footer>Footer content...</footer>
</body>
</html>"
Dim renderer As New ChromePdfRenderer()
renderer.RenderingOptions.EnableJavaScript = True
' Replace the body with only the target element
renderer.RenderingOptions.JavaScript = "
var el = document.querySelector('#invoice-summary');
if (el) {
document.body.innerHTML = el.outerHTML;
}
"
' Wait for the target element to exist before JS executes
renderer.RenderingOptions.WaitFor.HtmlQuerySelector("#invoice-summary", 10000)
Dim pdf As PdfDocument = renderer.RenderHtmlAsPdf(fullPageHtml)
pdf.SaveAs("invoice-summary-only.pdf")
이 JavaScript 코드는 본문 전체를 #invoice-summary div의 outerHTML로 대체합니다. 결과 PDF는 인보이스 테이블만 포함하며, 헤더, 내비게이션, 풋터는 포함하지 않습니다. WaitFor.HtmlElementById() 메서드는 ID를 기준으로 타겟팅할 때 더 간단한 대안을 제공합니다:
// Alternative: wait by ID directly
renderer.RenderingOptions.WaitFor.HtmlElementById("invoice-summary", 10000);
// Alternative: wait by ID directly
renderer.RenderingOptions.WaitFor.HtmlElementById("invoice-summary", 10000);
' Alternative: wait by ID directly
renderer.RenderingOptions.WaitFor.HtmlElementById("invoice-summary", 10000)
복잡한 선택자(클래스 이름, 데이터 속성, 중첩된 요소)의 경우, HtmlQuerySelector()은 document.querySelector()이 허용하는 모든 유효한 CSS 선택자 문자열을 허용합니다. 추가적인 WaitFor 편의 메서드로는 HtmlElementByClassName(), HtmlElementByName() 및 HtmlElementByTagName()가 있습니다. 이 메서드들은 내부적으로 HtmlQuerySelector()를 위임하지만, 코드 내에서 의도를 더 명확하게 전달합니다.
대상 요소가 상위 컨테이너에서 상속된 스타일에 의존하는 경우, outerHTML 대체를 사용하면 조상 선택자(예: .dashboard .widget table { ...)에 의존하는 CSS 규칙이 누락될 수 있습니다. }). 이를 유지하려면 <head>에서 관련 <style> 및 <link> 태그를 복사하여 JS 격리 영역에 붙여넣으십시오:
renderer.RenderingOptions.JavaScript = @"
var el = document.querySelector('#invoice-summary');
if (el) {
var head = document.head.innerHTML;
document.body.innerHTML = el.outerHTML;
document.head.innerHTML = head;
}
";
renderer.RenderingOptions.JavaScript = @"
var el = document.querySelector('#invoice-summary');
if (el) {
var head = document.head.innerHTML;
document.body.innerHTML = el.outerHTML;
document.head.innerHTML = head;
}
";
renderer.RenderingOptions.JavaScript = "
var el = document.querySelector('#invoice-summary');
if (el) {
var head = document.head.innerHTML;
document.body.innerHTML = el.outerHTML;
document.head.innerHTML = head;
}
"
이 번역은 본문만 교체하고 원본 <head> 콘텐츠(스타일시트, 폰트, 메타 태그)는 그대로 유지합니다. JavaScript를 PDF로 변환하는 방법과 WaitFor 사용법에는 여러 비동기 데이터 소스가 있는 페이지에 대한 NetworkIdle0()을 포함한 추가 구성 옵션이 설명되어 있습니다.
CSS 주입으로 요소를 어떻게 격리하나요?
ChromePdfRenderOptions.CustomCssUrl 속성은 IronPDF가 렌더링 전에 적용할 스타일시트의 파일 경로 또는 URL을 받습니다. DOM을 조작하는 대신, CSS display: none를 사용하여 대상 요소를 제외한 모든 요소를 숨깁니다. 이 방법은 원래의 DOM 구조를 유지하고 JavaScript 실행을 완전히 피합니다.
using IronPdf;
// Create a CSS file that hides everything except #invoice-summary
string cssContent = @"
body > *:not(#invoice-summary) {
display: none !important;
}
#invoice-summary {
display: block !important;
margin: 0;
padding: 20px;
}
";
File.WriteAllText("isolate-element.css", cssContent);
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.CustomCssUrl = "isolate-element.css";
PdfDocument pdf = renderer.RenderHtmlAsPdf(fullPageHtml);
pdf.SaveAs("invoice-css-isolated.pdf");
using IronPdf;
// Create a CSS file that hides everything except #invoice-summary
string cssContent = @"
body > *:not(#invoice-summary) {
display: none !important;
}
#invoice-summary {
display: block !important;
margin: 0;
padding: 20px;
}
";
File.WriteAllText("isolate-element.css", cssContent);
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.CustomCssUrl = "isolate-element.css";
PdfDocument pdf = renderer.RenderHtmlAsPdf(fullPageHtml);
pdf.SaveAs("invoice-css-isolated.pdf");
Imports IronPdf
Imports System.IO
' Create a CSS file that hides everything except #invoice-summary
Dim cssContent As String = "
body > *:not(#invoice-summary) {
display: none !important;
}
#invoice-summary {
display: block !important;
margin: 0;
padding: 20px;
}
"
File.WriteAllText("isolate-element.css", cssContent)
Dim renderer As New ChromePdfRenderer()
renderer.RenderingOptions.CustomCssUrl = "isolate-element.css"
Dim pdf As PdfDocument = renderer.RenderHtmlAsPdf(fullPageHtml)
pdf.SaveAs("invoice-css-isolated.pdf")
참고: CustomCssUrl 속성은 HTML 문자열에서 렌더링할 때만 RenderHtmlAsPdf()와 함께 작동합니다. URL 렌더링의 경우, CSS 삽입 코드를 JavaScript 속성에 포함시켜 주십시오:
renderer.RenderingOptions.JavaScript = @"
var style = document.createElement('style');
style.textContent = 'body > *:not(#invoice-summary) { display: none !important; }';
document.head.appendChild(style);
";
renderer.RenderingOptions.JavaScript = @"
var style = document.createElement('style');
style.textContent = 'body > *:not(#invoice-summary) { display: none !important; }';
document.head.appendChild(style);
";
renderer.RenderingOptions.JavaScript = "
var style = document.createElement('style');
style.textContent = 'body > *:not(#invoice-summary) { display: none !important; }';
document.head.appendChild(style);
"
소스 HTML을 제어할 수 있는 경우, @media print 규칙이 가장 가벼운 대안을 제공합니다. 외부 종속성이 없으며 런타임 주입이 필요하지 않습니다:
@media print {
header, nav, footer, .sidebar { display: none !important; }
#invoice-summary { width: 100%; margin: 0; }
}
렌더러에서 CssMediaType을 PdfCssMediaType.Print로 설정하여 이 규칙을 활성화하십시오:
renderer.RenderingOptions.CssMediaType = IronPdf.Rendering.PdfCssMediaType.Print;
renderer.RenderingOptions.CssMediaType = IronPdf.Rendering.PdfCssMediaType.Print;
renderer.RenderingOptions.CssMediaType = IronPdf.Rendering.PdfCssMediaType.Print
이는 애플리케이션에서 이미 @media print 규칙을 정의한 양식 섹션 PRINT 시나리오나, 양식 HTML이 서버 측에서 조립되는 경우의 '접근 방식 3'에 이상적입니다.
CSS 방식에는 한 가지 중요한 제한 사항이 있습니다. display: none을 잘못된 우선순위 수준에서 사용할 경우, 숨겨진 요소가 여전히 문서 흐름 내에서 공간을 차지하게 됩니다. 특정 브레이크포인트에서 요소가 다시 표시될 수 있는 프레임워크 스타일(Bootstrap, Tailwind)을 재정의할 때는 항상 !important를 사용하십시오. 깊이 중첩된 목표를 위해서는 더 정밀한 선택자가 동반되지 않은 숨기기를 피하도록 합니다.
body > *:not(#target),
body > *:not(#target) ~ * {
display: none !important;
}
서버 측에서 HTML 조각을 추출하는 방법은 무엇입니까?
파일, 데이터베이스, CMS 또는 HTTP 응답에서 원본 HTML에 접근할 수 있는 경우, 가장 깔끔한 접근 방식은 HTML 파서를 사용하여 서버 측에서 대상 요소를 추출한 다음, 해당 조각을 RenderHtmlAsPdf()로 전달하는 것입니다. JavaScript, CSS 주입 또는 런타임 DOM 조작이 아닙니다.
AngleSharp는 이 패턴에 필요한 .NET HTML 파서 표준입니다.
using IronPdf;
using AngleSharp;
using AngleSharp.Html.Parser;
string fullPageHtml = @"
<html>
<head>
<style>
table { border-collapse: collapse; width: 100%; }
td, th { border: 1px solid #ddd; padding: 8px; text-align: left; }
</style>
</head>
<body>
<header><h1>Dashboard</h1></header>
<div id='revenue-widget'>
<h3>Q4 Revenue</h3>
<table>
<tr><th>Month</th><th>Revenue</th></tr>
<tr><td>October</td><td>$1.2M</td></tr>
<tr><td>November</td><td>$1.5M</td></tr>
<tr><td>December</td><td>$1.8M</td></tr>
</table>
</div>
<div id='other-content'>Other widgets...</div>
</body>
</html>";
// Parse and extract the target element
var parser = new HtmlParser();
var document = parser.ParseDocument(fullPageHtml);
var targetElement = document.QuerySelector("#revenue-widget");
if (targetElement is null)
{
Console.WriteLine("Target element not found.");
return;
}
// Wrap the fragment in a minimal HTML document to preserve styles
string fragmentHtml = $@"
<html>
<head>
<style>
table {{ border-collapse: collapse; width: 100%; }}
td, th {{ border: 1px solid #ddd; padding: 8px; text-align: left; }}
</style>
</head>
<body>
{targetElement.OuterHtml}
</body>
</html>";
var renderer = new ChromePdfRenderer();
PdfDocument pdf = renderer.RenderHtmlAsPdf(fragmentHtml);
pdf.SaveAs("revenue-widget.pdf");
using IronPdf;
using AngleSharp;
using AngleSharp.Html.Parser;
string fullPageHtml = @"
<html>
<head>
<style>
table { border-collapse: collapse; width: 100%; }
td, th { border: 1px solid #ddd; padding: 8px; text-align: left; }
</style>
</head>
<body>
<header><h1>Dashboard</h1></header>
<div id='revenue-widget'>
<h3>Q4 Revenue</h3>
<table>
<tr><th>Month</th><th>Revenue</th></tr>
<tr><td>October</td><td>$1.2M</td></tr>
<tr><td>November</td><td>$1.5M</td></tr>
<tr><td>December</td><td>$1.8M</td></tr>
</table>
</div>
<div id='other-content'>Other widgets...</div>
</body>
</html>";
// Parse and extract the target element
var parser = new HtmlParser();
var document = parser.ParseDocument(fullPageHtml);
var targetElement = document.QuerySelector("#revenue-widget");
if (targetElement is null)
{
Console.WriteLine("Target element not found.");
return;
}
// Wrap the fragment in a minimal HTML document to preserve styles
string fragmentHtml = $@"
<html>
<head>
<style>
table {{ border-collapse: collapse; width: 100%; }}
td, th {{ border: 1px solid #ddd; padding: 8px; text-align: left; }}
</style>
</head>
<body>
{targetElement.OuterHtml}
</body>
</html>";
var renderer = new ChromePdfRenderer();
PdfDocument pdf = renderer.RenderHtmlAsPdf(fragmentHtml);
pdf.SaveAs("revenue-widget.pdf");
Imports IronPdf
Imports AngleSharp
Imports AngleSharp.Html.Parser
Dim fullPageHtml As String = "
<html>
<head>
<style>
table { border-collapse: collapse; width: 100%; }
td, th { border: 1px solid #ddd; padding: 8px; text-align: left; }
</style>
</head>
<body>
<header><h1>Dashboard</h1></header>
<div id='revenue-widget'>
<h3>Q4 Revenue</h3>
<table>
<tr><th>Month</th><th>Revenue</th></tr>
<tr><td>October</td><td>$1.2M</td></tr>
<tr><td>November</td><td>$1.5M</td></tr>
<tr><td>December</td><td>$1.8M</td></tr>
</table>
</div>
<div id='other-content'>Other widgets...</div>
</body>
</html>"
' Parse and extract the target element
Dim parser As New HtmlParser()
Dim document = parser.ParseDocument(fullPageHtml)
Dim targetElement = document.QuerySelector("#revenue-widget")
If targetElement Is Nothing Then
Console.WriteLine("Target element not found.")
Return
End If
' Wrap the fragment in a minimal HTML document to preserve styles
Dim fragmentHtml As String = $"
<html>
<head>
<style>
table {{ border-collapse: collapse; width: 100%; }}
td, th {{ border: 1px solid #ddd; padding: 8px; text-align: left; }}
</style>
</head>
<body>
{targetElement.OuterHtml}
</body>
</html>"
Dim renderer As New ChromePdfRenderer()
Dim pdf As PdfDocument = renderer.RenderHtmlAsPdf(fragmentHtml)
pdf.SaveAs("revenue-widget.pdf")
핵심 사항은 추출된 조각을 관련 <style> 또는 <link> 태그가 포함된 완전한 HTML 문서로 감싸는 것입니다. 이 래퍼 없이는 인라인 스타일이 올바르게 렌더링되지만, 외부 스타일시트 및 상속된 CSS 규칙은 손실됩니다. 이메일 템플릿 미리보기 렌더링 — 템플릿 HTML이 이미 문자열로 저장된 경우 — 이 추출 패턴은 우리가 렌더링된 콘텐츠의 모든 측면을 제어하기 때문에 픽셀 단위로 정확한 결과를 제공합니다.
괸계성 있는 대 갖을 위한 HtmlAgilityPack를 대 안 저택 장 일단.
using HtmlAgilityPack;
using IronPdf;
var htmlDoc = new HtmlDocument();
htmlDoc.LoadHtml(fullPageHtml);
var targetNode = htmlDoc.DocumentNode.SelectSingleNode("//*[@id='revenue-widget']");
if (targetNode is null)
{
Console.WriteLine("Target element not found.");
return;
}
string fragmentHtml = $"<html><body>{targetNode.OuterHtml}</body></html>";
var renderer = new ChromePdfRenderer();
PdfDocument pdf = renderer.RenderHtmlAsPdf(fragmentHtml);
pdf.SaveAs("revenue-widget-hap.pdf");
using HtmlAgilityPack;
using IronPdf;
var htmlDoc = new HtmlDocument();
htmlDoc.LoadHtml(fullPageHtml);
var targetNode = htmlDoc.DocumentNode.SelectSingleNode("//*[@id='revenue-widget']");
if (targetNode is null)
{
Console.WriteLine("Target element not found.");
return;
}
string fragmentHtml = $"<html><body>{targetNode.OuterHtml}</body></html>";
var renderer = new ChromePdfRenderer();
PdfDocument pdf = renderer.RenderHtmlAsPdf(fragmentHtml);
pdf.SaveAs("revenue-widget-hap.pdf");
Imports HtmlAgilityPack
Imports IronPdf
Dim htmlDoc As New HtmlDocument()
htmlDoc.LoadHtml(fullPageHtml)
Dim targetNode = htmlDoc.DocumentNode.SelectSingleNode("//*[@id='revenue-widget']")
If targetNode Is Nothing Then
Console.WriteLine("Target element not found.")
Return
End If
Dim fragmentHtml As String = $"<html><body>{targetNode.OuterHtml}</body></html>"
Dim renderer As New ChromePdfRenderer()
Dim pdf As PdfDocument = renderer.RenderHtmlAsPdf(fragmentHtml)
pdf.SaveAs("revenue-widget-hap.pdf")
PdfDocument pdf = renderer.RenderHtmlAsPdf(fragmentHtml, @"C:\templates\assets\");
PdfDocument pdf = renderer.RenderHtmlAsPdf(fragmentHtml, @"C:\templates\assets\");
Dim pdf As PdfDocument = renderer.RenderHtmlAsPdf(fragmentHtml, "C:\templates\assets\")
AngleSharp와 HtmlAgilityPack의 선택은 주로 선호도에 달려 있습니다. AngleSharp는 프론트엔드 개발자의 사고 방식에 부합하는 CSS 선택자(QuerySelector)를 사용합니다. HtmlAgilityPack은 XML이 많이 사용되는 .NET 코드베이스에서 더 친숙한 XPath(SelectSingleNode)를 사용합니다.
이메일 템플릿 미리보기 렌더링 — HTML 이메일 템플릿의 PDF 미리보기를 생성하여 발송 전 확인 — 는 순수한 방법 3 시나리오입니다. 템플릿 HTML은 저장된 문자열이며, 외부 리소스(이미지, 폰트)는 알려진 URL에 호스팅되어 있고, RenderHtmlAsPdf(string Html, string BaseUrlOrPath)의 RenderHtmlAsPdf() 매개변수가 모든 상대 경로를 해결합니다.
HTML에 React 또는 Vue 애플리케이션이 런타임에 채우는 <div id="app"></div>가 포함되어 있는 경우, 추출된 조각은 비어 있게 됩니다. 이런 경우, 방식 1 또는 4를 사용하세요.
라이브 URL을 렌더링할 때 요소를 어떻게 타겟화하나요?
소스 HTML에 직접 접근할 수 없는 활성 URL(타사 대시보드, 외부 보고서, 호스팅 애플리케이션 등)의 경우, 페이지가 로드된 후 특정 섹션을 분리하기 위해 RenderUrlAsPdf() 속성과 JavaScript 속성, WaitFor를 조합하여 사용합니다.
이는 대시보드 위젯 내보내기 시나리오입니다: BI 도구는 웹 페이지에 차트 및 표를 렌더링하며, 우리는 이해 관계자 배포를 위해 단일 위젯을 PDF로 내보내야 합니다.
using IronPdf;
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.EnableJavaScript = true;
// Wait for the dashboard widget to render (async content)
renderer.RenderingOptions.WaitFor.HtmlQuerySelector("[data-widget='revenue-chart']", 15000);
// Isolate the widget after it renders
renderer.RenderingOptions.JavaScript = @"
var widget = document.querySelector('[data-widget=""revenue-chart""]');
if (widget) {
// Preserve computed styles by cloning into a clean body
document.body.innerHTML = '';
document.body.appendChild(widget);
}
";
PdfDocument pdf = renderer.RenderUrlAsPdf("https://dashboard.example.com/q4-report");
pdf.SaveAs("revenue-chart-export.pdf");
using IronPdf;
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.EnableJavaScript = true;
// Wait for the dashboard widget to render (async content)
renderer.RenderingOptions.WaitFor.HtmlQuerySelector("[data-widget='revenue-chart']", 15000);
// Isolate the widget after it renders
renderer.RenderingOptions.JavaScript = @"
var widget = document.querySelector('[data-widget=""revenue-chart""]');
if (widget) {
// Preserve computed styles by cloning into a clean body
document.body.innerHTML = '';
document.body.appendChild(widget);
}
";
PdfDocument pdf = renderer.RenderUrlAsPdf("https://dashboard.example.com/q4-report");
pdf.SaveAs("revenue-chart-export.pdf");
Imports IronPdf
Dim renderer As New ChromePdfRenderer()
renderer.RenderingOptions.EnableJavaScript = True
' Wait for the dashboard widget to render (async content)
renderer.RenderingOptions.WaitFor.HtmlQuerySelector("[data-widget='revenue-chart']", 15000)
' Isolate the widget after it renders
renderer.RenderingOptions.JavaScript = "
var widget = document.querySelector('[data-widget=""revenue-chart""]);
if (widget) {
// Preserve computed styles by cloning into a clean body
document.body.innerHTML = '';
document.body.appendChild(widget);
}
"
Dim pdf As PdfDocument = renderer.RenderUrlAsPdf("https://dashboard.example.com/q4-report")
pdf.SaveAs("revenue-chart-export.pdf")
WaitFor.HtmlQuerySelector() 호출은 JavaScript가 실행되기 전에 위젯이 DOM에 존재하는지 확인합니다. 따라서 15초 타임아웃은 느린 API 요청이 대시보드 데이터를 채우는 경우를 수용합니다. JavaScript는 그런 다음 페이지를 위젯만 남도록 제거합니다.
복잡한 CSS 종속성이 있는 페이지의 경우, appendChild 방식(노드를 복사하는 대신 outerHTML 이동)을 사용하면 요소가 CSSOM 내에서 위치를 유지하므로 더 많은 계산된 스타일이 보존됩니다. 접근법 1의 innerHTML 대체 방식은 더 간단하지만, 상위 선택자에 의존하는 스타일이 손실될 수 있습니다.
대상 페이지에 인증이 필요한 경우, RenderUrlAsPdf()를 호출하기 전에 렌더러에서 쿠키를 구성하십시오:
renderer.RenderingOptions.CustomCookies = new Dictionary<string, string>
{
{ "session_id", "abc123" },
{ "auth_token", "bearer-xyz" }
};
renderer.RenderingOptions.CustomCookies = new Dictionary<string, string>
{
{ "session_id", "abc123" },
{ "auth_token", "bearer-xyz" }
};
Imports System.Collections.Generic
renderer.RenderingOptions.CustomCookies = New Dictionary(Of String, String) From {
{"session_id", "abc123"},
{"auth_token", "bearer-xyz"}
}
WaitFor 클래스는 HtmlQuerySelector() 외에도 추가적인 대기 전략을 제공합니다. NetworkIdle0()는 모든 네트워크 요청이 완료되고 미결 연결이 하나도 남지 않을 때까지 대기합니다. 이는 여러 API 엔드포인트에서 데이터를 불러오는 대시보드에 유용합니다. NetworkIdle2()는 최대 두 개의 활성 연결을 허용하며, 이는 지속적 WebSocket 연결이나 롱 폴링(long-polling)을 사용하는 페이지를 처리합니다. JavaScript()는 페이지가 window.ironpdf.notifyRender()를 호출할 때까지 대기합니다. 이는 대상 페이지를 제어할 수 있고, 모든 데이터 로딩 및 애니메이션이 완료된 후 렌더링 준비 상태를 명시적으로 알릴 수 있을 때 가장 정확한 옵션입니다.
반복적인 대시보드 내보내기 (예: 매일 밤 PDF 생성하여 이해관계자에게 이메일 배포)를 위해, 타임아웃 예외를 catch하는 retry 루프에 렌더링을 감싸세요. WaitFor이 maxWaitTime을 초과하는 경우, IronPDF는 사용 가능한 콘텐츠를 그대로 렌더링합니다. 이 경우 콘텐츠가 불완전할 수 있습니다. 타임아웃 시간을 늘리거나 NetworkIdle0()로 전환하면 일반적으로 느린 네트워크에서 발생하는 간헐적인 오류를 해결할 수 있습니다.
모든 4가지 접근 방식의 비교
| 접근 방식 | 최적 대상 | 소스 HTML을 요구함 | JS 의존성 | 복잡성 |
|---|---|---|---|---|
| JavaScript DOM 격리 | 모든 소스에서의 일반적인 요소 추출 | 아니요 | 예 | Medium |
| CSS 주입 | DOM 변경 없이 섹션 숨기기; @media print 레이아웃 |
일부 (CustomCssUrl에 RenderHtmlAsPdf 필요) |
아니요 (URL을 위한 JS 주입이 아니라면) | Low |
| 서버 측 조각 추출 | CMS 내용, 저장된 템플릿, 이메일 미리보기 | 예 | 아니요 | 낮음–중간 |
| JS 타겟팅으로 URL 렌더링 | 라이브 대시보드, 타사 페이지, SPA 위젯 | 아니요 | 예 | 중간–높음 |
올바른 접근 방법 선택하기
결정은 두 가지 요소에 따라 달라집니다: 원시 HTML에 액세스할 수 있는지 여부, 및 대상 내용이 렌더링에 JavaScript가 필요한지 여부.
Invoice 라인 항목 추출이 가장 일반적인 사용 사례입니다. 인보이스 HTML이 서버측에서 생성될 때 (Razor 뷰, Handlebars 템플릿, 저장된 HTML 문자열), 방식 3(서버측 추출)은 가장 깨끗한 결과를 제공하고 런타임 부담이 없습니다. #line-items 테이블을 추출하여 스타일링된 HTML 셸로 감싸고 렌더링하십시오.
Dashboard 위젯 내보내기는 초기 페이지 로드 후 API 호출을 통해 위젯 콘텐츠가 채워지기 때문에 JavaScript 실행이 필요합니다. 방식 1 (JS DOM 격리)은 대시보드가 로컬 또는 인증 뒤에서 실행될 때 이를 처리합니다. 방식 4 (JS 타겟팅으로 URL 렌더링)는 우리는 URL만을 가지고 있는 경우 호스팅된 타사 앱 대시보드가 필요합니다.
Form 섹션 인쇄 — 사용자 검토 또는 규정 준수 기록을 위해 다단계 양식의 특정 섹션을 추출하는 작업 —은 애플리케이션에 이미 @media print 규칙이 정의되어 있는 경우 자연스럽게 접근 방식 2(CSS 삽입)에 해당하며, 양식 HTML이 서버 측에서 조립되는 경우에는 접근 방식 3에 해당합니다.
Email 템플릿 미리보기 렌더링 — HTML 이메일 템플릿을 발송하기 전에 PDF 미리보기를 생성하는 작업 —은 순수한 접근 방식 3의 시나리오입니다. 템플릿 HTML은 저장된 문자열이며, 외부 리소스(이미지, 폰트)는 알려진 URL에 호스팅되어 있고, BaseUrlOrPath의 RenderHtmlAsPdf() 매개변수가 모든 상대 경로를 해결합니다.
여러 시나리오를 지원해야 하는 응용 프로그램들은 전략 매개변수를 수용하는 서비스 인터페이스 뒤에 렌더링 논리를 캡슐화합니다:
public enum ElementExtractionStrategy
{
JavaScriptIsolation,
CssInjection,
ServerSideExtraction,
UrlWithJsTargeting
}
public enum ElementExtractionStrategy
{
JavaScriptIsolation,
CssInjection,
ServerSideExtraction,
UrlWithJsTargeting
}
Public Enum ElementExtractionStrategy
JavaScriptIsolation
CssInjection
ServerSideExtraction
UrlWithJsTargeting
End Enum
이를 통해 호출 코드는 렌더러 구성을 복제하지 않고 입력 유형에 따라 적절한 접근 방식을 선택할 수 있습니다.
다음 단계
IronPDF의 HTML 요소 격리는 렌더링-시간 문제이며, 내장 API 기능이 아닙니다. 위의 네 가지 접근은 전체 범위를 포괄합니다 — 서버 측 템플릿 추출 (제로 JS, 가장 깨끗한 출력)에서 라이브 URL 타겟팅 (전체 JS 실행, SPA 및 비동기 콘텐츠를 처리). 비교 테이블은 빠른 참조를 제공하고, 실제 사례는 일반적인 비지니스 요구에 적합한 전략을 매핑합니다.
프로덕션 배포를 위한 몇 가지 추가 고려 사항:
성능: 서버 측 추출 (방식 3)은 JS 실행을 완전히 생략하므로 가장 빠릅니다. JavaScript 기반 접근 방식(1번 및 4번)은 페이지의 복잡도와 WaitFor 타임아웃에 비례하는 오버헤드를 발생시킵니다. 대량 처리(예: 500개의 청구서 PDF 생성)의 경우, Parallel.ForEach 및 여러 ChromePdfRenderer 인스턴스를 사용한 서버 측 추출이 최고의 처리량을 제공합니다.
디버깅: PDF 출력물이 비어 있거나 내용이 누락된 경우, EnableJavaScript = true을 활성화하고 WaitFor 타임아웃을 늘리십시오. 대상 요소가 비동기 데이터에 의존하는 경우, WaitFor.NetworkIdle0()가 고정된 RenderDelay보다 더 안정적입니다. 렌더링 옵션 안내서에는 레이아웃에 영향을 미치는 뷰포트 너비 및 페이퍼 맞춤 구성이 포함되어 있습니다.
접근 방식 결합: 전략을 혼합하는 것을 막는 것은 없습니다. 우리는 여러 조각 (한 소스의 헤더, 또 다른 소스의 데이터 테이블, 세 번째 소스의 차트 SVG)에서 구성된 HTML 문서를 빌드하기 위해 서버 측 추출을 사용할 수 있으며, 나중에 단일 PDF로 렌더링된 문서를 조립하여 롯전합니다. RenderHtmlAsPdf(string Html, string BaseUrlOrPath) 메서드는 기본 URL을 기준으로 상대 자산 경로를 해결하므로, 다양한 출처의 자료를 활용해 문서를 쉽게 작성할 수 있습니다.
고급 JS 실행 패턴에 대한 JavaScript to PDF 사용법, 사용 가능한 모든 대기 전략에 대한 WaitFor 문서, 전체 ChromePdfRenderOptions 표면에 대한 렌더링 옵션 가이드, 그리고 바로 실행 가능한 스니펫을 위한 사용자 지정 JavaScript 코드 예제를 확인해 보세요.
$999부터 시작하는 라이선스 옵션을 확인하세요. ChromePdfRenderOptions API 레퍼런스 및 WaitFor API 레퍼런스 문서에는 모든 속성과 메서드가 상세히 기술되어 있습니다.
자주 묻는 질문
C#에서 HTML 요소를 PDF로 변환하기 위한 주요 접근 방식은 무엇입니까?
주요 접근 방법은 JS 격리, CSS 숨기기, 서버 사이드 추출 및 라이브 URL 타겟팅을 포함하며, 모두 IronPDF를 사용하여 구현할 수 있습니다.
HTML을 PDF로 변환하는 문맥에서 JS 격리는 어떻게 작동합니까?
JS 격리는 JavaScript를 실행하여 HTML 문서를 동적으로 조작한 다음 PDF로 변환하는 것을 포함합니다. 이 작업은 IronPDF를 사용하여 특정 요소만 렌더링되도록 보장하며 달성할 수 있습니다.
CSS 숨기기란 무엇이며 PDF 변환 시 어떻게 활용됩니까?
CSS 숨기기는 PDF에 나타나지 않아야 하는 요소를 숨기기 위해 CSS 스타일을 사용하는 것을 포함합니다. IronPDF는 변환 프로세스 중에 스타일시트나 스타일 규칙을 지정할 수 있도록 지원합니다.
IronPDF는 PDF 생성을 위한 특정 HTML 요소를 서버 사이드에서 추출할 수 있습니까?
예, IronPDF는 특정 HTML 요소를 서버 사이드에서 추출할 수 있으며, 웹 페이지의 특정 부분만 PDF로 변환되도록 정밀하게 제어할 수 있습니다.
HTML을 PDF로 변환할 때 라이브 URL 타겟팅의 장점은 무엇입니까?
라이브 URL 타겟팅을 통해 IronPDF는 실시간 웹페이지 URL에서 요소를 직접 PDF로 변환하여 로컬 HTML 파일 없이도 최신 콘텐츠가 캡처되도록 보장합니다.
IronPDF를 사용하여 웹페이지의 특정 섹션만 PDF로 변환할 수 있습니까?
예, IronPDF는 웹페이지의 특정 섹션이나 요소를 PDF로 변환하는 기능을 제공하여 관련 콘텐츠에 집중할 수 있도록 합니다.
HTML을 PDF로 변환하는 동안 IronPDF는 동적 콘텐츠를 어떻게 처리할 수 있습니까?
IronPDF는 변환 중에 JavaScript를 실행하여 동적 콘텐츠를 렌더링할 수 있어, 클라이언트 사이드 스크립트에 의존하는 요소가 PDF에 정확하게 표현되도록 보장합니다.

