Purpose
Provide a direct, reusable scraper for Brookstone ETF product pages, including the page title, ticker and other labeled fund fields, data-block contents, objectives, listing information, and fund-document URLs.
When to Use
Use when the caller has a Brookstone product-page URL or its path slug and needs a structured snapshot of the ETF page. Substitute {product-slug} with the supplied path segment; do not guess an unknown slug from a fund name.
Workflow
- Build the product URL as
https://www.brookstoneam.com/{product-slug}. For a URL already supplied by the caller, use it directly. - In one browser call, navigate to that URL with
waitUntil: "domcontentloaded", then run thisevaluate()function on the loaded page:
(() => {
const clean = (s) => (s || "").replace(/\\s+/g, " ").trim();
const text = (el) => clean(el ? el.innerText || el.textContent : "");
const first = (sels) => {
for (const s of sels) {
const el = document.querySelector(s);
if (el && text(el)) return text(el);
}
return null;
};
const sectionByHeading = (heading) => {
const hs = [...document.querySelectorAll("h2,h3,h4")].filter(
(h) => clean(h.textContent).toLowerCase() === heading.toLowerCase(),
);
if (!hs.length) return null;
let node = hs[0];
for (let i = 0; i < 5 && node; i++, node = node.parentElement) {
if (text(node).length > text(hs[0]).length) return text(node);
}
return text(hs[0].parentElement);
};
const blockEls = [
...document.querySelectorAll(
'.data-block-2col, .data-block.light, [class*="data-block"]',
),
];
const seen = new Set();
const dataBlocks = blockEls
.map((el) => ({
className: String(el.className || ""),
text: text(el),
}))
.filter((x) => x.text && !seen.has(x.text) && (seen.add(x.text), true));
const fields = {};
document.querySelectorAll(".text-style-tagline").forEach((label) => {
const key = clean(label.textContent);
if (!key || fields[key]) return;
const parent = label.parentElement;
if (!parent) return;
const clone = parent.cloneNode(true);
clone.querySelectorAll(".text-style-tagline").forEach((n) => n.remove());
const value = text(clone);
if (value) fields[key] = value;
});
const documentHeading = [...document.querySelectorAll("h2,h3,h4")].find(
(h) => clean(h.textContent).toLowerCase() === "fund documents",
);
let documentRoot = documentHeading;
for (
let i = 0;
i < 5 && documentRoot;
i++, documentRoot = documentRoot.parentElement
) {
if (
documentRoot.querySelector &&
documentRoot.querySelectorAll("a[href]").length
)
break;
}
const fundDocuments = documentRoot
? [...documentRoot.querySelectorAll("a[href]")]
.map((a) => ({ text: text(a), href: a.href }))
.filter((x) => x.text || x.href)
: [];
return {
url: location.href,
title: first(["h1"]) || document.title,
ticker: fields.Ticker || first(["[data-ticker]"]),
fields,
sections: {
objective: sectionByHeading("Objective"),
etfData: sectionByHeading("ETF Data"),
listingInformation: sectionByHeading("Listing Information"),
fundDocuments: sectionByHeading("Fund Documents"),
},
dataBlocks,
fundDocuments,
};
})();Site-Specific Gotchas
- Brookstone product pages use path-based URLs such as
/brookstone-dividend-stock-etf; the product slug is not an opaque numeric ID, but an unprovided slug must still come from the caller or a prior site search rather than being invented. - Important content is organized under headings such as
ETF Data,Listing Information, andFund Documents; document links should be collected from the heading's nearby ancestor rather than from the entire page. - Labeled metadata uses the Webflow-style
.text-style-taglineclass, while larger metadata groups commonly use.data-block-2col,.data-block.light, or another class containingdata-block. The extractor includes fallbacks because these classes are presentation-oriented and may vary between templates. - Arlington Asset Management is a separate domain encountered during the run. Do not substitute its homepage for the Brookstone product URL when scraping this site.
Expected Output
Return the evaluator's object containing the canonical URL, fund title, ticker when available, a label-to-value fields map, heading-based section text, deduplicated data blocks, and {text, href} fund-document links.