Esempio n. 1
0
def main():
    # Colorama module's initialization.
    init(autoreset=True)

    with open('COPYRIGHT', 'r', encoding="utf8") as copyright:
        cop = copyright.read()

    version_snoop = f"%(prog)s: {__version__}\n" +  \
                     f"{requests.__description__}:  {requests.__version__}\n" + \
                     f"Python:  {platform.python_version()}\n\n" + \
                     f"\033[37m{cop}\033[0m\n"

    with open('sites.md', 'r', encoding="utf8") as support:
        sup = support.read()
    sup_color = f"\033[37m{sup}\033[0m"

    donate = ("""
╭donate:
├──BTC_BHC: \033[37m1EXoQj1rd5oi54k9yynVLsR4kG61e4s8g3\033[0m
├──Яндекс.Деньги: \033[37m4100111364257544\033[0m  
└──PayPal: \033[[email protected]\033[0m    
\nИсходный код: \033[37mhttps://github.com/snooppr/snoop\033[0m                """
              )

    parser = ArgumentParser(
        formatter_class=RawDescriptionHelpFormatter,
        description=f"{module_name} (Version {__version__})",
        epilog=donate)
    parser.add_argument("--donate Y",
                        action="store_true",
                        dest="donation",
                        help="Пожертвовать на развитие Snoop project-а")
    parser.add_argument(
        "--sort Y",
        action="store_true",
        dest="sort",
        help=
        "Обновление/сортировка черного и белого списков (.json) сайтов БД Snoop"
    )
    parser.add_argument(
        "--version",
        "-V",
        action="version",
        version=(version_snoop),
        help="Вывод на дисплей: версий Snoop, Python; Сублицензии")
    parser.add_argument(
        "--verbose",
        "-v",
        "-d",
        "--debug",
        action="store_true",
        dest="verbose",
        default=False,
        help=
        "Вывод на дисплей отладочной информации и подробная её вербализация")
    # parser.add_argument("--rank", "-r",
    #                    action="store_true", dest="rank", default=False,
    #                   help="Результаты поиска сортируются не по алфавиту, а по полуярности рейтинга Alexa #опция временно отключена")
    parser.add_argument(
        "--folderoutput",
        "-fo",
        dest="folderoutput",
        help=
        "Указать каталог отличный от стандартного, куда будут сохранены результаты поиска при разовом поиске нескольких имён"
    )
    parser.add_argument(
        "--output",
        "-o",
        dest="output",
        help=
        "Указать отличный от стандартного файл с сохранением результатов. По умолчанию файл для сохранения результатов — переменное username.txt"
    )
    parser.add_argument(
        "--tor",
        "-t",
        action="store_true",
        dest="tor",
        default=False,
        help=
        "Делать запросы через Tor-службу; требуется чтобы Tor был установлен по системному стандартному пути и не модифицирован torrc"
    )
    parser.add_argument(
        "--unique-tor",
        "-u",
        action="store_true",
        dest="unique_tor",
        default=False,
        help=
        "Делать запросы через Tor-службу с новой цепочкой Tor после каждого запроса; увеличивает время выполнения; требуется чтобы Tor был установлен по системному стандартному пути"
    )
    parser.add_argument(
        "--proxy",
        "-p",
        metavar='PROXY_URL',
        action="store",
        dest="proxy",
        default=None,
        help="Делать запросы через прокси, например, socks5://127.0.0.1:9070")
    parser.add_argument(
        "--proxy_list",
        "-pl",
        metavar='PROXY_LIST',
        action="store",
        dest="proxy_list",
        default=None,
        help=
        "Поиск 'username' через случайный прокси, указать file.csv с прокси")
    parser.add_argument(
        "--check_proxies",
        "-cp",
        metavar='CHECK_PROXY',
        action="store",
        dest="check_prox",
        default=None,
        help="Связка с параметром '--proxy_list'. "
        "Скрипт проверяет рабочие ли предоставленные прокси из file.csv, являются ли они анонимными. "
        "Установите '0' для безлимитного количества успешно-проверенных прокси, установите > '1' для ограничения"
    )
    parser.add_argument(
        "--csv",
        action="store_true",
        dest="csv",
        default=False,
        help="Сохранить файл в формате (nickname.CSV) с расширенным анализом")
    parser.add_argument(
        "--json",
        "-j",
        metavar="JSON_FILE",
        dest="json_file",
        default="data.json",
        help=
        "Указать для поиска 'username' другую БД сайтов в формате file.json")
    parser.add_argument(
        "--site",
        action="append",
        metavar='SITE_NAME',
        dest="site_list",
        default=None,
        help=
        "Указать имя сайта из БД (data.json). Ограничение поиска 'username' до одного ресурса"
    )
    parser.add_argument(
        "--timeout",
        action="store",
        metavar='--time 9',
        dest="timeout",
        type=timeout_check,
        default=None,
        help="Выделение макс.времени на ожидание ответа от сервера\n"
        "Влияет на продолжительность поиска. Оптимальное значение при хорошем интернет соединении и нескольких 'упавших' сайтов = 9с."
    )
    parser.add_argument("--print-found",
                        action="store_true",
                        dest="print_found_only",
                        default=False,
                        help="Выводить на печать только найденные аккаунты")
    parser.add_argument(
        "--no-color",
        action="store_true",
        dest="no_color",
        default=False,
        help="Монохромный терминал, не использовать цвета в url")
    parser.add_argument(
        "username",
        nargs='+',
        metavar='USERNAMES',
        action="store",
        help=
        "Никнейм разыскиваемого пользователя, поддерживается несколько имён")
    parser.add_argument("--list all",
                        action="store_true",
                        dest="listing",
                        help="Вывод на дисплей БД поддерживаемых сайтов")
    parser.add_argument("--update Y",
                        action="store_true",
                        dest="update",
                        help="Обновить Snoop")

    args = parser.parse_args()

    if args.sort:
        subprocess.run(["python3", "site_list.py"])
        exit(0)

    if args.listing:
        listall = []
        with open('sites.md') as listyes:
            for site in listyes.readlines():
                patch = (site.split(']')[0]).replace("[", "  ")
                listall.append(patch)
            print(Fore.GREEN + "++Белый список++", *listall, sep="\n")

    if args.listing:
        listall_bad = []
        with open('bad_site.md') as listbad:
            for site_bad in listbad.readlines():
                patch_bad = (site_bad.split(']')[0]).replace("[", "  ")
                listall_bad.append(patch_bad)
            print(Fore.RED + "\n\n--Чёрный список--", *listall_bad, sep="\n")
        sys.exit(0)

    if args.donation:
        print(donate)
        webbrowser.open("https://yasobe.ru/na/snoop_project")
        print("Выход")
        sys.exit(0)

    if args.update:
        print("=======================")
        update_snoop()
        print("=======================\nВыход")
        sys.exit(0)

    # Argument check
    # TODO regex check on args.proxy
    if args.tor and (args.proxy != None or args.proxy_list != None):
        raise Exception("Tor и Proxy не могут быть запущены одновременно.")

    # Proxy argument check.
    # Does not necessarily need to throw an error,
    # since we could join the single proxy with the ones generated from the .csv,
    # but it seems unnecessarily complex at this time.
    if args.proxy != None and args.proxy_list != None:
        raise Exception(
            "Один прокси не может использоваться вместе со списком прокси.")

    # Make prompts
    if args.proxy != None:
        print("Using the proxy: " + args.proxy)

    global proxy_list

    if args.proxy_list != None:
        print_info("Loading proxies from", args.proxy_list, not args.color)

        proxy_list = load_proxies_from_csv(args.proxy_list)

    # Checking if proxies should be checked for anonymity.
    if args.check_prox != None and args.proxy_list != None:
        try:
            limit = int(args.check_prox)
            if limit == 0:
                proxy_list = check_proxy_list(proxy_list)
            elif limit > 0:
                proxy_list = check_proxy_list(proxy_list, limit)
            else:
                raise ValueError
        except ValueError:
            raise Exception(
                "Parameter --check_proxies/-cp must be a positive integer.")

    if args.tor or args.unique_tor:
        print(
            "\033[31mВнимание запущена экспериментальная функция! 'Snoop попытается работать через луковую сеть Tor'.\nВаши запросы могут посылаться НЕ анонимно!\033[0m\nТакже многие сайты могут блокировать выходные_ноды_Tor, что приведёт к 'ошибкам соединения' на этих сайтах."
        )

    # Check if both output methods are entered as input.
    if args.output is not None and args.folderoutput is not None:
        print("Вы можете использовать только один метода выхода.")
        sys.exit(1)

    # Check validity for single username output.
    if args.output is not None and len(args.username) != 1:
        print("Вы можете использовать флаг --output только с одним username")
        sys.exit(1)

    response_json_online = None
    site_data_all = None

    # Try to load json from website.
    try:
        response_json_online = requests.get(url=args.json_file)
    except requests.exceptions.MissingSchema:  # In case the schema is wrong it's because it may not be a website
        pass

    # Check if the response is appropriate.
    if response_json_online is not None and response_json_online.status_code == 200:
        # Since we got data from a website, try to load json and exit if parsing fails.
        try:
            site_data_all = response_json_online.json()
        except ValueError:
            print("Invalid JSON website!")
            sys.exit(1)
            pass

    data_file_path = os.path.join(os.path.dirname(os.path.realpath(__file__)),
                                  args.json_file)
    # This will be none if the request had a missing schema
    if site_data_all is None:
        # Check if the file exists otherwise exit.
        if not os.path.exists(data_file_path):
            print("JSON file не существует.")
            print(
                "Вы не добавили .json файл или убедитесь, что сделали запрос http:// или https://..."
            )
            sys.exit(1)
        else:
            raw = open(data_file_path, "r", encoding="utf-8")
            try:
                site_data_all = json.load(raw)
            except:
                print("Invalid загружаемый JSON file.")

    if args.site_list is None:
        # Not desired to look at a sub-set of sites
        site_data = site_data_all
    else:
        # User desires to selectively run queries on a sub-set of the site list.

        # Make sure that the sites are supported & build up pruned site database.
        site_data = {}
        site_missing = []
        for site in args.site_list:
            for existing_site in site_data_all:
                if site.lower() == existing_site.lower():
                    site_data[existing_site] = site_data_all[existing_site]
            if not site_data:
                # Build up list of sites not supported for future error message.
                site_missing.append(f"'{site}'")

        if site_missing:
            print(
                f"Ошибка: желаемые сайты не найдены: {', '.join(site_missing)}."
            )
            sys.exit(1)


