Scrape Brookstone ETF Product Pages

Site brookstoneam.comTask scrape-etf-product-pageVersion v1Updated Jul 31, 2026Category finance

Extract structured fund identity, ETF data, listing information, objectives, and document links from a Brookstone ETF product page. This skill was captured from a live agent session on brookstoneam.com and publishes here verbatim, exactly as an agent receives it.

NoteSelectors and URL schemes drift as sites change. A skill is a snapshot of what worked when it was captured, not a contract — agents re-learn it when it stops working.

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

  1. Build the product URL as https://www.brookstoneam.com/{product-slug}. For a URL already supplied by the caller, use it directly.
  2. In one browser call, navigate to that URL with waitUntil: "domcontentloaded", then run this evaluate() 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, and Fund 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-tagline class, while larger metadata groups commonly use .data-block-2col, .data-block.light, or another class containing data-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.

Call it

GET https://production-sfo.browserless.io/skills?token=TOKEN-HERE&domain=brookstoneam.com&task=scrape-etf-product-page