У меня есть python парсер:
from selenium.common.exceptions import NoSuchElementException
import argparse
import os
from typing import Optional

import pandas as pd
import undetected_chromedriver as uc
from selenium.webdriver.common.by import By

from util.selenium_workflow import driver_context_manager

INPUT_CSV_PATH = "data/processed/matches_cleaned.csv"
OUTPUT_CSV_PATH = "data/processed/series_results.csv"
SERIES_DIV_SELECTOR = ".columns"
SERIES_RESULT_SELECTOR = (
    "a.col:nth-child(1) > div:nth-child(2) > div:nth-child(1) > div:nth-child(1)"
)


def save_to_csv(row: pd.Series, input_path: str) -> None:
    """
    Сохраняет одну строку в CSV файл. Если файл существует — добавляет, иначе создаёт.
    """
    columns = ["team_name", "opponent", "date",
               "series_result", "match_type", "link"]
    # Гарантируем наличие всех необходимых полей
    row_dict = {col: row.get(col, None) for col in columns}
    df_new = pd.DataFrame([row_dict], columns=columns)

    if os.path.exists(input_path):
        df_new.to_csv(input_path, mode="a", index=False,
                      header=False, encoding="utf-8")
    else:
        df_new.to_csv(input_path, mode="w", index=False,
                      header=True, encoding="utf-8")
    print(f"Сохранено 1 строка в {input_path}")


def process_row(
    row: pd.Series, driver: uc.Chrome, index: Optional[int] = None
) -> pd.Series:
    """
    Обрабатывает один ряд данных.
    Возвращает готовый ряд, который можно добавить в файл.
    В зависимости от типа матча (bo3/bo5 или bo1) добавляет соответствующее значение в поле 'match_type'.
    """
    link = row["link"]
    driver.get(link)

    try:
        print("try bo3/bo5 logic")
        parent_element = driver.find_element(
            By.CSS_SELECTOR, SERIES_DIV_SELECTOR)
        a = parent_element.find_element(By.CSS_SELECTOR, "a.col:nth-child(1)")
        row["series_link"] = a.get_attribute("href")
        row["series_result"] = parent_element.find_element(
            By.CSS_SELECTOR,
            SERIES_RESULT_SELECTOR,
        ).text.strip()
        row["match_type"] = "bo3/bo5"
        print("bo3/bo5 успешно обработан")
        return row

    except NoSuchElementException as e:
        print("bo3/bo5 не найден, пробуем bo1...", e)

        try:
            team_left = driver.find_element(By.CSS_SELECTOR, ".team-left")
            team_left_name = team_left.find_element(By.TAG_NAME, "img").get_attribute(
                "alt"
            )
            team_left_w_or_l = (
                "W"
                if team_left.find_element(By.TAG_NAME, "div").get_attribute("class")
                == "bold won"
                else "L"
            )

            # Логика для обработки bo1
            match ((team_left_w_or_l == "W"), (team_left_name == row["team_name"])):
                case (True, True):
                    row["series_result"] = "1:0"
                case (True, False):
                    row["series_result"] = "0:1"
                case (False, True):
                    row["series_result"] = "0:1"
                case (False, False):
                    row["series_result"] = "1:0"

            row["match_type"] = "bo1"
            print("bo1 успешно обработан")
            return row

        except Exception as inner_e:
            print("Ошибка при обработке bo1:", inner_e)
            return row  # или пробросить ошибку, если нужно

    except Exception as other:
        print("Неизвестная ошибка при обработке:", other)
        return row


def get_processed_teams(csv_file):
    """
    Читает результирующий CSV и возвращает множество названий команд, для которых уже
    были спаршены матчи.
    """
    if os.path.exists(csv_file):
        df = pd.read_csv(csv_file)
        return set(df["team_name"].unique())
    return set()


def main(test_mode: bool = False) -> None:
    if test_mode:
        print("TEST MODE IS ENABLED\nPROCESSING ONLY 1 ROW")
        with driver_context_manager() as driver_manager:
            driver = driver_manager.driver
            data = {
                "team_id": [6667],
                "opponent_id": [5995],
                "date": ["13/12/24"],
                "link": [
                    "https://www.hltv.org/stats/matches/mapstatsid/189558/g2-vs-heroic"
                ],
                "series_link": [None],
                "series_result": [None],
            }
            row = pd.DataFrame(data).iloc[0]
            result_row = process_row(row, driver)
            print(result_row)
            return

    processed_df = get_processed_teams(OUTPUT_CSV_PATH)
    print(f"Обработано: {len(processed_df)}")
    full_df = pd.read_csv(INPUT_CSV_PATH)
    unprocessed_df = full_df[~full_df["link"].isin(processed_df)]

    if unprocessed_df.empty:
        print("Все строки уже обработаны.")
        return

    print(f"Начинаем обработку {len(unprocessed_df)} строк...")

    for index, row in unprocessed_df.iterrows():
        try:
            with driver_context_manager(False) as driver_manager:
                driver = driver_manager.driver
                extended_row = {
                    **row.to_dict(),
                    "series_link": None,
                    "series_result": None,
                }  # потому что process_row ожидает в таком форате данные
                row_series = pd.Series(extended_row)
                result_row = process_row(row_series, driver, index)
                save_to_csv(result_row, OUTPUT_CSV_PATH)
        except Exception as e:
            print(f"Ошибка при обработке строки {index}: {e}")
            print("Останавливаем парсинг. Вы можете перезапустить позже.")
            break


if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    # чтобы запустить модуль с флагом --test и это передало True в test_mode
    parser.add_argument("--test", action="store_true", help="Run in test mode")
    args = parser.parse_args()
    main(test_mode=args.test)

Измени механизм проверки сохранения прогресса. Он должен смотреть set обработанных ссылок, и начинать с последней необработаной, а не сет обработаных команд