166 lines
6.8 KiB
Python
166 lines
6.8 KiB
Python
# Standard library imports
|
||
import json
|
||
import re
|
||
from io import BytesIO
|
||
|
||
# Third-party imports
|
||
import requests
|
||
|
||
# Local imports
|
||
from mainapp.models import Polarization, Satellite
|
||
|
||
from .models import Transponders
|
||
|
||
def search_satellite_on_page(data: dict, satellite_name: str):
|
||
for pos, value in data.get('page', {}).get('positions').items():
|
||
for name in value['satellites']:
|
||
if name['other_names'] is None:
|
||
name['other_names'] = ''
|
||
if satellite_name.lower() in name['name'].lower() or satellite_name.lower() in name['other_names'].lower():
|
||
return pos, name['id']
|
||
return '', ''
|
||
|
||
def get_footprint_data(position: str = 62) -> dict:
|
||
"""Возвращает словарь с данным по footprint для спутников на выбранной долготе"""
|
||
response = requests.get(f"https://www.satbeams.com/footprints?position={position}")
|
||
response.raise_for_status()
|
||
match = re.search(r'var data = ({.*?});', response.text, re.DOTALL)
|
||
if match:
|
||
json_str = match.group(1)
|
||
try:
|
||
data = json.loads(json_str)
|
||
return data.get("page", {}).get("footprint_data", {}).get("beams",[])
|
||
except json.JSONDecodeError as e:
|
||
print("Ошибка парсинга JSON:", e)
|
||
else:
|
||
print("Нужных данных не найдено")
|
||
return {}
|
||
|
||
|
||
|
||
def get_all_page_data(url:str = 'https://www.satbeams.com/footprints') -> dict:
|
||
"""Возвращает словарь с данными по всем спутникам на странице"""
|
||
response = requests.get(url)
|
||
response.raise_for_status()
|
||
match = re.search(r'var data = ({.*?});', response.text, re.DOTALL)
|
||
if match:
|
||
json_str = match.group(1)
|
||
try:
|
||
data = json.loads(json_str)
|
||
# Файл json на диске для достоверности
|
||
with open('data.json', 'w') as jf:
|
||
json.dump(data, jf, indent=2)
|
||
return data
|
||
except json.JSONDecodeError as e:
|
||
print("Ошибка парсинга JSON:", e)
|
||
else:
|
||
print("Нужных данных не найдено")
|
||
return {}
|
||
|
||
|
||
def get_names_footprints_for_satellite(footprint_data: dict, sat_id: str) -> list[str]:
|
||
names = []
|
||
for beam in footprint_data:
|
||
if 'ku' in beam['band'].lower() and sat_id in beam['satellite_id']:
|
||
names.append(
|
||
{
|
||
"name": beam['name'],
|
||
"fullname": beam['fullname'][8:]
|
||
}
|
||
)
|
||
return names
|
||
|
||
|
||
def get_band_names(satellite_name: str) -> list[str]:
|
||
data = get_all_page_data()
|
||
pos, sat_id = search_satellite_on_page(data, satellite_name)
|
||
footprints = get_footprint_data(pos)
|
||
names = get_names_footprints_for_satellite(footprints, sat_id)
|
||
return names
|
||
|
||
def parse_transponders_from_json(filepath: str):
|
||
with open(filepath, encoding="utf-8") as jf:
|
||
data = json.load(jf)
|
||
for sat_name, trans_zone in data["satellites"].items():
|
||
for zone, trans in trans_zone.items():
|
||
for tran in trans:
|
||
f_b, f_e = tran["freq"][0].split("-")
|
||
f = round((float(f_b) + float(f_e))/2, 3)
|
||
f_range = round(abs(float(f_e) - float(f_b)), 3)
|
||
tran_obj = Transponders.objects.create(
|
||
name=tran["name"],
|
||
frequency=f,
|
||
frequency_range=f_range,
|
||
zone_name=zone,
|
||
polarization=Polarization.objects.get(name=tran["pol"]),
|
||
sat_id=Satellite.objects.get(name__iexact=sat_name)
|
||
)
|
||
tran_obj.save()
|
||
|
||
|
||
# Third-party imports (additional)
|
||
from lxml import etree
|
||
|
||
def parse_transponders_from_xml(data_in: BytesIO):
|
||
|
||
tree = etree.parse(data_in)
|
||
ns = {
|
||
'i': 'http://www.w3.org/2001/XMLSchema-instance',
|
||
'ns': 'http://schemas.datacontract.org/2004/07/Geolocation.Domain.Utils.Repository.SatellitesSerialization.Memos',
|
||
'tr': 'http://schemas.datacontract.org/2004/07/Geolocation.Common.Extensions'
|
||
}
|
||
satellites = tree.xpath('//ns:SatelliteMemo', namespaces=ns)
|
||
for sat in satellites[:]:
|
||
name = sat.xpath('./ns:name/text()', namespaces=ns)[0]
|
||
if name == 'X' or 'DONT USE' in name:
|
||
continue
|
||
norad = sat.xpath('./ns:norad/text()', namespaces=ns)
|
||
beams = sat.xpath('.//ns:BeamMemo', namespaces=ns)
|
||
zones = {}
|
||
for zone in beams:
|
||
zone_name = zone.xpath('./ns:name/text()', namespaces=ns)[0] if zone.xpath('./ns:name/text()', namespaces=ns) else '-'
|
||
zones[zone.xpath('./ns:id/text()', namespaces=ns)[0]] = {
|
||
"name": zone_name,
|
||
"pol": zone.xpath('./ns:polarization/text()', namespaces=ns)[0],
|
||
}
|
||
transponders = sat.xpath('.//ns:TransponderMemo', namespaces=ns)
|
||
for transponder in transponders:
|
||
tr_id = transponder.xpath('./ns:downlinkBeamId/text()', namespaces=ns)[0]
|
||
downlink_start = float(transponder.xpath('./ns:downlinkFrequency/tr:start/text()', namespaces=ns)[0])
|
||
downlink_end = float(transponder.xpath('./ns:downlinkFrequency/tr:end/text()', namespaces=ns)[0])
|
||
uplink_start = float(transponder.xpath('./ns:uplinkFrequency/tr:start/text()', namespaces=ns)[0])
|
||
uplink_end = float(transponder.xpath('./ns:uplinkFrequency/tr:end/text()', namespaces=ns)[0])
|
||
tr_data = zones[tr_id]
|
||
# p = tr_data['pol'][0] if tr_data['pol'] else '-'
|
||
match tr_data['pol']:
|
||
case 'Horizontal':
|
||
pol = 'Горизонтальная'
|
||
case 'Vertical':
|
||
pol = 'Вертикальная'
|
||
case 'CircularRight':
|
||
pol = 'Правая'
|
||
case 'CircularLeft':
|
||
pol = 'Левая'
|
||
case _:
|
||
pol = '-'
|
||
tr_name = transponder.xpath('./ns:name/text()', namespaces=ns)[0]
|
||
|
||
pol_obj, _ = Polarization.objects.get_or_create(name=pol)
|
||
sat_obj, _ = Satellite.objects.get_or_create(
|
||
name=name,
|
||
defaults={
|
||
"norad": int(norad[0]) if norad else -1
|
||
})
|
||
trans_obj, _ = Transponders.objects.get_or_create(
|
||
polarization=pol_obj,
|
||
downlink=(downlink_start+downlink_end)/2/1000000,
|
||
uplink=(uplink_start+uplink_end)/2/1000000,
|
||
frequency_range=abs(downlink_end-downlink_start)/1000000,
|
||
name=tr_name,
|
||
defaults={
|
||
"zone_name": tr_data['name'],
|
||
"sat_id": sat_obj,
|
||
}
|
||
)
|
||
trans_obj.save()
|