Tabductor
Explore/ SEC EDGAR new filings
Public workflow

SEC EDGAR new filings

By Malik Ammar Faisal · used 0 times · updated 2026-10-18

How it runs

Distilled · v1 Includes a distilled script, so your copy runs it from its first run. If a page has changed, it falls back to the AI agent for that run.

Instructions

Open efts.sec.gov/LATEST/search-index?q= (EDGAR full-text search)
Search filings for "$phrase" filed in the last $days days, form type $form.
Return: company, form, filed_date, filing_url.

You provide “phrase”, “days”, “form” each time you run it.

Review the distilled script

This Python runs in your browser session when you use the workflow. Review it before running.

from datetime import date, timedeltafrom urllib.parse import parse_qs, unquoteimport re from playwright.sync_api import expect  def run(page, context, browser):    def visible(locator, scope):        try:            expect(locator).to_be_visible(timeout=10000)        except AssertionError:            scope.deopt(                reason="The next operation's target is not visible.",                evidence={"locator": str(locator)},            )     def editable(locator, scope):        visible(locator, scope)        try:            expect(locator).to_be_editable(timeout=10000)        except AssertionError:            scope.deopt(                reason="The requested search field is not editable.",                evidence={"locator": str(locator)},            )     def value_is(locator, value, scope):        try:            expect(locator).to_have_value(value, timeout=10000)        except AssertionError:            scope.deopt(                reason="An applied search control does not match the requested criterion.",                evidence={                    "locator": str(locator),                    "expected": value,                    "actual": locator.input_value(),                },            )     def select_requested_form(form, scope):        labels = page.locator("label").evaluate_all(            "(es)=>es.map(e=>({text:e.innerText,for:e.htmlFor}))"        )        matches = [            label for label in labels            if label["text"].strip() == form and label["for"]        ]        if len(matches) != 1:            scope.deopt(                reason="The requested form does not resolve to exactly one picker checkbox.",                evidence={"form": form, "matches": matches},            )        checkbox = page.locator('[id="' + matches[0]["for"] + '"]')        visible(checkbox, scope)        checkbox.check()        expect(checkbox).to_be_checked(timeout=10000)     def verify_url(criteria, scope):        expected = {            "q": criteria["query"],            "dateRange": "custom",            "startdt": criteria["filed_from"],            "enddt": criteria["filed_to"],            "forms": criteria["form"],        }        page.wait_for_function(            """expected => {                const hash = location.hash.replace(/^#\\/?/, '');                const p = new URLSearchParams(hash);                return Object.entries(expected).every(([k,v]) => {                    let actual = p.get(k);                    if (k === 'q' && actual !== null) {                        for (let i=0; i<2 && actual !== v; i++) {                            try { actual = decodeURIComponent(actual); } catch (_) { break; }                        }                    }                    return actual === v;                });            }""",            arg=expected,            timeout=10000,        )        url = page.url        params = parse_qs(url.split("#", 1)[-1].lstrip("/"))        actual = {k: params.get(k, [None])[0] for k in expected}        if actual["q"] is not None:            for _ in range(2):                if actual["q"] == expected["q"]:                    break                actual["q"] = unquote(actual["q"])        if actual != expected:            scope.deopt(                reason="The search URL does not encode the requested criteria.",                evidence={"url": url, "expected": expected, "actual": actual},            )        return url     object_schema = {"type": "object"}     with browser.scope(        "open-edgar-search",        goal="Open the required endpoint and reveal interactive EDGAR advanced controls.",        returns=None,    ) as opening:        page.goto("https://efts.sec.gov/LATEST/search-index?q=")        page.wait_for_load_state("domcontentloaded")        page.goto("https://www.sec.gov/edgar/search/")        page.wait_for_load_state("domcontentloaded")        more = page.get_by_text("+ more search options", exact=True)        visible(more, opening)        more.click()        visible(page.locator("#keywords"), opening)        visible(page.locator("#category-select"), opening)        page.locator("#category-select").click()        opening.value = None     with browser.scope(        "configure-and-submit-search",        goal="Set the quoted phrase, requested form, and runtime custom filing-date interval.",        returns={            "type": "object",            "required": [                "phrase", "query", "form", "days", "filed_from", "filed_to",            ],            "properties": {                "phrase": {"type": "string"},                "query": {"type": "string"},                "form": {"type": "string"},                "days": {"type": "integer"},                "filed_from": {"type": "string"},                "filed_to": {"type": "string"},            },        },    ) as configuration:        inputs = browser.input["promptInputs"]        phrase = inputs["phrase"]        form = inputs["form"].removeprefix("Form ").strip()        days = int(inputs["days"])        if not phrase or not form or days < 0:            configuration.deopt(                reason="The supplied search criteria are unusable.",                evidence={"phrase": phrase, "form": form, "days": days},            )         enter = page.get_by_text("Enter the filing types", exact=True)        visible(enter, configuration)        enter.click()        editable(page.locator("#filing-types"), configuration)        page.locator("#filing-types").fill(form)        editable(page.locator("#keywords"), configuration)        query = '"' + phrase + '"'        page.locator("#keywords").fill(query)        visible(page.locator("#date-range-select"), configuration)        page.locator("#date-range-select").select_option("custom")        editable(page.locator("#date-to"), configuration)        end_text = page.locator("#date-to").input_value()        runtime_date = page.evaluate("new Date().toISOString()")        end = date.fromisoformat(end_text)        today = date.fromisoformat(runtime_date[:10])        if end != today:            configuration.deopt(                reason="The default filing end date differs from the runtime date.",                evidence={"end_date": end_text, "runtime_date": runtime_date},            )        start = end - timedelta(days=days)        editable(page.locator("#date-from"), configuration)        page.locator("#date-from").fill(start.isoformat())        editable(page.locator("#date-to"), configuration)        page.locator("#date-to").fill(end.isoformat())        visible(page.locator("#keywords"), configuration)        page.locator("#keywords").click()        value_is(page.locator("#date-from"), start.isoformat(), configuration)        value_is(page.locator("#date-to"), end.isoformat(), configuration)        value_is(page.locator("#date-range-select"), "custom", configuration)        visible(page.locator("#search"), configuration)        page.locator("#search").click()        criteria = {            "phrase": phrase,            "query": query,            "form": form,            "days": days,            "filed_from": start.isoformat(),            "filed_to": end.isoformat(),        }        verify_url(criteria, configuration)        configuration.value = criteria     with browser.scope(        "apply-explicit-form-selection",        goal="Resolve and explicitly check the requested filing type and verify its applied filter.",        returns={"type": "object", "required": ["criteria", "search_url"]},    ) as selection:        criteria = configuration.value        browse = page.get_by_text("Browse filing types", exact=True).filter(visible=True)        visible(browse, selection)        browse.click()        select_requested_form(criteria["form"], selection)        visible(page.locator("#custom_forms_set"), selection)        page.locator("#custom_forms_set").click()        expect(page.locator("#custom_forms_set")).not_to_be_visible(timeout=10000)         visible(browse, selection)        browse.click()        select_requested_form(criteria["form"], selection)        visible(page.locator("#custom_forms_set"), selection)        page.locator("#custom_forms_set").click()        value_is(page.locator("#filing-types"), criteria["form"], selection)        value_is(page.locator("#keywords"), criteria["query"], selection)        value_is(page.locator("#date-range-select"), "custom", selection)        value_is(page.locator("#date-from"), criteria["filed_from"], selection)        value_is(page.locator("#date-to"), criteria["filed_to"], selection)        search_url = verify_url(criteria, selection)        selection.value = {"criteria": criteria, "search_url": search_url}     with browser.scope(        "extract-matching-documents",        goal="Read the runtime results summary and structurally extract all covered document hits.",        returns={            "type": "object",            "required": ["criteria", "search_url", "rows", "result_count", "summary"],            "properties": {                "criteria": object_schema,                "search_url": {"type": "string"},                "rows": {"type": "array", "items": object_schema},                "result_count": {"type": "integer"},                "summary": {"type": "string"},            },        },    ) as extraction:        applied = selection.value        value_is(page.locator("#filing-types"), applied["criteria"]["form"], extraction)        summary_pattern = re.compile(            r"(?:[\d,]+\s+search results?|no\s+(?:matching\s+)?(?:search\s+)?results)",            re.I,        )        try:            expect(page.locator("body")).to_contain_text(                summary_pattern, timeout=30000            )        except AssertionError:            extraction.deopt(                reason="A completed search result summary did not render.",                evidence={"url": page.url},            )        text = page.locator("body").inner_text()        match = summary_pattern.search(text)        if match is None:            extraction.deopt(                reason="The rendered summary cannot be parsed.",                evidence={"text": text[:4000]},            )        summary = match.group(0)        number = re.search(r"[\d,]+", summary)        total = int(number.group(0).replace(",", "")) if number else 0         row_locator = page.locator("tr").filter(has=page.locator("a.preview-file"))        if total:            visible(row_locator.first, extraction)        rows = row_locator.evaluate_all(            """es=>es.map(e=>({                company:e.querySelector('.entity-name').innerText.trim(),                form:e.querySelector('.filetype').innerText.split(' ')[0],                filed_date:e.querySelector('.filed').innerText,                filing_url:e.querySelector('a.preview-file').href,                accession:e.querySelector('a.preview-file').dataset.adsh,                document:e.querySelector('.filetype').innerText            }))"""        )        if len(rows) != total:            extraction.deopt(                reason="The extracted page does not cover the runtime document count; pagination coverage must be completed and verified.",                evidence={                    "summary": summary,                    "extracted_count": len(rows),                    "url": page.url,                    "rows": rows,                },            )        for row in rows:            required = (                "company", "form", "filed_date", "filing_url", "accession", "document"            )            if any(not isinstance(row.get(k), str) or not row[k].strip() for k in required):                extraction.deopt(                    reason="A document row lacks required filing fields.",                    evidence={"row": row},                )            filed = date.fromisoformat(row["filed_date"].strip())            if not (                date.fromisoformat(applied["criteria"]["filed_from"])                <= filed                <= date.fromisoformat(applied["criteria"]["filed_to"])            ):                extraction.deopt(                    reason="A document is outside the applied date interval.",                    evidence={"row": row, "criteria": applied["criteria"]},                )        extraction.value = {            "criteria": applied["criteria"],            "search_url": page.url,            "rows": rows,            "result_count": total,            "summary": summary,        }     with browser.scope(        "deduplicate-and-report",        goal="Deduplicate by accession and return exact forms separately from amendments.",        returns=object_schema,    ) as reporting:        data = extraction.value        by_accession = {}        for row in data["rows"]:            old = by_accession.get(row["accession"])            if old is None or (                " EX-" in old["document"] and " EX-" not in row["document"]            ):                by_accession[row["accession"]] = row         requested = data["criteria"]["form"]        fields = ("company", "form", "filed_date", "filing_url")        filings = []        amendments = []        for row in by_accession.values():            item = {key: row[key] for key in fields}            if row["form"] == requested:                filings.append(item)            elif row["form"] == requested + "/A":                amendments.append(item)            else:                reporting.deopt(                    reason="A result has a form outside the requested form and its amendments.",                    evidence={"requested_form": requested, "row": row},                )        filings.sort(key=lambda row: (row["filed_date"], row["company"]), reverse=True)        amendments.sort(key=lambda row: (row["filed_date"], row["company"]), reverse=True)        reporting.value = {            "criteria": {                key: value for key, value in data["criteria"].items() if key != "query"            },            "search_url": data["search_url"],            "document_matches": data["result_count"],            "unique_filings": len(by_accession),            "filing_count": len(filings),            "filings": filings,            "additional_amendment_matches": amendments,            "evidence": {                "visible_result_count": data["summary"],                "extracted_document_count": len(data["rows"]),                "pagination_coverage_verified": len(data["rows"]) == data["result_count"],            },        }     browser.done(result=reporting.value)