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 is published here as a reusable recipe for agents.

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.

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.

Use Cases

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.

Automation Flow

  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,
  };
})();

Possible Friction Points

  • 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.

Call it

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