Python скрипты для изменения файла hosts

Раздел: Администрирование -> Администрирование

Файл hosts используется операционной системой для сопоставления доменных имен с IP-адресами. Редактирование этого файла может потребоваться для блокировки или перенаправления трафика, тестирования серверов или локальной разработки. Python предоставляет удобные средства для автоматизации этой задачи, однако необходимо учитывать особенности разных ОС, права доступа и формат файла.

Основное решение: чтение и запись файла hosts построчно

Наиболее надежный способ - обработать файл как обычный текстовый файл, построчно проверить каждую строку и записать изменения. Это позволяет избежать повреждения структуры и сохранить комментарии.

import os
import sys

HOSTS_PATH = {
    'win32': r'C:\Windows\System32\drivers\etc\hosts',
    'linux': '/etc/hosts',
    'darwin': '/etc/hosts'
}.get(sys.platform)

if not HOSTS_PATH:
    raise OSError('Operating system not supported')

# Чтение существующего содержимого
try:
    with open(HOSTS_PATH, 'r', encoding='utf-8') as f:
        lines = f.readlines()
except PermissionError:
    # На Windows требуется запуск от имени администратора, на Linux/macOS через sudo
    print('Ошибка: нет прав на чтение файла. Запустите скрипт с повышенными привилегиями.')
    sys.exit(1)

# Добавление новой записи, если её ещё нет
new_entry = '127.0.0.1 example.com'
entry_present = any(new_entry in line for line in lines if not line.strip().startswith('#'))

if not entry_present:
    # Добавляем перед маркером 'localhost' или в конец
    lines.append(f'{new_entry}\n')

# Запись изменений
with open(HOSTS_PATH, 'w', encoding='utf-8') as f:
    f.writelines(lines)

Python git bash (работа с git и bash в python)