#rak опция временно отключена
#if args.rank:
# Sort data by rank
#site_dataCpy = dict(site_data)
#ranked_sites = sorted(site_data, key=lambda k: ("rank" not in k, site_data[k].get("rank", sys.maxsize)))
#site_data = {}
#for site in ranked_sites:
#site_data[site] = site_dataCpy.get(site)

# Run report on all specified users.
    for username in args.username:
        print()

        if args.output:
            file = open(args.output, "w", encoding="utf-8")
        elif args.folderoutput:  # In case we handle multiple usernames at a targetted folder.
            # If the folder doesnt exist, create it first
            if not os.path.isdir(args.folderoutput):
                os.mkdir(args.folderoutput)
            file = open(os.path.join(args.folderoutput, username + ".txt"),
                        "w",
                        encoding="utf-8")
        else:
            file = open(username + ".txt", "w", encoding="utf-8")

        # We try to ad a random member of the 'proxy_list' var as the proxy of the request.
        # If we can't access the list or it is empty, we proceed with args.proxy as the proxy.
        try:
            random_proxy = random.choice(proxy_list)
            proxy = f'{random_proxy.protocol}://{random_proxy.ip}:{random_proxy.port}'
        except (NameError, IndexError):
            proxy = args.proxy

        results = snoop(username,
                        site_data,
                        verbose=args.verbose,
                        tor=args.tor,
                        unique_tor=args.unique_tor,
                        proxy=args.proxy,
                        print_found_only=args.print_found_only,
                        timeout=args.timeout,
                        color=not args.no_color)

        exists_counter = 0
        for website_name in results:
            dictionary = results[website_name]
            if dictionary.get("exists") == "yes":
                exists_counter += 1
                file.write(dictionary["url_user"] + "\n")
        file.write("\n" f"Запрашиваемый объект: <")
        file.write(username)
        file.write(f"> найден: {exists_counter} раз(а)")
        file.write("\n" f"Обновлено: ")
        file.write(date.strftime("%d/%m/%Yг. в %Hч.%Mм.%Sс."))
        print(Fore.WHITE + "├─Результаты поиска:", "всего найдено —",
              exists_counter, "url")
        file.close()

        if args.csv == True:
            with open(username + ".csv", "w", newline='',
                      encoding="utf-8") as csv_report:
                writer = csv.writer(csv_report)
                writer.writerow([
                    'username', 'name', 'url_main', 'url_user', 'exists',
                    'http_status', 'response_time_ms'
                ])
                for site in results:
                    writer.writerow([
                        username, site, results[site]['url_main'],
                        results[site]['url_user'], results[site]['exists'],
                        results[site]['http_status'],
                        results[site]['response_time_ms']
                    ])
