08Extract titles from a public page
HTTP fetches a public page that robots.txt allows, the HTML node pulls just the titles and links with a CSS selector, and Set tidies them up. Not for login-walled or personal-data pages.
Best forwatching for announcements, collecting a public list
HTTP → HTML extractCSS 선택자V2 실행 확인

<main class="stage">
<svg class="flow" viewBox="-28 -28 654 212" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="godrich 201-08 html-extract-public-page">
<path class="edge" d="M170 28 C192 28 192 28 214 28"/>
<path class="edge edge--flow" style="--i:0" d="M170 28 C192 28 192 28 214 28"/>
<circle class="pulse" style="--i:0;offset-path:path('M170 28 C192 28 192 28 214 28')" r="7"/>
<path class="edge" d="M384 28 C406 28 406 28 428 28"/>
<path class="edge edge--flow" style="--i:1" d="M384 28 C406 28 406 28 428 28"/>
<circle class="pulse" style="--i:1;offset-path:path('M384 28 C406 28 406 28 428 28')" r="7"/>
<path class="edge" d="M513 56 C513 78 85 78 85 100"/>
<path class="edge edge--flow" style="--i:2" d="M513 56 C513 78 85 78 85 100"/>
<circle class="pulse" style="--i:2;offset-path:path('M513 56 C513 78 85 78 85 100')" r="7"/>
<g class="node node--trigger" style="--i:0" transform="translate(0 0)"><rect class="node__box" width="170" height="56"/><text class="node__name" x="14" y="24">Manual Trigger</text><text class="node__type" x="14" y="42">Manual Trigger</text></g>
<g class="node" style="--i:1" transform="translate(214 0)"><rect class="node__box" width="170" height="56"/><text class="node__name" x="14" y="24">Get Page</text><text class="node__type" x="14" y="42">Http Request</text></g>
<g class="node" style="--i:2" transform="translate(428 0)"><rect class="node__box" width="170" height="56"/><text class="node__name" x="14" y="24">Extract Titles</text><text class="node__type" x="14" y="42">Html</text></g>
<g class="node" style="--i:3" transform="translate(0 100)"><rect class="node__box" width="170" height="56"/><text class="node__name" x="14" y="24">Clean Fields</text><text class="node__type" x="14" y="42">Set</text></g>
</svg>
</main>@use "../../../../site/static/demo-tokens" as *;
// ── 변수 3개 ──────────────────────────────────────────
$duration: $dur-loop; // 한 바퀴 (데모 2초와 같은 값 — gif 가 끊기지 않게)
$easing: linear; // 대시 흐름은 등속
$color: $subject-blue; // 강조(흐름·켜진 노드) 색
$ink: $subject-ink; // 글자·테두리
$n: 4; // 노드 수 — 켜지는 순서 간격
@include stage($stage-paper);
.flow { width: 100%; height: 100%; max-height: 100vh; display: block; overflow: visible; }
.edge { fill: none; stroke: $ink; stroke-opacity: .28; stroke-width: 3; stroke-linecap: round; }
.edge--flow { stroke: $color; stroke-opacity: 1; stroke-dasharray: 10 14; animation: flow $duration $easing infinite; }
@keyframes flow { to { stroke-dashoffset: -48; } }
.node__box { fill: transparent; stroke: $ink; stroke-opacity: .45; stroke-width: 2; rx: $r-sm; }
.node__name { fill: $ink; font-weight: 700; font-size: 17px; font-family: -apple-system, "Segoe UI", sans-serif; }
.node__type { fill: $ink; fill-opacity: .6; font-weight: 500; font-size: 12px; font-family: -apple-system, "Segoe UI", sans-serif; letter-spacing: .04em; }
.node--trigger .node__box { stroke-dasharray: 6 5; }
// 켜진 노드는 테두리가 강조색으로 두꺼워진다 (filter 대신 stroke — 렌더 비용). --i 는 <g> 에서 상속된다
.node .node__box { animation: box-lit $duration $ease-spring infinite; animation-delay: calc(var(--i) * #{$duration} / #{$n}); }
@keyframes box-lit {
0%, 100% { stroke: $ink; stroke-opacity: .45; stroke-width: 2; }
12%, 32% { stroke: $color; stroke-opacity: 1; stroke-width: 4; }
50% { stroke: $ink; stroke-opacity: .45; stroke-width: 2; }
}
.pulse { fill: $color; offset-distance: 0%; offset-rotate: 0deg; animation: travel $duration $ease-out infinite; animation-delay: calc(var(--i) * #{$duration} / #{$n}); }
@keyframes travel {
0% { offset-distance: 0%; opacity: 0; }
10% { opacity: 1; }
45% { offset-distance: 100%; opacity: 1; }
55%, 100% { offset-distance: 100%; opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
.edge--flow, .node, .node .node__box, .pulse { animation: none; }
.edge--flow { stroke-dasharray: none; } // 흐름은 멈추고 연결선만 남긴다
.pulse { display: none; }
}html, body {
margin: 0;
overflow: hidden;
}
.stage {
box-sizing: border-box;
min-height: 100vh;
display: grid;
place-items: center;
margin: 0;
background: #ffffff;
font-family: -apple-system, "Segoe UI", "Noto Sans KR", sans-serif;
padding: clamp(8px, 4vw, 24px);
}
.flow {
width: 100%;
height: 100%;
max-height: 100vh;
display: block;
overflow: visible;
}
.edge {
fill: none;
stroke: #17141a;
stroke-opacity: 0.28;
stroke-width: 3;
stroke-linecap: round;
}
.edge--flow {
stroke: #2f6df6;
stroke-opacity: 1;
stroke-dasharray: 10 14;
animation: flow 2s linear infinite;
}
@keyframes flow {
to {
stroke-dashoffset: -48;
}
}
.node__box {
fill: transparent;
stroke: #17141a;
stroke-opacity: 0.45;
stroke-width: 2;
rx: 8px;
}
.node__name {
fill: #17141a;
font-weight: 700;
font-size: 17px;
font-family: -apple-system, "Segoe UI", sans-serif;
}
.node__type {
fill: #17141a;
fill-opacity: 0.6;
font-weight: 500;
font-size: 12px;
font-family: -apple-system, "Segoe UI", sans-serif;
letter-spacing: 0.04em;
}
.node--trigger .node__box {
stroke-dasharray: 6 5;
}
.node .node__box {
animation: box-lit 2s cubic-bezier(0.2, 0.8, 0.2, 1) infinite;
animation-delay: calc(var(--i) * 2s / 4);
}
@keyframes box-lit {
0%, 100% {
stroke: #17141a;
stroke-opacity: 0.45;
stroke-width: 2;
}
12%, 32% {
stroke: #2f6df6;
stroke-opacity: 1;
stroke-width: 4;
}
50% {
stroke: #17141a;
stroke-opacity: 0.45;
stroke-width: 2;
}
}
.pulse {
fill: #2f6df6;
offset-distance: 0%;
offset-rotate: 0deg;
animation: travel 2s ease-out infinite;
animation-delay: calc(var(--i) * 2s / 4);
}
@keyframes travel {
0% {
offset-distance: 0%;
opacity: 0;
}
10% {
opacity: 1;
}
45% {
offset-distance: 100%;
opacity: 1;
}
55%, 100% {
offset-distance: 100%;
opacity: 0;
}
}
@media (prefers-reduced-motion: reduce) {
.edge--flow, .node, .node .node__box, .pulse {
animation: none;
}
.edge--flow {
stroke-dasharray: none;
}
.pulse {
display: none;
}
}08 Extract titles from a public page — Measured area 4.88% · moving frames 23/23Original by GODRICH · SCSS and React ship in the zip · 9 n8n Workflow Examples, Zero Accounts Needed
The post this demo lives in
9 n8n Workflow Examples, Zero Accounts Neededn8n connects apps into automated tasks without writing code. If you're building with AI tools and just ran into this nam See all demos in this post


