#!/usr/bin/python """ Script to retrieve all Openstreetmap items matching a query and save them as GPX Waypoints to a given output file in GPX format. """ __author__ = "fordprefect" __date__ = "2020-03-26" __version__ = "0.1" import gpxpy import requests import os import sys assert sys.version_info >= (3, 6), "At least Python 3.8 required due to fStrings. Replace all f\"…\" and comment this line to enable running in lower versions (but really, you should just update your Python version…)." class OSMSearch(): def __init__(self, args): """ TODO: write docstring """ self.url = args.pop("url") self.maxsearchnums = args.pop("maxsearchnums") self.save_to_file = True if args["output"] == "disk" else False if self.save_to_file: self.gpxfilename = args.pop("outputfilename") self.print_xml = True if args["output"] == "print" else False self.use_boundingbox = args.pop("use_boundingbox") if self.use_boundingbox: assert isinstance(list, args["boundingbox"]) assert len(args["boundingbox"]) == 4 else: args.pop("boundingbox") self.searchargs = args self.initialize_gpx_file() self.search() if self.save_to_file: self.save_to_disk() if self.print_xml: self.print_to_stdout() def initialize_gpx_file(self): if not self.save_to_file: self.gpxfile = gpxpy.gpx.GPX() return if os.path.isfile(self.gpxfilename): # open file and parse #if verbosity > 0: print(f"found file, extending") self.gpxfile = gpxpy.parse(open(gpxfilename, "r")) else: #if verbosity > 0: print("creating new file") self.gpxfile = gpxpy.gpx.GPX() def get_argstring(self): argstrings = [] if self.use_boundingbox: argstring.append(",".join(list(map(str, self.searchargs["boundingbox"])))) for arg in self.searchargs: argstrings.append(f"{arg}={self.searchargs[arg]}") return "?"+"&".join(argstrings) def search(self): """ """ for i in range(self.maxsearchnums): # fetch request r = requests.get(self.url + self.get_argstring()) if r.status_code != 200: #if verbosity > 0: print(f"Query gone wrong: HTTP returned {r.status_code}") exit(1) # parse reply reply = r.json() assert isinstance(reply, list), "Unexpected type of reply: " + type(reply) if len(reply) == 0: if verbosity > 0: print(f"found {len(ignore_ids)} results in {i-1} iterations, finishing") break for point in reply: self.searchargs["ignore_ids"].append(point["place_id"]) self.gpxfile.waypoints.append(gpxpy.gpx.GPXWaypoint(latitude=point["lat"], longitude=point["lon"], name=point["display_name"])) def save_to_disk(self): with open(self.gpxfilename, "w") as f: f.write(self.gpxfile.to_xml()) #if verbosity > 0: print(f"GPX file written to {gpxfilename}") def print_to_stdout(self): print(self.gpxfile.to_xml()) default_args = { "q": "Camping", "format": "json", "limit": 50, "use_boundingbox": False, "boundingbox": [], "outputfilename": "test.gpx", "ignore_ids": [], "maxsearchnums": 10, "url": "https://nominatim.openstreetmap.org/search/", "output": "print", } if __name__ == "__main__": # cli invocation goes here # TODO: take user arguments and bring together with sensible defaults above OSMSearch(default_args)