Esempio n. 2
0
def main():
    # Colorama module's initialization.
    init(autoreset=True)

    version_string = f"%(prog)s {__version__}\n" +  \
                     f"{requests.__description__}:  {requests.__version__}\n" + \
                     f"Python:  {platform.python_version()}"

    parser = ArgumentParser(
        formatter_class=RawDescriptionHelpFormatter,
        description=f"{module_name} (Version {__version__})")
    parser.add_argument("--version",
                        action="version",
                        version=version_string,
                        help="Display version information and dependencies.")
    parser.add_argument(
        "--verbose",
        "-v",
        "-d",
        "--debug",
        action="store_true",
        dest="verbose",
        default=False,
        help="Display extra debugging information and metrics.")
    parser.add_argument(
        "--rank",
        "-r",
        action="store_true",
        dest="rank",
        default=False,
        help=
        "Present websites ordered by their Alexa.com global rank in popularity."
    )
    parser.add_argument(
        "--folderoutput",
        "-fo",
        dest="folderoutput",
        help=
        "If using multiple usernames, the output of the results will be saved to this folder."
    )
    parser.add_argument(
        "--output",
        "-o",
        dest="output",
        help=
        "If using single username, the output of the result will be saved to this file."
    )
    parser.add_argument(
        "--tor",
        "-t",
        action="store_true",
        dest="tor",
        default=False,
        help=
        "Make requests over Tor; increases runtime; requires Tor to be installed and in system path."
    )
    parser.add_argument(
        "--unique-tor",
        "-u",
        action="store_true",
        dest="unique_tor",
        default=False,
        help=
        "Make requests over Tor with new Tor circuit after each request; increases runtime; requires Tor to be installed and in system path."
    )
    parser.add_argument("--csv",
                        action="store_true",
                        dest="csv",
                        default=False,
                        help="Create Comma-Separated Values (CSV) File.")
    parser.add_argument(
        "--site",
        action="append",
        metavar='SITE_NAME',
        dest="site_list",
        default=None,
        help=
        "Limit analysis to just the listed sites. Add multiple options to specify more than one site."
    )
    parser.add_argument(
        "--proxy",
        "-p",
        metavar='PROXY_URL',
        action="store",
        dest="proxy",
        default=None,
        help="Make requests over a proxy. e.g. socks5://127.0.0.1:1080")
    parser.add_argument(
        "--json",
        "-j",
        metavar="JSON_FILE",
        dest="json_file",
        default="data.json",
        help="Load data from a JSON file or an online, valid, JSON file.")
    parser.add_argument(
        "--proxy_list",
        "-pl",
        metavar='PROXY_LIST',
        action="store",
        dest="proxy_list",
        default=None,
        help=
        "Make requests over a proxy randomly chosen from a list generated from a .csv file."
    )
    parser.add_argument(
        "--check_proxies",
        "-cp",
        metavar='CHECK_PROXY',
        action="store",
        dest="check_prox",
        default=None,
        help="To be used with the '--proxy_list' parameter. "
        "The script will check if the proxies supplied in the .csv file are working and anonymous."
        "Put 0 for no limit on successfully checked proxies, or another number to institute a limit."
    )
    parser.add_argument(
        "--print-found",
        action="store_true",
        dest="print_found_only",
        default=False,
        help="Do not output sites where the username was not found.")
    parser.add_argument(
        "username",
        nargs='+',
        metavar='USERNAMES',
        action="store",
        help="One or more usernames to check with social networks.")

    args = parser.parse_args()

    # Argument check
    # TODO regex check on args.proxy
    if args.tor and (args.proxy != None or args.proxy_list != None):
        raise Exception("Tor and Proxy cannot be set in the meantime.")

    # Proxy argument check.
    # Does not necessarily need to throw an error,
    # since we could join the single proxy with the ones generated from the .csv,
    # but it seems unnecessarily complex at this time.
    if args.proxy != None and args.proxy_list != None:
        raise Exception("A single proxy cannot be used along with proxy list.")

    # Make prompts
    if args.proxy != None:
        print("Using the proxy: " + args.proxy)

    global proxy_list

    if args.proxy_list != None:
        print_info("Loading proxies from", args.proxy_list)

        proxy_list = load_proxies_from_csv(args.proxy_list)

    # Checking if proxies should be checked for anonymity.
    if args.check_prox != None and args.proxy_list != None:
        try:
            limit = int(args.check_prox)
            if limit == 0:
                proxy_list = check_proxy_list(proxy_list)
            elif limit > 0:
                proxy_list = check_proxy_list(proxy_list, limit)
            else:
                raise ValueError
        except ValueError:
            raise Exception(
                "Parameter --check_proxies/-cp must be a positive integer.")

    if args.tor or args.unique_tor:
        print("Using Tor to make requests")
        print(
            "Warning: some websites might refuse connecting over Tor, so note that using this option might increase connection errors."
        )

    # Check if both output methods are entered as input.
    if args.output is not None and args.folderoutput is not None:
        print("You can only use one of the output methods.")
        sys.exit(1)

    # Check validity for single username output.
    if args.output is not None and len(args.username) != 1:
        print("You can only use --output with a single username")
        sys.exit(1)

    response_json_online = None
    site_data_all = None

    # Try to load json from website.
    try:
        response_json_online = requests.get(url=args.json_file)
    except requests.exceptions.MissingSchema:  # In case the schema is wrong it's because it may not be a website
        pass

    # Check if the response is appropriate.
    if response_json_online is not None and response_json_online.status_code == 200:
        # Since we got data from a website, try to load json and exit if parsing fails.
        try:
            site_data_all = response_json_online.json()
        except ValueError:
            print("Invalid JSON from website!")
            sys.exit(1)
            pass

    data_file_path = os.path.join(os.path.dirname(os.path.realpath(__file__)),
                                  args.json_file)
    # This will be none if the request had a missing schema
    if site_data_all is None:
        # Check if the file exists otherwise exit.
        if not os.path.exists(data_file_path):
            print("JSON file doesn't exist.")
            print(
                "If this is not a file but a website, make sure you have appended http:// or https://."
            )
            sys.exit(1)
        else:
            raw = open(data_file_path, "r", encoding="utf-8")
            try:
                site_data_all = json.load(raw)
            except:
                print("Invalid JSON loaded from file.")

    if args.site_list is None:
        # Not desired to look at a sub-set of sites
        site_data = site_data_all
    else:
        # User desires to selectively run queries on a sub-set of the site list.

        # Make sure that the sites are supported & build up pruned site database.
        site_data = {}
        site_missing = []
        for site in args.site_list:
            for existing_site in site_data_all:
                if site.lower() == existing_site.lower():
                    site_data[existing_site] = site_data_all[existing_site]
            if not site_data:
                # Build up list of sites not supported for future error message.
                site_missing.append(f"'{site}'")

        if site_missing:
            print(
                f"Error: Desired sites not found: {', '.join(site_missing)}.")
            sys.exit(1)

    if args.rank:
        # Sort data by rank
        site_dataCpy = dict(site_data)
        ranked_sites = sorted(
            site_data,
            key=lambda k:
            ("rank" not in k, site_data[k].get("rank", sys.maxsize)))
        site_data = {}
        for site in ranked_sites:
            site_data[site] = site_dataCpy.get(site)

    # Run report on all specified users.
    for username in args.username:
        print()

        if args.output:
            file = open(args.output, "w", encoding="utf-8")
        elif args.folderoutput:  # In case we handle multiple usernames at a targetted folder.
            # If the folder doesnt exist, create it first
            if not os.path.isdir(args.folderoutput):
                os.mkdir(args.folderoutput)
            file = open(os.path.join(args.folderoutput, username + ".txt"),
                        "w",
                        encoding="utf-8")
        else:
            file = open(username + ".txt", "w", encoding="utf-8")

        # We try to ad a random member of the 'proxy_list' var as the proxy of the request.
        # If we can't access the list or it is empty, we proceed with args.proxy as the proxy.
        try:
            random_proxy = random.choice(proxy_list)
            proxy = f'{random_proxy.protocol}://{random_proxy.ip}:{random_proxy.port}'
        except (NameError, IndexError):
            proxy = args.proxy

        results = {}
        results = sherlock(username,
                           site_data,
                           verbose=args.verbose,
                           tor=args.tor,
                           unique_tor=args.unique_tor,
                           proxy=args.proxy,
                           print_found_only=args.print_found_only)

        exists_counter = 0
        for website_name in results:
            dictionary = results[website_name]
            if dictionary.get("exists") == "yes":
                exists_counter += 1
                file.write(dictionary["url_user"] + "\n")
        file.write("Total Websites : {}".format(exists_counter))
        file.close()

        if args.csv == True:
            with open(username + ".csv", "w", newline='',
                      encoding="utf-8") as csv_report:
                writer = csv.writer(csv_report)
                writer.writerow([
                    'username', 'name', 'url_main', 'url_user', 'exists',
                    'http_status', 'response_time_ms'
                ])
                for site in results:
                    writer.writerow([
                        username, site, results[site]['url_main'],
                        results[site]['url_user'], results[site]['exists'],
                        results[site]['http_status'],
                        results[site]['response_time_ms']
                    ])
