How to deduplicate rows in a CSV file with Python

If every row in your CSV is a genuine full duplicate, Python's standard library is enough — no pandas install needed. Here's a script that works on any file, keeping the first occurrence of each row and dropping the rest:

import csv, sys

def dedupe(path_in, path_out):
    seen = set()
    with open(path_in, newline="", encoding="utf-8") as f_in, \
         open(path_out, "w", newline="", encoding="utf-8") as f_out:
        reader = csv.reader(f_in)
        writer = csv.writer(f_out)
        for row in reader:
            key = tuple(row)
            if key not in seen:
                seen.add(key)
                writer.writerow(row)

if __name__ == "__main__":
    dedupe(sys.argv[1], sys.argv[2])

Run it with python3 dedupe.py input.csv output.csv.

When "the whole row" isn't the right definition of duplicate

Most real exports aren't that clean. Two rows are "the same customer" even though the phone number is formatted differently, or the email has different casing, or one row has a typo in the company name. To dedupe by a single column instead of the whole row, swap the key:

key = row[2].strip().lower()  # e.g. column index 2 is the email

That covers a lot of cases. It stops covering them the moment you need more than one rule at once — normalize a date format and dedupe by email and map five inconsistent header names to the ones your next tool expects. At that point you're not writing a five-line script anymore, you're writing and testing a small program, and that's the part people usually pay someone else to do.

The finished version, free

The five lines above dedupe on the whole row. csvclean.py is the finished version of the same idea: dedupe on any column, ignoring case and padding, plus whitespace, ISO dates, header cleanup, and a --report mode that tells you what is wrong before it changes anything. It reads .xlsx directly too — no save-as-CSV step, and no dependency: a spreadsheet is a zip of XML, and Excel dates come back as dates rather than as the day numbers it stores. It also reads 1.234,56 and 1,234.56 correctly, which is harder than it looks.

csvclean.py on GitHub — one file, no dependencies, public domain, tested on Python 3.9 to 3.13. Keep it, change it, ship it in something you sell.

Or skip writing it yourself

Send a sample of the file, and get back a script that dedupes by whichever field actually identifies a duplicate in your data, normalizes dates and number formats, and maps columns to the headers you need — yours to re-run on every future export.

49€ — one-time, fixed, 48h

Buy — Stripe checkout   details

← See the other two packages (website scraping, API/webhook bridges)