Added web scraping, own thread, etc.

This commit is contained in:
Marat Fayzullin 2023-07-09 15:51:44 -04:00
parent 102bc3c27a
commit 46bcc7f558
2 changed files with 209 additions and 8 deletions

View File

@ -154,8 +154,8 @@ $(function(){
marker.gain = update.location.gain;
marker.device = update.location.device;
marker.aircraft = update.location.aircraft;
marker.receiver = update.location.receiver;
marker.antenna = update.location.antenna;
marker.users = update.location.users;
marker.directivity = update.location.directivity;
if (expectedCallsign && expectedCallsign == update.callsign) {
@ -524,20 +524,20 @@ $(function(){
}
if (marker.device) {
detailsString += makeListItem('Device',
marker.device.device + " by " +
marker.device.manufacturer
detailsString += makeListItem('Device', marker.device.manufacturer?
marker.device.device + " by " + marker.device.manufacturer
: marker.device
);
}
//if (marker.receiver) {
// detailsString += makeListItem('Receiver', marker.receiver);
//}
//if (marker.antenna) {
// detailsString += makeListItem('Antenna', marker.antenna);
//}
//if (marker.users) {
// detailsString += makeListItem('Users', marker.users);
//}
if (marker.height) {
detailsString += makeListItem('Height', marker.height.toFixed(0) + ' m');
}

201
owrx/receiverdb.py Normal file
View File

@ -0,0 +1,201 @@
from owrx.config.core import CoreConfig
from owrx.map import Map, LatLngLocation
from owrx.aprs import getSymbolData
from json import JSONEncoder
import urllib
import threading
import logging
import json
import re
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
class ReceiverJSONEncoder(JSONEncoder):
def default(self, obj):
return obj.toJSON()
class ReceiverLocation(LatLngLocation):
def __init__(self, lat: float, lon: float, attrs):
self.attrs = attrs
super().__init__(lat, lon)
def getId(self):
return re.sub(r"^.*://(.*)[/:].*$", r"\1", self.attrs["url"])
def __dict__(self):
return self.attrs
def toJSON(self):
return self.attrs
class ReceiverDatabase(object):
sharedInstance = None
creationLock = threading.Lock()
@staticmethod
def getSharedInstance():
with ReceiverDatabase.creationLock:
if ReceiverDatabase.sharedInstance is None:
ReceiverDatabase.sharedInstance = ReceiverDatabase()
return ReceiverDatabase.sharedInstance
@staticmethod
def _getReceiversFile():
coreConfig = CoreConfig()
return "{data_directory}/receivers.json".format(data_directory=coreConfig.get_temporary_directory())
def __init__(self):
self.receivers = {}
self.thread = None
def toJSON(self):
return self.receivers
def refresh(self):
if self.thread is None:
self.thread = threading.Thread(target=self._refreshThread)
self.thread.start()
def _refreshThread(self):
logger.debug("Starting receiver database refresh...")
#self._loadReceivers()
# Scrape websites for receivers
self.receivers = {}
self.receivers.update(self.scrapeKiwiSDR())
self.receivers.update(self.scrapeWebSDR())
# Save parsed data into a file
file = ReceiverDatabase._getReceiversFile()
logger.debug("Saving {0} receivers to '{1}'...".format(len(self.receivers), file))
try:
with open(file, "w") as f:
json.dump(self, f, cls=ReceiverJSONEncoder, indent=2)
except Exception as e:
logger.debug("Exception: {0}".format(e))
# Update map with receivers
logger.debug("Updating map...")
self._updateMap()
# Done
logger.debug("Done refreshing receiver database.")
self.thread = None
def _loadReceivers(self, fileName: str = None):
# Get filename
if fileName is None:
fileName = self._getReceiversFile()
# Load receivers list from JSON file
try:
with open(fileName, "r") as f:
content = f.read()
if content:
db = json.loads(content)
except Exception as e:
logger.debug("Exception: {0}".format(e))
return
# Clear current database
self.receivers = []
# Fill database with the read data
for entry in db:
if "gps" in entry:
m = re.match(r"\(\s*(-?\d+\.\d+)\s*,\s*(-?\d+\.\d+)\s*\)", entry["gps"])
if m:
self.receivers += [
ReceiverLocation(float(m.group(1)), float(m.group(2)), entry)
]
def _updateMap(self):
for r in self.receivers.values():
Map.getSharedInstance().updateLocation(r.getId(), r, "Internet")
def scrapeWebSDR(self, url: str = "http://websdr.ewi.utwente.nl/~~websdrlistk?v=1&fmt=2&chseq=0"):
result = {}
try:
data = urllib.request.urlopen(url).read().decode('utf-8')
data = json.loads(re.sub("^\s*//.*", "", data, flags=re.MULTILINE))
for entry in data:
if "lat" in entry and "lon" in entry and "url" in entry:
# Save accumulated attributes, use hostname as key
lat = entry["lat"]
lon = entry["lon"]
rl = ReceiverLocation(lat, lon, {
"type" : "latlon",
"lat" : lat,
"lon" : lon,
"comment" : entry["desc"],
"url" : entry["url"],
#"users" : int(entry["users"]),
"device" : "WebSDR",
"symbol" : getSymbolData('/', '\\')
})
result[rl.getId()] = rl
except Exception as e:
logger.debug("scrapeWebSDR() exception: {0}".format(e))
# Done
return result
def scrapeKiwiSDR(self, url: str = "http://kiwisdr.com/public/"):
result = {}
try:
patternAttr = re.compile(r".*<!--\s+(\S+)=(.*)\s+-->.*")
patternUrl = re.compile(r".*<a\s+href=['\"](\S+?)['\"].*>.*</a>.*")
patternGps = re.compile(r"\(\s*(-?\d+\.\d+)\s*,\s*(-?\d+\.\d+)\s*\)")
entry = {}
for line in urllib.request.urlopen(url).readlines():
# Convert read bytes to a string
line = line.decode('utf-8')
# When we encounter a URL...
m = patternUrl.match(line)
if m is not None:
# Add URL attribute
entry["url"] = m.group(1)
# Must have "gps" attribut with latitude / longitude
if "gps" in entry and "url" in entry:
m = patternGps.match(entry["gps"])
if m is not None:
# Save accumulated attributes, use hostname as key
lat = float(m.group(1))
lon = float(m.group(2))
rl = ReceiverLocation(lat, lon, {
"type" : "latlon",
"lat" : lat,
"lon" : lon,
"comment" : entry["name"],
"url" : entry["url"],
#"users" : int(entry["users"]),
#"maxusers": int(entry["users_max"]),
"loc" : entry["loc"],
"altitude": int(entry["asl"]),
"antenna" : entry["antenna"],
"device" : entry["sw_version"],
"symbol" : getSymbolData('/', '/')
})
result[rl.getId()] = rl
# Clear current entry
entry = {}
else:
# Save all parsed attributes in the current entry
m = patternAttr.match(line)
if m is not None:
# Save attribute in the current entry
entry[m.group(1).lower()] = m.group(2)
except Exception as e:
logger.debug("scrapeKiwiSDR() exception: {0}".format(e))
# Done
return result