Esempio n. 3
0
def main():

    with open('COPYRIGHT', 'r', encoding="utf8") as copyright:
        cop = copyright.read()

    version_snoop = f"%(prog)s: {__version__}\n" +  \
                     f"{requests.__description__}:  {requests.__version__}\n" + \
                     f"Python:  {platform.python_version()}\n\n" + \
                     f"\033[37m{cop}\033[0m\n"

    with open('sites.md', 'r', encoding="utf8") as support:
        sup = support.read()
    sup_color = f"\033[37m{sup}\033[0m"

    # Пожертование.
    donate = ("""
╭donate:
├──BTC_BHC: \033[37m1EXoQj1rd5oi54k9yynVLsR4kG61e4s8g3\033[0m
├──Яндекс.Деньги: \033[37m4100111364257544\033[0m  
└──PayPal: \033[[email protected]\033[0m    
\nИсходный код: \033[37mhttps://github.com/snooppr/snoop\033[0m """)

    # Назначение опций Snoop.
    parser = ArgumentParser(
        formatter_class=RawDescriptionHelpFormatter,
        description=f"{module_name} (Version {__version__})",
        epilog=donate)
    parser.add_argument("--donate Y",
                        action="store_true",
                        dest="donation",
                        help="Пожертвовать на развитие Snoop project-а")
    parser.add_argument(
        "--sort Y",
        action="store_true",
        dest="sort",
        help=
        "Обновление/сортировка черного и белого списков (.json) сайтов БД Snoop"
    )
    parser.add_argument(
        "--version",
        "-V",
        action="version",
        version=(version_snoop),
        help="Вывод на дисплей: версий Snoop, Python; Сублицензии")
    parser.add_argument(
        "--verbose",
        "-v",
        "-d",
        "--debug",
        action="store_true",
        dest="verbose",
        default=False,
        help=
        "Вывод на дисплей отладочной информации и подробная её вербализация")
    parser.add_argument(
        "--folderoutput",
        "-fo",
        dest="folderoutput",
        help=
        "Указать каталог отличный от стандартного, куда будут сохранены результаты поиска при разовом поиске нескольких имён"
    )
    parser.add_argument(
        "--output",
        "-o",
        dest="output",
        help=
        "Указать отличный от стандартного файл с сохранением результатов. По умолчанию файл для сохранения результатов — переменное username.txt"
    )
    parser.add_argument(
        "--tor",
        "-t",
        action="store_true",
        dest="tor",
        default=False,
        help=
        "Делать запросы через Tor-службу; требуется чтобы Tor был установлен по системному стандартному пути и не модифицирован torrc"
    )
    parser.add_argument(
        "--unique-tor",
        "-u",
        action="store_true",
        dest="unique_tor",
        default=False,
        help=
        "Делать запросы через Tor-службу с новой цепочкой Tor после каждого запроса; увеличивает время выполнения; требуется чтобы Tor был установлен по системному стандартному пути"
    )
    parser.add_argument(
        "--proxy",
        "-p",
        metavar='PROXY_URL',
        action="store",
        dest="proxy",
        default=None,
        help="Делать запросы через прокси, например, socks5://127.0.0.1:9070")
    parser.add_argument(
        "--proxy_list",
        "-pl",
        metavar='PROXY_LIST',
        action="store",
        dest="proxy_list",
        default=None,
        help=
        "Поиск 'username' через случайный прокси, указать file.csv с прокси")
    parser.add_argument(
        "--check_proxies",
        "-cp",
        metavar='CHECK_PROXY',
        action="store",
        dest="check_prox",
        default=None,
        help="Связка с параметром '--proxy_list'. "
        "Скрипт проверяет рабочие ли предоставленные прокси из file.csv, являются ли они анонимными. "
        "Установите '0' для безлимитного количества успешно-проверенных прокси, установите > '1' для ограничения"
    )
    parser.add_argument(
        "--csv",
        action="store_true",
        dest="csv",
        default=False,
        help="Сохранить файл в формате (nickname.CSV) с расширенным анализом")
    parser.add_argument(
        "--json",
        "-j",
        metavar="JSON_FILE",
        dest="json_file",
        default="data.json",
        help=
        "Указать для поиска 'username' другую БД сайтов в формате file.json")
    parser.add_argument(
        "--site",
        action="append",
        metavar='SITE_NAME',
        dest="site_list",
        default=None,
        help=
        "Указать имя сайта из БД (data.json). Ограничение поиска 'username' до одного ресурса"
    )
    parser.add_argument(
        "--timeout",
        action="store",
        metavar='--time 9',
        dest="timeout",
        type=timeout_check,
        default=None,
        help="Выделение макс.времени на ожидание ответа от сервера\n"
        "Влияет на продолжительность поиска. Оптимальное значение при хорошем интернет соединении и нескольких 'упавших' сайтов = 9с."
    )
    parser.add_argument("--print-found",
                        action="store_true",
                        dest="print_found_only",
                        default=False,
                        help="Выводить на печать только найденные аккаунты")
    parser.add_argument(
        "--no-func",
        "-n",
        action="store_true",
        dest="no_color",
        default=False,
        help="""✓Монохромный терминал, не использовать цвета в url\n
                                ✓Отключить звук\n
                                ✓Запретить открытие web browser-a""")
    parser.add_argument(
        "username",
        nargs='+',
        metavar='USERNAMES',
        action="store",
        help=
        "Никнейм разыскиваемого пользователя, поддерживается несколько имён")
    parser.add_argument(
        "--list all",
        action="store_true",
        dest="listing",
        help="Вывод на дисплей БД (БС+ЧС) поддерживаемых сайтов")
    parser.add_argument("--update Y",
                        action="store_true",
                        dest="update",
                        help="Обновить Snoop")

    args = parser.parse_args()

    # Опция сортировки.
    if args.sort:
        if sys.platform == 'win32':
            subprocess.run(["python", "site_list.py"])
        else:
            subprocess.run(["python3", "site_list.py"])
        exit(0)

    if args.listing:
        listall = []
        with open('sites.md', "r", encoding="utf8") as listyes:
            for site in listyes.readlines():
                patch = (site.split(']')[0]).replace("[", "  ")
                listall.append(patch)
            print(Fore.GREEN + "++Белый список++", *listall, sep="\n")

    if args.listing:
        listall_bad = []
        with open('bad_site.md', "r", encoding="utf8") as listbad:
            for site_bad in listbad.readlines():
                patch_bad = (site_bad.split(']')[0]).replace("[", "  ")
                listall_bad.append(patch_bad)
            print(Fore.RED + "\n\n--Чёрный список--", *listall_bad, sep="\n")
        sys.exit(0)

