Created
May 24, 2025 16:19
-
-
Save snacsnoc/6f474cbdb6060434fb31ceeab646a305 to your computer and use it in GitHub Desktop.
Dollar General coupon loader via API
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env python3 | |
| """ | |
| Dollar General – clip **everything** that is currently visible in | |
| ‘Digital Coupons’. | |
| USAGE | |
| DG_COOKIE="Paste the long Cookie header here" \ | |
| python3 dg_clip_all.py | |
| """ | |
| import json, os, sys, time, urllib.parse, requests | |
| BASE = "https://www.dollargeneral.com/bin/omni/coupons" | |
| HEAD = { | |
| "User-Agent": "Mozilla/5.0", | |
| "Accept": "application/json, text/javascript, */*; q=0.01", | |
| "X-Requested-With": "XMLHttpRequest", | |
| "Referer": "https://www.dollargeneral.com/deals/coupons", | |
| "Cookie": ( | |
| "form_key=6MzGRJsdB2ZZXMXA; " # probably need this | |
| "c_uuid=2501015138020100101138051050168030; " # probably need this | |
| "authType=1; " | |
| "userPreferences=false|false|true; " | |
| ), | |
| } | |
| DEVICE_ID = "YOUR-DEVICE-ID" # fixed | |
| STORE_NUM = "25558" # any valid store | |
| PARAMS = { | |
| "searchText": "", | |
| "sortOrder": "2", | |
| "sortBy": "0", | |
| "numPageRecords": "40", # grab many at once | |
| "pageIndex": "0", | |
| "offerSourceType": "1", | |
| "mixMode": "0", | |
| "deviceId": DEVICE_ID, | |
| "isMobileDevice": "false", | |
| "clientOriginStoreNumber": "", | |
| } | |
| print("Starting.....") | |
| sess = requests.Session() | |
| sess.headers.update(HEAD) | |
| def all_offer_ids(): | |
| ids, idx = [], 0 | |
| while True: | |
| PARAMS["pageIndex"] = str(idx) | |
| r = sess.get(f"{BASE}/search", params=PARAMS, timeout=10) | |
| r.raise_for_status() | |
| data = r.json() | |
| coupons = data.get("Coupons", []) | |
| if not coupons: | |
| break | |
| ids.extend(c["OfferID"] for c in coupons) | |
| idx += 1 | |
| print(f"Going thru ID {idx}") | |
| return ids | |
| def activate_batch(offer_ids): | |
| payload = { | |
| "offerGuids": ",".join(offer_ids), | |
| "storeNumber": STORE_NUM, | |
| "deviceId": DEVICE_ID, | |
| "isMobileDevice": "false", | |
| "clientOriginStoreNumber": "", | |
| } | |
| r = sess.post( | |
| f"{BASE}/activate", | |
| data=urllib.parse.urlencode(payload), | |
| headers={"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"}, | |
| ) | |
| r.raise_for_status() | |
| return r.json() | |
| if not HEAD["Cookie"]: | |
| sys.exit("Set DG_COOKIE env var first.") | |
| offers = all_offer_ids() | |
| print(f"Found {len(offers)} coupons.") | |
| CHUNK = 30 # DG API allows ~50 ids at once, stay safe | |
| for i in range(0, len(offers), CHUNK): | |
| chunk = offers[i : i + CHUNK] | |
| resp = activate_batch(chunk) | |
| ok = sum(1 for o in resp["result"] if o["Success"]) | |
| print(f" clipped {ok}/{len(chunk)} (batch {i//CHUNK+1})") | |
| time.sleep(0.4) # be nice | |
| print("Done.") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment