diff options
Diffstat (limited to 'src/rn.py')
| -rw-r--r-- | src/rn.py | 149 |
1 files changed, 85 insertions, 64 deletions
@@ -1,81 +1,102 @@ -import requests +import argparse +import json import re +import xml.etree.ElementTree as ET + +import requests + +from kml_utils import add_placemark, add_polygon, new_document, write_kml +LIST_URL = "https://reserves-naturelles.org/reserves-naturelles/" -def get_coordinates_from_url(url): + +def get_coordinates_from_url(url: str) -> list[tuple[float, float]] | None: + """Fetch a reserve page and extract its outer polygon ring. + + Args: + url (str): URL of the reserve page. + Returns: + list[tuple[float, float]] | None: (longitude, latitude) points, or None if no + coordinates could be found on the page. + """ response = requests.get(url) - regex = r"\[\[-?\d+\.\d+,-?\d+\.\d+\](?:,\[-?\d+\.\d+,-?\d+\.\d+\])+\]" - matche = re.search(regex, response.text) - if not matche: + match = re.search( + r"\[\[-?\d+\.\d+,-?\d+\.\d+\](?:,\[-?\d+\.\d+,-?\d+\.\d+\])+\]", response.text + ) + if not match: return None - coordinates = eval(matche.group(0)) - return coordinates + return [tuple(point) for point in json.loads(match.group(0))] + + +def get_reserves(list_url: str = LIST_URL) -> list[dict]: + """Fetch the reserves list page and extract each reserve's name and URL. + + Args: + list_url (str, optional): URL of the reserves list page. Defaults to LIST_URL. + Returns: + list[dict]: One {"full_name", "name", "url"} entry per reserve found on the page. + """ + response = requests.get(list_url) + items = re.findall(r"<li class=\"reserve\"[\s\S]*?</li>", response.text) + + reserves = [] + for item in items: + full_name_match = re.search(r"title=\"([^\"]+)\"", item) + name_match = re.search(r"class=\"rsv_nom\">([^<]+)<", item) + url_match = re.search(r"href=\"([^\"]+)\"", item) + + if not full_name_match or not name_match or not url_match: + print(f"Skipping incomplete list entry: {item}") + continue + + reserves.append( + { + "full_name": full_name_match.group(1), + "name": name_match.group(1), + "url": url_match.group(1), + } + ) + + return reserves -response = requests.get("https://reserves-naturelles.org/reserves-naturelles/") -regex = r"<li class=\"reserve\"[\s\S]*?</li>" -matches = re.findall(regex, response.text) +def scrape_reserves(list_url: str = LIST_URL) -> ET.Element: + """Scrape reserves-naturelles.org and build a KML tree with one Placemark per reserve. -kml_file = open("reserves_naturelles.kml", "w", encoding="utf-8") -kml_file.write("""<?xml version="1.0" encoding="UTF-8"?> -<kml xmlns="http://www.opengis.net/kml/2.2"> - <Document> - <name>RN</name> -""") + Args: + list_url (str, optional): URL of the reserves list page. Defaults to LIST_URL. + Returns: + ET.Element: The root <kml> element. + """ + root, document = new_document("RN") + reserves = get_reserves(list_url) + for i, reserve in enumerate(reserves): + coordinates = get_coordinates_from_url(reserve["url"]) + if not coordinates: + print(f"No coordinates found for URL: {reserve['url']}") + continue -for i, match in enumerate(matches): + placemark = add_placemark( + document, + name=reserve["name"], + description=f"{reserve['full_name']}<br/>{reserve['url']}", + ) + add_polygon(placemark, coordinates) - regex = r"title=\"([^\"]+)\"" - full_name = re.search(regex, match) - if not full_name: - print(f"Full name not found in the match: {match}") - continue - full_name = full_name.group(1) + print(f"Processed: {reserve['name']} ({i + 1:3d}/{len(reserves)})") - regex = r"class=\"rsv_nom\">([^<]+)<" - name = re.search(regex, match) - if not name: - print(f"Name not found in the match: {match}") - continue - name = name.group(1) + return root - regex = r"href=\"([^\"]+)\"" - url = re.search(regex, match) - if not url: - print(f"URL not found in the match: {match}") - continue - url = url.group(1) - coordinates = get_coordinates_from_url(url) - if not coordinates: - print(f"Coordinates not found for URL: {url}") - continue +def main(): + parser = argparse.ArgumentParser(description="Scrape reserves-naturelles.org and export reserves to KML") + parser.add_argument("-o", "--output", default="reserves_naturelles.kml", help="Path to the output KML file") + args = parser.parse_args() - kml_file.write(f""" - <Placemark> - <name>{name}</name> - <description> - {full_name}<br/>{url} - </description> - <Polygon> - <outerBoundaryIs> - <LinearRing> - <coordinates> -""") - for coordinate in coordinates: - kml_file.write(f" {coordinate[0]},{coordinate[1]},0\n") - kml_file.write(""" - </coordinates> - </LinearRing> - </outerBoundaryIs> - </Polygon> - </Placemark> -""") - - print(f"Processed: {name} ({i+1: 3d}/{len(matches)})") + root = scrape_reserves() + write_kml(root, args.output) -kml_file.write(""" - </Document> -</kml>""") +if __name__ == "__main__": + main() |