# Опция донат.
    if args.donation:
        print(donate)
        webbrowser.open("https://yasobe.ru/na/snoop_project")
        print("Выход")
        sys.exit(0)

# Завершение обновления Snoop.
    if args.update:
        print("=======================")
        update_snoop()
        print("=======================\nВыход")
        sys.exit(0)

# Проверка остальных аргументов.
# Проверка регулярных выражений TODO на args.proxy.
    if args.tor and (args.proxy != None or args.proxy_list != None):
        raise Exception("Tor и Proxy не могут быть запущены одновременно.")

# Проверка аргументов прокси.
# Не обязательно генерировать ошибку, так как мы могли бы объединить один прокси с теми, которые были сгенерированы из .csv,
# но в настоящее время это кажется излишне сложным.
    if args.proxy != None and args.proxy_list != None:
        raise Exception(
            "Один прокси не может использоваться вместе со списком прокси.")

# Делать подсказку.
    if args.proxy != None:
        print("Using the proxy: " + args.proxy)

    global proxy_list

    if args.proxy_list != None:
        print_info("Loading proxies from", args.proxy_list, not args.color)

        proxy_list = load_proxies_from_csv(args.proxy_list)

# Анонимность? Должны ли проки проверяться на анонимность.
    if args.check_prox != None and args.proxy_list != None:
        try:
            limit = int(args.check_prox)
            if limit == 0:
                proxy_list = check_proxy_list(proxy_list)
            elif limit > 0:
                proxy_list = check_proxy_list(proxy_list, limit)
            else:
                raise ValueError
        except ValueError:
            raise Exception(
                "Parameter --check_proxies/-cp must be a positive integer.")

    if args.tor or args.unique_tor:
        print(
            Fore.RED +
            "Внимание запущена экспериментальная функция!'Snoop попытается работать через луковую сеть Tor'.\n\
Ваши запросы могут посылаться НЕ анонимно!\n\
Также многие сайты могут блокировать выходные_ноды_Tor, что приведёт к 'ошибкам соединения' на этих сайтах."
        )

# Проверка, введены ли оба метода вывода в качестве ввода.
    if args.output is not None and args.folderoutput is not None:
        print("Вы можете использовать только один метода выхода.")
        sys.exit(1)

# Проверка правильность вывода одного из имен username.
    if args.output is not None and len(args.username) != 1:
        print("Вы можете использовать данный флаг только с одним username")
        sys.exit(1)

    response_json_online = None
    site_data_all = None

    # Попробовать загрузить JSON с веб-сайта.
    try:
        response_json_online = requests.get(url=args.json_file)
    except requests.exceptions.MissingSchema:  # В случае если Shema неверная (не может быть на сайте).
        pass

# Проверка на соответствие ответа.
    if response_json_online is not None and response_json_online.status_code == 200:
        # Поскольку мы получили данные с веб-сайта, попробовать загрузить json и выйти, если синтаксический анализ завершился ошибкой.
        try:
            site_data_all = response_json_online.json()
        except ValueError:
            print("Invalid JSON website!")
            sys.exit(1)
            pass

    data_file_path = os.path.join(os.path.dirname(os.path.realpath(__file__)),
                                  args.json_file)
    # Этого не будет, если в запросе отсутствовала Shema.
    if site_data_all is None:
        # Проверьте, существует ли файл, иначе выход.
        if not os.path.exists(data_file_path):
            print("JSON file не существует.")
            print(
                "Вы не добавили .json файл или убедитесь, что сделали запрос http:// или https://..."
            )
            sys.exit(1)
        else:
            raw = open(data_file_path, "r", encoding="utf-8")
            try:
                site_data_all = json.load(raw)
            except:
                print("Invalid загружаемый JSON file.")

    if args.site_list is None:
        # Не желательно смотреть на подмножество сайтов.
        site_data = site_data_all
    else:
        # Пользователь желает выборочно запускать запросы к подмножеству списку сайтов.

        # Убедится, что сайты поддерживаются, создать сокращенную базу данных сайта.
        site_data = {}
        site_missing = []
        for site in args.site_list:
            for existing_site in site_data_all:
                if site.lower() == existing_site.lower():
                    site_data[existing_site] = site_data_all[existing_site]
            if not site_data:
                # Создать список сайтов, которые не поддерживаются для будущего сообщения об ошибке.
                site_missing.append(f"'{site}'")

        if site_missing:
            print(
                f"Ошибка: желаемые сайты не найдены: {', '.join(site_missing)}."
            )
            sys.exit(1)

