Не получается написать цикл для записи в JSON

помогите, пожалуйста. Есть код, который проверяет доступность домена и, если он доступен, сканирует открытые порты и записывает их с названиями служб в JSON файл. У меня получилось, что идёт запись только последней пары:

[
  {
    "hostname": "www.youtube.com",
    "ports": [
      {
        "443": "HTTPS"
      }
    ]
  }
]

Но нужно, чтобы были все порты вот так

[
  {
    "hostname": "www.youtube.com",
    "ports": [
      {
        "80": "http"
        "443": "HTTPS"
      }
    ]
  }
]

Я не могу понять, как это можно сделать :( Заранее спасибо!

import json
import sys
import socket
import urllib.request
from urllib.error import URLError

ports = [20, 21, 22, 23, 25, 43, 53, 80,
         115, 123, 143, 161, 179, 443, 445,
         514, 515, 993, 995, 1080, 1194,
         1433, 1723, 3128, 3268, 3306, 3389,
         5432, 5060, 5900, 8080, 10000]
   
services = [
"FTP-DATA", "FTP", "SSH", "Telnet", "SMTP", "WHOIS", "DNS", "http", "SFTP", "NTP", "IMAP", "SNMP", "BGP", "HTTPS",
"MICROSOFT-DS", "SYSLOG", "PRINTER", "IMAPS", "POP3S", "SOCKS", "OpenVPN", "SQL Server", "PPTP", "HTTP", "LDAP",
"MySQL", "RDP", "PostgreSQL", "VNC", "Tomcat", "Webmin"]

hostName = 'www.youtube.com'

try:
    response = urllib.request.urlopen(f'https://{hostName}')
except URLError:
    response = None

if response is not None:
    ip = socket.gethostbyname(hostName)
    try:
        i = 0
        for i in range(len(ports)):
            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            socket.setdefaulttimeout(0.1)
            result = s.connect_ex((ip, ports[i]))
            if result == 0:
                json_data = [{
                    "hostname": f"{hostName}",
                    "ports": [{
                        f"{ports[i]}": f"{services[i]}"
                    }]
                }]
                 with open("hosts.json", "w") as file:
                file.write(json.dumps(json_data, indent=2, ensure_ascii=False))
            s.close()
    except socket.error:
        print("Host not responding")
        sys.exit()
else:
    sys.exit()

Ответы (1 шт):

Автор решения: Алексей Р

Нужно вынести инициализацию json_data до начала цикла, а в цикле добавлять значения в словарь json_data[0]["ports"][0][ports[i]] = services[i]. Запись в файл производить после окончания цикла.

import json
import sys
import socket
import urllib.request
from urllib.error import URLError

ports = [20, 21, 22, 23, 25, 43, 53, 80,
         115, 123, 143, 161, 179, 443, 445,
         514, 515, 993, 995, 1080, 1194,
         1433, 1723, 3128, 3268, 3306, 3389,
         5432, 5060, 5900, 8080, 10000]

services = [
    "FTP-DATA", "FTP", "SSH", "Telnet", "SMTP", "WHOIS", "DNS", "http", "SFTP", "NTP", "IMAP", "SNMP", "BGP", "HTTPS",
    "MICROSOFT-DS", "SYSLOG", "PRINTER", "IMAPS", "POP3S", "SOCKS", "OpenVPN", "SQL Server", "PPTP", "HTTP", "LDAP",
    "MySQL", "RDP", "PostgreSQL", "VNC", "Tomcat", "Webmin"]

hostName = 'www.youtube.com'

try:
    response = urllib.request.urlopen(f'https://{hostName}')
except URLError:
    response = None

if response is not None:
    ip = socket.gethostbyname(hostName)
    json_data = [{
        "hostname": f"{hostName}",
        "ports": [{}]
    }]
    try:
        i, s = 0, None
        for i in range(len(ports)):
            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            socket.setdefaulttimeout(0.1)
            result = s.connect_ex((ip, ports[i]))
            if result == 0:
                json_data[0]["ports"][0][ports[i]] = services[i]
        with open("hosts.json", "w") as file:
            file.write(json.dumps(json_data, indent=2, ensure_ascii=False))
        if s is not None:
            s.close()
    except socket.error:
        print("Host not responding")
        sys.exit()
else:
    sys.exit()
[
  {
    "hostname": "www.youtube.com",
    "ports": [
      {
        "80": "http",
        "443": "HTTPS"
      }
    ]
  }
]
→ Ссылка