Пояснение шагов:

  • Определение пути к файлу в зависимости от ОС (Windows, Linux, macOS).
  • Чтение всех строк с кодировкой UTF-8 (на старых Windows может быть ANSI, но UTF-8 чаще работает).
  • Проверка наличия записи с учётом комментариев (строки, начинающиеся с #).
  • Добавление записи и перезапись файла.

Типичные ошибки:

  • PermissionError - недостаточно прав. Решение: запустить скрипт от администратора (Windows) или с sudo (Linux/macOS).
  • UnicodeDecodeError - файл в другой кодировке (например, cp1251). Решение: открыть с ошибкой обработки encoding='utf-8', errors='ignore' или определить кодировку через chardet.
  • Неверное добавление - если добавить строку без символа новой строки, следующая операция может склеить записи. Всегда используйте \n.

Как автоматически запрашивать права администратора на Windows?

Можно использовать модуль ctypes для запроса повышения привилегий. Если скрипт запущен без прав, он перезапускает себя с аргументом --admin. Пример:

if sys.platform == 'win32':
    import ctypes
    if not ctypes.windll.shell32.IsUserAnAdmin():
        ctypes.windll.shell32.ShellExecuteW(
            None, 'runas', sys.executable, ' '.join(sys.argv), None, 1)
        sys.exit()

Python host file (редактирование файла hosts)

Проблема: бесконечный перезапуск, если пользователь отказывает в правах. Решение - обработать возвращаемое значение ShellExecuteW (32 - успех, другие коды - ошибка).

Как использовать pathlib для работы с путями?

from pathlib import Path

hosts = Path('/etc/hosts')
content = hosts.read_text(encoding='utf-8')
# Изменяем содержимое
if '127.0.0.1 test.local' not in content:
    with hosts.open('a', encoding='utf-8') as f:
        f.write('127.0.0.1 test.local\n')

Python установка программы (установка программы на python)

Дополнительно: для добавления строки без проверки дубликатов используется режим 'a' (append).

Как временно редактировать hosts только для определённого процесса?

Этот вопрос выходит за рамки прямого редактирования файла. Можно использовать виртуальную сеть Docker или настройки прокси, но с файлом hosts такой трюк не работает.

Как добавить несколько записей из списка?

entries = ['10.0.0.1 app.local', '10.0.0.2 db.local']
with open(HOSTS_PATH, 'a', encoding='utf-8') as f:
    for entry in entries:
        f.write(f'{entry}\n')

Ошибка: дублирование записей при повторном запуске. Решение - сначала прочитать и удалить старые совпадающие строки, а затем добавить новые.

Расширенные примеры работы с файлом hosts

1. Атомарная замена с резервным копированием

Пример
import shutil
from pathlib import Path

hosts = Path('/etc/hosts')
backup = hosts.with_suffix('.hosts.bak')

# Создаём резервную копию
shutil.copy2(hosts, backup)

# Читаем, редактируем, записываем во временный файл
temp = hosts.with_suffix('.tmp')
with hosts.open('r', encoding='utf-8') as src, temp.open('w', encoding='utf-8') as dst:
    for line in src:
        # Удаляем строки с определённым доменом
        if 'example.com' in line:
            continue
        dst.write(line)
    # Добавляем новую запись
    dst.write('192.168.1.100 newserver.local\n')

# Атомарно заменяем оригинал
temp.replace(hosts)
# После выполнения файл hosts обновлён, старый сохранён как /etc/hosts.bak

Преимущество: в случае сбоя, временный файл не повреждает оригинал.

2. Парсинг существующих записей в структуру данных

Пример
import re

parsed = []
with open(HOSTS_PATH, 'r', encoding='utf-8') as f:
    for line in f:
        stripped = line.strip()
        if not stripped or stripped.startswith('#'):
            continue
        parts = re.split(r'\s+', stripped, maxsplit=2)
        if len(parts) >= 2:
            parsed.append({'ip': parts[0], 'hostnames': parts[1].split('#')[0].strip().split()})

print(parsed[:5])
[{'ip': '127.0.0.1', 'hostnames': ['localhost']}, {'ip': '::1', 'hostnames': ['localhost', 'ip6-localhost', 'ip6-loopback']}]

3. Удаление дублирующихся записей с сохранением комментариев

Пример
seen = []
new_lines = []
with open(HOSTS_PATH, 'r', encoding='utf-8') as f:
    for line in f:
        stripped = line.strip()
        if not stripped or stripped.startswith('#'):
            new_lines.append(line)
            continue
        # Нормализуем: приводим к нижнему регистру, убираем лишние пробелы
        normalized = ' '.join(stripped.split())
        if normalized.lower() not in seen:
            seen.append(normalized.lower())
            new_lines.append(line)

with open(HOSTS_PATH, 'w', encoding='utf-8') as f:
    f.writelines(new_lines)
# Файл очищен от повторяющихся строк, комментарии сохранены.

4. Работа с hosts на Windows через кодировку cp1251

Пример
import chardet

with open(r'C:\Windows\System32\drivers\etc\hosts', 'rb') as f:
    raw = f.read()
    encoding = chardet.detect(raw)['encoding'] or 'utf-8'

with open(r'C:\Windows\System32\drivers\etc\hosts', 'r', encoding=encoding) as f:
    lines = f.readlines()
    # ... изменения

with open(r'C:\Windows\System32\drivers\etc\hosts', 'w', encoding=encoding) as f:
    f.writelines(lines)

Примечание: модуль chardet необходимо установить отдельно (pip install chardet).

5. Скрипт с аргументами командной строки

Пример
import argparse

parser = argparse.ArgumentParser(description='Управление файлом hosts')
parser.add_argument('--add', nargs=2, metavar=('IP', 'HOST'), help='Добавить запись')
parser.add_argument('--remove', metavar='HOST', help='Удалить все строки с указанным хостом')
parser.add_argument('--list', action='store_true', help='Вывести активные записи')
args = parser.parse_args()

# Пример реализации функций...
print('Аргументы получены')
> python hostctl.py --add 127.0.0.1 mytest
Аргументы получены

6. Блокировка множества доменов по списку

Пример
block_domains = ['ads.com', 'tracker.net', 'spam.org']
redirect_ip = '0.0.0.0'

with open(HOSTS_PATH, 'r+', encoding='utf-8') as f:
    data = f.read()
    for domain in block_domains:
        entry = f'{redirect_ip} {domain}\n'
        if entry not in data:
            f.write(entry)
# При повторном запуске дублирование не происходит благодаря проверке вхождения строки.

Редактирование файла hosts - comments

En
Python host file (python)