#Запись в txt.
    for username in args.username:
        print()

        if args.output:
            file = open(args.output, "w", encoding="utf-8")
        elif args.folderoutput:
            # В случае, если мы обрабатываем несколько имен пользователей в целевой папке. Если папка не существует, сначала создать её.
            if not os.path.isdir(args.folderoutput):
                os.mkdir(args.folderoutput)
            file = open(os.path.join(args.folderoutput, username + ".txt"),
                        "w",
                        encoding="utf-8")
        else:
            file = open("results/" + username + ".txt", "w", encoding="utf-8")
            try:
                file = open("results/" + username + ".txt",
                            "w",
                            encoding="utf-8")
            except (SyntaxError, ValueError):
                pass
# Попытаться объявить случайный 'proxy_list' в качестве прокси запроса.
# Если мы не можем получить доступ к списку или он пуст, мы используем 'args.proxy' в качестве прокси.
        try:
            random_proxy = random.choice(proxy_list)
            proxy = f'{random_proxy.protocol}://{random_proxy.ip}:{random_proxy.port}'
        except (NameError, IndexError):
            proxy = args.proxy

        results = snoop(username,
                        site_data,
                        verbose=args.verbose,
                        tor=args.tor,
                        unique_tor=args.unique_tor,
                        proxy=args.proxy,
                        print_found_only=args.print_found_only,
                        timeout=args.timeout,
                        color=not args.no_color)

        exists_counter = 0
        file.write("Адрес | ресурс" + "\n\n")
        for website_name in results:
            dictionary = results[website_name]
            if dictionary.get("exists") == "yes":
                exists_counter += 1
                file.write(dictionary["url_user"] + " | " + (website_name) +
                           "\n")
        file.write("\n" f"Запрашиваемый объект: <")
        file.write(username)
        file.write(f"> найден: {exists_counter} раз(а)")
        file.write("\n" f"Обновлено: ")
        file.write(date.strftime("%d/%m/%Yг. в %Hч.%Mм.%Sс."))
        print(Fore.WHITE + "├─Результаты поиска:", "всего найдено —",
              exists_counter, "url")

        #Запись в html.
        file = open("results/" + username + ".html", "w", encoding="utf-8")

        file.write("<h3>" + "Snoop Project" + "</h3>" + "Объект" + " " +
                   "<b>" + (username) + "</b>" + " " +
                   "найден на нижеперечисленных" + "<b> " +
                   str(exists_counter) + "</b> ресурсах: " + "<br><ol>")
        for website_name in results:
            dictionary = results[website_name]
            if dictionary.get("exists") == "yes":
                exists_counter += 1
                file.write("<li>" + "<a href='" + dictionary["url_user"] +
                           "'>" + (website_name) + "</a>" + "</li>")
        file.write(f"</ol> Запрашиваемый объект: <")
        file.write(username)
        file.write(f"> найден: <b>{exists_counter/2}</b> раз(а).")
        file.write("<br> Обновлено: ")
        file.write(date.strftime("%d/%m/%Yг. в %Hч.%Mм.%Sс.") + "<br>")
        file.write(
            "<br><a href='https://github.com/snooppr/snoop'>Snoop/Исходный код</a>"
        )
        file.close()

        if args.csv == True:
            print(
                Fore.WHITE +
                "├───Положительные результаты поиска сохранены в:",
                username + ".txt" + " " + "и", username + ".html")
            print(
                Fore.WHITE + "├───Расширенный анализ по поиску:" + Fore.RED +
                "\033[5m <\033[0m" + Fore.GREEN + f"{username}" + Fore.RED +
                "\033[5m>\033[0m", "сохранён в", username + ".csv")
        else:
            print(
                Fore.WHITE +
                "├───Положительные результаты поиска сохранены в:",
                username + ".txt" + " " + "и", username + ".html")
        file.close()

        #Запись в csv.
        if args.csv == True:
            with open("results/" + username + ".csv",
                      "w",
                      newline='',
                      encoding="utf-8") as csv_report:
                writer = csv.writer(csv_report)
                writer.writerow([
                    'Объект', 'Ресурс', 'url_main', 'url_user', 'статус',
                    'статус_кода', 'время/мс'
                ])
                for site in results:
                    writer.writerow([
                        username, site, results[site]['url_main'],
                        results[site]['url_user'], results[site]['exists'],
                        results[site]['http_status'],
                        results[site]['response_time_ms']
                    ])
# Открыть/нет браузер с результатами поиска.
    if args.no_color == False:
        if exists_counter >= 1:
            webbrowser.open(
                str("file://" + str(dirresults) + "/results/" + str(username) +
                    ".html"))


# Музыка.
        playsound('end.wav')