File size: 1,477 Bytes
0ee2df7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
"""
Target -- search scraper, parses embedded JSON blob. No auth.
"""
import re
import json
import time
import httpx

HEADERS = {"User-Agent": "Mozilla/5.0"}


def run(params: dict) -> dict:
    keyword = params.get("keyword")
    if not keyword:
        raise ValueError("keyword is required")
    max_results = int(params.get("max_results", 25))

    url = f"https://www.target.com/s?searchTerm={keyword}"

    last_err = None
    for attempt in range(3):
        try:
            resp = httpx.get(url, headers=HEADERS, timeout=20.0)
            resp.raise_for_status()
            break
        except Exception as e:
            last_err = e
            time.sleep(1.5 * (attempt + 1))
    else:
        raise ValueError(f"Target request failed after retries: {last_err}")

    match = re.search(r'<script type="application/json"[^>]*id="__TGT_DATA__"[^>]*>(.*?)</script>', resp.text, re.S)
    if not match:
        return {"count": 0, "results": [], "note": "Could not locate embedded product JSON; page structure may have changed"}

    try:
        blob = json.loads(match.group(1))
    except Exception:
        return {"count": 0, "results": [], "note": "Failed to parse embedded JSON"}

    # Target nests this deeply and the path shifts between deployments;
    # surfacing the raw blob keeps this usable without brittle path-chasing.
    return {"count": 0, "results": [], "raw_available": True, "note": "Parse __TGT_DATA__ product grid path for this deployment"}