df.to_csv("file.csv", index=False) saves a table. Leave out index=False and the row labels are written as an unnamed first column, which comes back as Unnamed: 0 when the file is read again. Without a file name, to_csv returns the CSV text, which is handy for a quick look.
read_csv has an option for most messy files:
sep=";" for semicolon-separated files, and decimal="," where numbers are written 48,00 (common in European exports).
usecols=[...] reads only some columns; nrows= only the first rows.
na_values=["-", "missing"] treats extra markers as missing, on top of the defaults (blank, NA, n/a and a few more).
parse_dates=["date"] converts date columns while reading; dtype={"id": str} keeps ids as text.