diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 409bb3a4aedcb6d25bf191e02328edaec4bbde42..b93399f4b8b377b8b75d4f3ef3214c3a6ee0f3e3 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -45,6 +45,34 @@ install: - lib/ - pyvenv.cfg +test_pref06: + stage: test + image: registry.git.laquadrature.net/bastien/raaspotter/base:latest + tags: + - unprivileged + needs: [install] + script: + - curl --silent --location --output artifacts.zip "${CI_SERVER_PROTOCOL}://${CI_SERVER_HOST}:${CI_SERVER_PORT}/api/v4/projects/${CI_PROJECT_ID}/jobs/artifacts/${CI_COMMIT_BRANCH}/download?job=${CI_JOB_NAME}&job_token=${CI_JOB_TOKEN}" || true + - unzip -q artifacts.zip data/pref06/* || true + - rm artifacts.zip || true + - source bin/activate + - /etc/init.d/tor start + - python ./pref06.py + retry: 2 + only: + - main + cache: + key: $CI_COMMIT_REF_SLUG + paths: + - bin/ + - lib/ + - pyvenv.cfg + artifacts: + paths: + - data/pref06/*.txt + - output.log + expire_in: 1 hour + test_pref13: stage: test image: registry.git.laquadrature.net/bastien/raaspotter/base:latest diff --git a/Makefile b/Makefile index 1f17ffcb77454f02635e05c777b081120a4556e4..5e48a15fb4c89572a3feb25d8bdffe3f820ecdf7 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,8 @@ make: pref13 pref35 ppparis pref13: python pref13.py +pref06: + python pref06.py pref35: python pref35.py ppparis: diff --git a/RAAspotter_pref06.py b/RAAspotter_pref06.py new file mode 100644 index 0000000000000000000000000000000000000000..f3f58330003eb4a296e2b86fc425c0550fd58ca3 --- /dev/null +++ b/RAAspotter_pref06.py @@ -0,0 +1,95 @@ +import os, sys +import datetime + +from bs4 import BeautifulSoup +from urllib.parse import unquote + +from RAAspotter import RAAspotter + +class RAAspotter_pref06(RAAspotter): + + # Config + __HOST = 'https://www.alpes-maritimes.gouv.fr' + __RAA_PAGE = {'2024': + [f'{__HOST}/Publications/Recueil-des-actes-administratifs-RAA/Annee-2024/Recueils-mensuels', + f'{__HOST}/Publications/Recueil-des-actes-administratifs-RAA/Annee-2024/Recueils-speciaux', + f'{__HOST}/Publications/Recueil-des-actes-administratifs-RAA/Annee-2024/Recueils-specifiques'], + '2023': + [f'{__HOST}/Publications/Recueil-des-actes-administratifs-RAA/Annee-2023/Recueils-mensuels', + f'{__HOST}/Publications/Recueil-des-actes-administratifs-RAA/Annee-2023/Recueils-speciaux', + f'{__HOST}/Publications/Recueil-des-actes-administratifs-RAA/Annee-2023/Recueils-specifiques'], + '2022': + [f'{__HOST}/Publications/Recueil-des-actes-administratifs-RAA/Annee-2022/Recueils-mensuels', + f'{__HOST}/Publications/Recueil-des-actes-administratifs-RAA/Annee-2022/Recueils-speciaux', + f'{__HOST}/Publications/Recueil-des-actes-administratifs-RAA/Annee-2022/Recueils-specifiques'], + '2021': + [f'{__HOST}/Publications/Recueil-des-actes-administratifs-RAA/Annee-2021/Recueils-mensuels', + f'{__HOST}/Publications/Recueil-des-actes-administratifs-RAA/Annee-2021/Recueils-speciaux', + f'{__HOST}/Publications/Recueil-des-actes-administratifs-RAA/Annee-2021/Recueils-specifiques'], + '2020': + [f'{__HOST}/Publications/Recueil-des-actes-administratifs-RAA/Annee-2020/Recueils-mensuels', + f'{__HOST}/Publications/Recueil-des-actes-administratifs-RAA/Annee-2020/Recueils-speciaux', + f'{__HOST}/Publications/Recueil-des-actes-administratifs-RAA/Annee-2020/Recueils-specifiques'], + '2019': + [f'{__HOST}/Publications/Recueil-des-actes-administratifs-RAA/Annee-2019/Recueils-mensuels', + f'{__HOST}/Publications/Recueil-des-actes-administratifs-RAA/Annee-2019/Recueils-speciaux', + f'{__HOST}/Publications/Recueil-des-actes-administratifs-RAA/Annee-2019/Recueils-specifiques']} + __USER_AGENT = 'Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0' + + def __init__(self, data_dir): + super().__init__(data_dir, self.__USER_AGENT) + self.enable_tor(20) + + def get_raa(self, keywords): + self.print_output('RAAspotter_pref06') + self.print_output(f'Termes recherchés: {keywords}') + self.print_output('') + + pages_to_parse = [] + if self.not_before.year <= 2024: + for page in self.__RAA_PAGE['2024']: + pages_to_parse.append(page) + if self.not_before.year <= 2023: + for page in self.__RAA_PAGE['2023']: + pages_to_parse.append(page) + if self.not_before.year <= 2022: + for page in self.__RAA_PAGE['2022']: + pages_to_parse.append(page) + if self.not_before.year <= 2021: + for page in self.__RAA_PAGE['2021']: + pages_to_parse.append(page) + if self.not_before.year <= 2020: + for page in self.__RAA_PAGE['2020']: + pages_to_parse.append(page) + if self.not_before.year <= 2019: + for page in self.__RAA_PAGE['2019']: + pages_to_parse.append(page) + + elements = self.get_raa_with_pager(pages_to_parse, ".fr-pagination__link.fr-pagination__link--next", self.__HOST) + self.tor_get_new_id() + self.set_sleep_time(10) + self.parse_raa(elements, keywords.split(',')) + self.mailer() + + def get_raa_elements(self, page_content): + elements = [] + # On charge le parser + soup = BeautifulSoup(page_content, 'html.parser') + + # Pour chaque élément fr-card__content, on cherche sa balise a, et si c'est un PDF on le parse + cards = soup.find_all('div', class_='fr-card__content') + for card in cards: + a = card.find('a') + if a['href'].endswith('.pdf'): + if a['href'].startswith('/'): + url = f"{self.__HOST}{a['href']}" + else: + url = a['href'] + + name = a.get_text().strip() + date = datetime.datetime.strptime(card.find('p', class_='fr-card__detail').get_text().replace('Publié le ', '').strip(), '%d/%m/%Y') + filename = unquote(url.split('/')[-1]) + + raa = RAAspotter.RAA(url, date, name, filename) + elements.append(raa) + return elements diff --git a/README.md b/README.md index 529793b372f1f25a09d0b802451153c34579b316..dd22f661bed27c7ddf0d1cf3c0fac1e4260874c1 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,7 @@ Il est possible de ne lancer l'analyse que pour une seule administration, en lan ## Administrations supportées +- Préfecture des Alpes-Maritimes (`pref06.py`) - Préfecture des Bouches-du-Rhône (`pref13.py`) - Préfecture d'Ille-et-Vilaine (`pref35.py`) - Préfecture de police de Paris (`ppparis.py`) diff --git a/pref06.py b/pref06.py new file mode 100755 index 0000000000000000000000000000000000000000..3ed803d3283cac22d7caf53ccd586216f4eef753 --- /dev/null +++ b/pref06.py @@ -0,0 +1,105 @@ +import os +import argparse +import logging +import datetime + +from RAAspotter import RAAspotter +from RAAspotter_pref06 import RAAspotter_pref06 + +# Config +__KEYWORDS = os.getenv('KEYWORDS') or 'vidéoprotection,caméras,captation,aéronef' +__DATA_DIR = os.path.dirname(os.path.abspath(__file__))+'/data/pref06/' +__SMTP_HOSTNAME = os.getenv('SMTP_HOSTNAME') or 'localhost' +__SMTP_USERNAME = os.getenv('SMTP_USERNAME') or '' +__SMTP_PASSWORD = os.getenv('SMTP_PASSWORD') or '' +__EMAIL_FROM = os.getenv('EMAIL_FROM') +__EMAIL_TO = os.getenv('EMAIL_TO') +if os.getenv('SMTP_PORT'): + __SMTP_PORT = int(os.getenv('SMTP_PORT')) +else: + __SMTP_PORT = 587 +if os.getenv('SMTP_STARTTLS'): + __SMTP_STARTTLS = True +else: + __SMTP_STARTTLS = False +if os.getenv('SMTP_SSL'): + __SMTP_SSL = True +else: + __SMTP_SSL = False +if os.getenv('NOT_BEFORE'): + __NOT_BEFORE = datetime.datetime.strptime(os.getenv('NOT_BEFORE'), '%Y-%m-%d') +else: + __NOT_BEFORE = datetime.datetime(1970, 1, 1) +__MASTODON_ACCESS_TOKEN = os.getenv('MASTODON_ACCESS_TOKEN') +__MASTODON_INSTANCE = os.getenv('MASTODON_INSTANCE') + +# Début du script +parser = argparse.ArgumentParser(prog='pref06.py', description='Télécharge les RAA de la préfecture d\'Ille-et-Vilaine et recherche des mots-clés') +parser.add_argument('-k', '--keywords', action='store', help='liste des termes recherchés, séparés par une virgule (par défaut : vidéoprotection,caméras,captation,aéronef)') +parser.add_argument('--not-before', action='store', help='n\'analyse pas les RAA datant d\'avant la date indiquée, au format YYYY-MM-DD (par défaut : analyse tous les RAA)') +parser.add_argument('--smtp-hostname', action='store', help='nom d\'hôte SMTP (par défaut : localhost)') +parser.add_argument('--smtp-username', action='store', help='nom d\'utilisateur SMTP (par défaut : vide)') +parser.add_argument('--smtp-password', action='store', help='mot de passe SMTP (par défaut : vide)') +parser.add_argument('--smtp-port', action='store', help='port SMTP (par défaut : 587)') +parser.add_argument('--smtp-starttls', action='store_true', help='connexion SMTP avec STARTTLS') +parser.add_argument('--smtp-ssl', action='store_true', help='connexion SMTP avec SSL') +parser.add_argument('-f', '--email-from', action='store', help='adresse de courrier électronique expéditrice des notifications') +parser.add_argument('-t', '--email-to', action='store', help='adresses de courrier électronique destinataires des notifications (séparées par une virgule)') +parser.add_argument('--mastodon-access-token', action='store', help='jeton d\'accès pour publier sur Mastodon (par défaut : vide)') +parser.add_argument('--mastodon-instance', action='store', help='URL de l\'instance (doit inclure "http://" ou "https://" ; par défaut : vide)') +parser.add_argument('-v', action='store_true', help='relève le niveau de verbosité à INFO') +parser.add_argument('-vv', action='store_true', help='relève le niveau de verbosité à DEBUG') +args = parser.parse_args() + +if args.v or os.getenv('VERBOSE'): + logging.basicConfig(level=logging.INFO) + +if args.vv or os.getenv('VVERBOSE'): + logging.basicConfig(level=logging.DEBUG) + +if args.keywords: + __KEYWORDS = args.keywords + +if args.not_before: + __NOT_BEFORE = datetime.datetime.strptime(args.not_before, '%Y-%m-%d') + +if args.smtp_hostname: + __SMTP_HOSTNAME = args.smtp_hostname + +if args.smtp_username: + __SMTP_USERNAME = args.smtp_username + +if args.smtp_password: + __SMTP_PASSWORD = args.smtp_password + +if args.smtp_port: + __SMTP_PORT = int(args.smtp_port) + +if args.smtp_starttls: + __SMTP_STARTTLS = True + +if args.smtp_ssl: + __SMTP_SSL = True + +if args.email_from: + __EMAIL_FROM = args.email_from + +if args.email_to: + __EMAIL_TO = args.email_to + +if args.mastodon_access_token: + __MASTODON_ACCESS_TOKEN = args.mastodon_access_token + +if args.mastodon_instance: + __MASTODON_INSTANCE = args.mastodon_instance + +# On crée le dossier de téléchargement +os.makedirs(__DATA_DIR, exist_ok=True) + +raa_spotter = RAAspotter_pref06(__DATA_DIR) +raa_spotter.not_before = __NOT_BEFORE +raa_spotter.configure_mailer(__SMTP_HOSTNAME, __SMTP_USERNAME, __SMTP_PASSWORD, __SMTP_PORT, + __SMTP_STARTTLS, __SMTP_SSL, __EMAIL_FROM, __EMAIL_TO, + '[RAAspotter] [Préfecture des Alpes-Maritimes] Nouveaux éléments trouvés') +raa_spotter.configure_mastodon(__MASTODON_ACCESS_TOKEN, __MASTODON_INSTANCE, '[Préfecture des Alpes-Maritimes]', '#pref06') +raa_spotter.get_raa(__KEYWORDS)