The $1 Tech Stack: How I Connected Claude and DeepSeek APIs for Massive Data Extraction (Without Writing Code)
Before this project, I had never used an API. I had never written Python. I had never opened a terminal. I am a TCM practitioner building an auto parts export site after work. In two evenings, using Claude to write every line of code and DeepSeek's API to process 500 PDF pages, I turned a supplier catalog into 15,000+ CSV rows. The API bill was under 5 RMB — less than one US dollar. This is exactly how I set it up, what broke, and what I would skip if I had to do it again.
The First Thing That Went Wrong
Let me start with a failure because the tutorials never do.
I set up my DeepSeek API key. I asked Claude to write a Python script. I ran it. The terminal filled with a red error message I did not understand.
The problem: I had installed Python but missed the checkbox that says "Add Python to PATH." On Windows, this means you can type python in PowerShell and nothing happens. The fix is checking one box during installation. But no tutorial mentioned this, because people who write tutorials installed Python five years ago and forgot this step exists.
This is not the interesting kind of failure. It is the stupid kind. But it is the kind that stops non-programmers cold. I nearly quit on day one because of a checkbox.
If you are reading this and have never installed Python: go to python.org, download the installer, and check the box labeled "Add Python to PATH." Everything else in this article assumes you did that. If you skip it, nothing works and the error messages will not tell you why.
OK. Now the part that actually worked.
The Actual Setup (15 Minutes, $6 Loaded, $1 Spent)
I used two AI APIs: DeepSeek for the bulk vision processing, Claude for writing the script and handling edge-case pages. Here is how to get both:
DeepSeek API key:
- Go to
platform.deepseek.com, create an account. - Click "API Keys" in the sidebar → "Create new key." Copy it. Paste it into a plain text file named
api_key.txt. - Top up 10 RMB (about $1.40). This turned out to be more than enough for 500 pages.
Claude API key (optional):
- Go to
console.anthropic.com, create an account. - "API Keys" → "Create Key." Save it.
- Load $5. I only used Claude for the hardest 10% of pages — the ones where DeepSeek's output wasn't clean enough.
That is the entire setup. No server. No cloud configuration. No command-line wizardry. Two websites, two passwords, $6 loaded, about $1 actually spent on processing. DeepSeek's vision pricing is absurdly cheap — I wasn't careful about token optimization and the bill still barely moved.
How Claude Wrote the Script (And What Broke)
I wrote zero lines of Python. I described the task in plain English. Here is the prompt that produced the first working version:
I have a folder of PNG images. Each image is one page from an auto parts PDF catalog. The pages have a consistent layout: 3 columns, about 8 products per page. Each product has a part number in the upper-left corner, a short description, dimensions, and vehicle fitment info.
Write me a Python script that:
1. Reads every PNG in a folder named "catalog_pages"
2. Sends each image to the DeepSeek API (vision model)
3. Uses this system prompt: "Return ONLY valid JSON. Each product should have fields: part_number, description, dimensions, fitment. If unreadable, use null. Do not guess."
4. Saves everything to products.csvI am on Windows. Python is installed. My DeepSeek API key is in api_key.txt in the same folder.
Claude produced about 60 lines of Python. I did not understand most of it. I ran it anyway.
It crashed. Five times.
Crash #1: JSON decode error. DeepSeek returned something like "Sure! Here is the extracted data:" followed by the JSON. My script tried to parse the whole thing as JSON and died. Claude's fix: strip everything before the first curly brace. One-line change. Took 30 seconds.
Crash #2: Markdown code fences. Some pages came back with the JSON wrapped in ```json ... ```. The parser choked on the backticks. Fix: add a cleanup step that removes code fences before parsing.
Crash #3: Null fields causing CSV writer to fail. When a field was genuinely unreadable and the model returned null, the CSV writer threw a type error instead of writing "null" as a string. Fix: convert null to empty string before writing.
Crash #4: API rate limiting. I had no delay between requests. Around page 40, DeepSeek started returning HTTP 429 errors. Fix: add time.sleep(0.5) between pages. Processing time went from 8 minutes to 15 minutes. Worth it.
Crash #5: A page with zero products. One page in the PDF was a section divider — no products, just a title. The model returned an empty array, which was correct, but the CSV writer expected at least one row and produced a malformed file. Fix: skip writing CSV rows when the products array is empty.
Each fix was one follow-up message to Claude. The whole debugging loop took 30 minutes. By the end, the script processed 500 pages without human intervention — and when it did hit a parsing error, it saved the raw response to a file for manual review instead of crashing.
The key insight: I did not debug. Claude debugged. I described what I saw on the screen in plain English, and Claude rewrote the code. That loop — see red text, describe it, get a fix — is the actual workflow. Not "AI writes perfect code first try."
The Working Script
Here is the final version, with all five crash fixes baked in. Copy it. Break it. Fix it the same way I did:
import os
import json
import base64
import requests
import csv
import time
with open("api_key.txt", "r") as f:
api_key = f.read().strip()
url = "https://api.deepseek.com/v1/chat/completions"
headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
}
system_prompt = """You are extracting product data from an auto parts catalog page.
Return ONLY valid JSON. No markdown. No explanation.
Format: {"products": [{"part_number": "...", "description": "...", "dimensions": "...", "fitment": "..."}]}
If a field is unreadable, use null. Do not guess."""
all_products = []
image_folder = "catalog_pages"
for filename in sorted(os.listdir(image_folder)):
if not filename.endswith(".png"):
continue
with open(os.path.join(image_folder, filename), "rb") as f:
image_data = base64.b64encode(f.read()).decode("utf-8")
payload = {
"model": "deepseek-chat",
"messages": [
{"role": "system", "content": system_prompt},
{"role": "user", "content": [
{"type": "image_url", "image_url": {"url": f"data:image/png;base64,{image_data}"}},
{"type": "text", "text": "Extract all products from this catalog page as JSON."}
]}
],
"temperature": 0.1
}
response = requests.post(url, headers=headers, json=payload)
data = response.json()
content = data["choices"][0]["message"]["content"]
# Fix #1 and #2: strip conversational wrappers and code fences
content = content.strip()
if "{" in content:
content = content[content.index("{"):]
if "}" in content:
content = content[:content.rindex("}") + 1]
content = content.replace("```json", "").replace("```", "").strip()
try:
result = json.loads(content)
products = result.get("products", [])
if products: # Fix #5: skip empty pages
all_products.extend(products)
print(f"Page {filename}: {len(products)} products")
else:
print(f"Page {filename}: no products found (section divider?)")
except json.JSONDecodeError:
print(f"Page {filename}: JSON parse failed — saved for manual review")
with open(f"failed_{filename}.txt", "w", encoding="utf-8") as f:
f.write(content)
time.sleep(0.5) # Fix #4: don't get rate-limited
# Fix #3: null → empty string for CSV compatibility
with open("products.csv", "w", newline="", encoding="utf-8") as f:
writer = csv.DictWriter(f, fieldnames=["part_number", "description", "dimensions", "fitment"])
writer.writeheader()
for product in all_products:
writer.writerow({k: (v if v is not None else "") for k, v in product.items()})
print(f"\nDone. {len(all_products)} products saved to products.csv")
This is not elegant. It is not production code. The error handling is crude. But it processed 500 pages into 15,000+ CSV rows while I made tea. For a non-programmer working alone after hours, that is the only metric that mattered.
The Prompt Template I Arrived At (After 500 Pages)
After watching DeepSeek's output across hundreds of pages, I learned exactly what makes a prompt produce clean, parseable JSON vs. garbage that breaks your script. Here is the template:
You are extracting structured data from a [DOCUMENT TYPE].
Return ONLY valid JSON. No markdown. No explanation. No "here is the output."
Format: {"items": [{"field_1": "value", "field_2": "value"}]}
Rules:
- If a field is unreadable, use null. Do not guess.
- If a field does not exist on this page, use null. Do not hallucinate.
- Preserve exact codes and identifiers — dashes, slashes, and punctuation matter.
- Ignore page headers, footers, watermarks, and page numbers.
- If the page contains no valid items, return {"items": []}.
Each line of this template exists because a previous version of the prompt failed in a specific way. Here is what happened without each rule:
- Without "No markdown. No explanation." — DeepSeek about 30% of the time would wrap the JSON in triple-backtick code fences or preface it with "Here is the extracted data:" My parser choked. Adding this line dropped the error rate to near zero.
- Without "use null. Do not guess." — On a page where a part number was slightly blurry, the model invented a plausible-looking code. I only caught it because I recognized the real part number from memory. A hallucinated part number in your database is worse than a blank cell — it looks correct and is silently wrong.
- Without "Ignore headers." — The model extracted the page number and the supplier's company name as "products." I got rows like "Page 42" with part number "ABC Radiator Co." in my CSV. Took me 10 minutes to figure out why my product count was inflated.
- Without "If no valid items, return empty array." — On section divider pages, the model sometimes hallucinated products because it felt obligated to return something. Giving it explicit permission to return nothing fixed this.
These rules look obvious in hindsight. They were not obvious when I started. Each one was added after I found a specific failure in my CSV and traced it back to the prompt.
What I Would Skip If I Did This Again
I wasted time on things that did not matter. Here is what I would not repeat:
- I tried three different "PDF to PNG" tools before picking the simplest one. The free ones work fine. Do not research this. Pick the first one that exports 300 DPI PNGs and move on.
- I obsessed over the CSV column order. It does not matter. You can reorder columns in Excel in 10 seconds. Get the data out first, format later.
- I tried to make the prompt handle every edge case upfront. You cannot predict edge cases before you see them. Write a prompt that handles 80% of pages. Run it. Find the failures. Add rules for those specific failures. Repeat. Trying to write the perfect prompt before seeing any output just delays seeing any output.
- I worried about Python virtual environments. Every Python tutorial mentions
venv. For a single script that calls one API and writes one CSV, you do not need it. Install Python,pip install requests, run the script. The gatekeeping around "proper Python setup" stops non-programmers from starting.
Why Two Models Instead of One
I did not pick between Claude and DeepSeek. I used both for different jobs:
- DeepSeek did 90% of the work. Their vision API is absurdly cheap. It handled every clean, well-structured page without issues. The output quality was slightly lower than Claude's on ambiguous pages, but the cost savings bought me enough margin to manually review those rows.
- Claude handled the hard 10%. Pages with unusual layouts, nested tables, or mixed Chinese-English text. Claude's reasoning is better on edge cases. I used it sparingly — the pages where DeepSeek's output needed too much cleanup to be worth it.
The principle is the same as hiring: you do not pay a senior engineer to do data entry. Use the cheap tool for volume, the smart tool for hard problems. This is not a technical decision. It is a cost decision — and it is the reason the whole project cost under a dollar instead of $20.
If I had run all 500 pages through Claude's API at standard pricing, the bill would have been somewhere around $15-25 depending on resolution. Still cheap compared to hiring a VA. But $1 sounds a lot better than $20 when you are a solo operator testing whether an idea even works.
Still Staring at a Supplier Catalog?
If you have a PDF that needs to become a database and do not know whether AI vision will work on your specific document layout, send me a 2-page sample through the Contact page. I will tell you honestly what accuracy to expect — and whether you are better off with this approach or just hiring someone to type it manually.
Most people pick wrong because they do not test first. Two pages is enough to know.
Related Articles
- How I Built a 15,000+ Product Database for Under $1 Using Claude and DeepSeek — the full database workflow, from PDF to CSV.
- Why Standard OCR Fails on 500-page PDF Catalogs (And How I Solved It with AI Vision) — side-by-side comparison of OCR vs AI vision.
- Codex, Claude, and DeepSeek: How I Actually Use AI Tools from China — the real tool split behind this project.
- AI Tools & Extensions — all the tools, APIs, and extensions I use.
→ Back to AI Export Lab — every build note from this experiment.