Skip to content
Extraits de code Groupes Projets

Comparer les révisions

Les modifications sont affichées comme si la révision source était fusionnée avec la révision cible. En savoir plus sur la comparaison des révisions.

Source

Sélectionner le projet cible
No results found

Cible

Sélectionner le projet cible
  • la-quadrature-du-net/Attrap
  • foggyfrog/Attrap
  • skhwiz/Attrap
  • precambrien/Attrap
  • ketsapiwiq/Attrap
  • Joseki/Attrap
  • kr1p/attrap-pref-12
  • kr1p/attrap-pref-46
  • kr1p/attrap-pi
  • Guinness/Attrap
  • astroidgritty/attrap-pref-84
  • davinov/Attrap
  • maettellite/attrap-pref-01
  • m242/Attrap
  • multi/Attrap
  • mverdeil/Attrap
  • olpo/Attrap
17 résultats
Afficher les modifications
......@@ -14,14 +14,7 @@ class Attrap_pref80(Attrap):
# Config
hostname = 'https://www.somme.gouv.fr'
raa_page = {
'2024': f'{hostname}/Publications/Recueil-des-actes-administratifs-du-departement-de-la-Somme/Annee-2024',
'2023': f'{hostname}/Publications/Recueil-des-actes-administratifs-du-departement-de-la-Somme/Annee-2023',
'2022': f'{hostname}/Publications/Recueil-des-actes-administratifs-du-departement-de-la-Somme/Annee-2022',
'2021': f'{hostname}/Publications/Recueil-des-actes-administratifs-du-departement-de-la-Somme/Annee-2021',
'2020': f'{hostname}/Publications/Recueil-des-actes-administratifs-du-departement-de-la-Somme/Annee-2020',
'2019': f'{hostname}/Publications/Recueil-des-actes-administratifs-du-departement-de-la-Somme/Annee-2019'
}
raa_page = f'{hostname}/Publications/Recueil-des-actes-administratifs-du-departement-de-la-Somme'
user_agent = 'Mozilla/5.0 (Windows NT 10.0; rv:109.0) Gecko/20100101 Firefox/115.0'
full_name = 'Préfecture de la Somme'
short_code = 'pref80'
......@@ -33,18 +26,19 @@ class Attrap_pref80(Attrap):
def get_raa(self, keywords):
year_pages_to_parse = []
if self.not_before.year <= 2024:
year_pages_to_parse.append(self.raa_page['2024'])
if self.not_before.year <= 2023:
year_pages_to_parse.append(self.raa_page['2023'])
if self.not_before.year <= 2022:
year_pages_to_parse.append(self.raa_page['2022'])
if self.not_before.year <= 2021:
year_pages_to_parse.append(self.raa_page['2021'])
if self.not_before.year <= 2020:
year_pages_to_parse.append(self.raa_page['2020'])
if self.not_before.year <= 2019:
year_pages_to_parse.append(self.raa_page['2019'])
# On détermine quelles pages d'année parser
page_content = self.get_page(self.raa_page, 'get').content
year_pages = self.get_sub_pages(
page_content,
'div.fr-card.fr-card--sm.fr-card--grey.fr-enlarge-link div.fr-card__body div.fr-card__content h2.fr-card__title a',
self.hostname,
False
)
for year_page in year_pages:
year_date = Attrap.guess_date(year_page['name'].strip(), '.*([0-9]{4})').replace(day=1, month=1)
if year_date.year >= self.not_before.year:
year_pages_to_parse.append(year_page['url'])
# Pour chaque page Année, on récupère la liste des RAA
elements = []
......@@ -63,7 +57,7 @@ class Attrap_pref80(Attrap):
# Pour chaque balise a, on regarde si c'est un PDF, et si oui on le
# parse
for a in soup.select('div.fr-text--lead.fr-my-3w p a.fr-link'):
for a in soup.select('div.fr-text--lead p a.fr-link'):
if a.get('href') and a['href'].endswith('.pdf'):
if a['href'].startswith('/'):
url = f"{self.hostname}{a['href']}"
......
......@@ -19,7 +19,7 @@ class Attrap_pref81(Attrap):
def __init__(self, data_dir):
super().__init__(data_dir, self.user_agent)
self.set_sleep_time(30)
self.set_sleep_time(5)
def get_raa(self, keywords):
year_pages_to_parse = []
......
......@@ -11,14 +11,7 @@ class Attrap_pref83(Attrap):
# Config
hostname = 'https://www.var.gouv.fr'
raa_page = {
'2024': f'{hostname}/Publications/RAA-Recueil-des-actes-administratifs/Recueil-des-actes-administratifs-2024',
'2023': f'{hostname}/Publications/RAA-Recueil-des-actes-administratifs/Recueil-des-actes-administratifs-2023',
'2022': f'{hostname}/Publications/RAA-Recueil-des-actes-administratifs/Recueil-des-actes-administratifs-2022',
'2021': f'{hostname}/Publications/RAA-Recueil-des-actes-administratifs/Recueil-des-actes-administratifs-2021',
'2020': f'{hostname}/Publications/RAA-Recueil-des-actes-administratifs/Recueil-des-actes-administratifs-2020',
'2019': f'{hostname}/Publications/RAA-Recueil-des-actes-administratifs/Recueil-des-actes-administratifs-2019'
}
raa_page = f'{hostname}/Publications/Recueil-des-actes-administratifs'
user_agent = 'Mozilla/5.0 (Windows NT 10.0; rv:109.0) Gecko/20100101 Firefox/115.0'
full_name = 'Préfecture du Var'
short_code = 'pref83'
......@@ -29,38 +22,39 @@ class Attrap_pref83(Attrap):
self.set_sleep_time(30)
def get_raa(self, keywords):
year_pages_to_parse = []
# On détermine quelles pages d'année parser
page_content = self.get_page(self.raa_page, 'get').content
for year_page in self.get_sub_pages(
page_content,
'div.fr-card__body div.fr-card__content h2.fr-card__title a',
self.hostname,
False
):
year = Attrap.guess_date(year_page['name'].strip(), 'Recueil des actes administratifs ([0-9]{4})').year
if year < 9999 and year >= self.not_before.year:
year_pages_to_parse.append(year_page['url'])
pages_to_parse = []
if self.not_before.year <= 2024:
pages_to_parse.append(self.raa_page['2024'])
if self.not_before.year <= 2023:
pages_to_parse.append(self.raa_page['2023'])
if self.not_before.year <= 2022:
pages_to_parse.append(self.raa_page['2022'])
if self.not_before.year <= 2021:
pages_to_parse.append(self.raa_page['2021'])
if self.not_before.year <= 2020:
pages_to_parse.append(self.raa_page['2020'])
if self.not_before.year <= 2019:
pages_to_parse.append(self.raa_page['2019'])
sub_pages_to_parse = []
# Pour chaque année, on cherche les sous-pages de mois
for raa_page in pages_to_parse:
sub_pages_to_parse.append(raa_page)
for raa_page in year_pages_to_parse:
pages_to_parse.append(raa_page)
page_content = self.get_page(raa_page, 'get').content
month_pages = self.get_sub_pages(
for month_page in self.get_sub_pages(
page_content,
'.fr-card.fr-card--sm.fr-card--grey.fr-enlarge-link div.fr-card__body div.fr-card__content h2.fr-card__title a',
self.hostname,
False
)[::-1]
for month_page in month_pages:
sub_pages_to_parse.append(month_page['url'])
)[::-1]:
card_date = Attrap.guess_date(month_page['name'].strip(), '(.*)').replace(day=1)
if card_date >= self.not_before.replace(day=1):
pages_to_parse.append(month_page['url'])
# On parse les pages contenant des RAA
elements = self.get_raa_with_pager(
sub_pages_to_parse[::-1],
pages_to_parse[::-1],
'.fr-pagination__link.fr-pagination__link--next',
self.hostname
)
......
import os
import datetime
from Attrap_prefdpt import Attrap_prefdpt
from bs4 import BeautifulSoup
from urllib.parse import unquote
from Attrap import Attrap
class Attrap_pref87(Attrap_prefdpt):
class Attrap_pref87(Attrap):
# Config
# Configuration de la préfecture
hostname = 'https://www.haute-vienne.gouv.fr'
raa_page = {
'2024': [
f'{hostname}/Publications/Recueil-des-actes-administratifs/JANVIER-JUIN-2024/JANVIER-JUIN-2024',
f'{hostname}/Publications/Recueil-des-actes-administratifs/JUILLET-DECEMBRE-2024'
],
'2023': [
f'{hostname}/Publications/Recueil-des-actes-administratifs/JANVIER-JUIN-2023',
f'{hostname}/Publications/Recueil-des-actes-administratifs/JUILLET-DECEMBRE-2023/JUILLET-DECEMBRE-2023'
],
'2022': [
f'{hostname}/Publications/Recueil-des-actes-administratifs/JANVIER-JUIN-2022',
f'{hostname}/Publications/Recueil-des-actes-administratifs/JUILLET-DECEMBRE-2022/Recueil-des-actes-administratifs-2022',
],
'2021': [f'{hostname}/Publications/Recueil-des-actes-administratifs/Archives-des-recueils-des-actes-administratifs/2021'],
'2020': [f'{hostname}/Publications/Recueil-des-actes-administratifs/Archives-des-recueils-des-actes-administratifs/2020'],
'2019': [f'{hostname}/Publications/Recueil-des-actes-administratifs/Archives-des-recueils-des-actes-administratifs/2019']
}
user_agent = 'Mozilla/5.0 (Windows NT 10.0; rv:109.0) Gecko/20100101 Firefox/115.0'
raa_page = f'{hostname}/Publications/Recueil-des-actes-administratifs'
full_name = 'Préfecture de la Haute-Vienne'
short_code = 'pref87'
timezone = 'Europe/Paris'
def __init__(self, data_dir):
super().__init__(data_dir, self.user_agent)
self.set_sleep_time(30)
def get_raa(self, keywords):
year_pages_to_parse = []
if self.not_before.year <= 2024:
for year_page in self.raa_page['2024']:
year_pages_to_parse.append(year_page)
if self.not_before.year <= 2023:
for year_page in self.raa_page['2023']:
year_pages_to_parse.append(year_page)
if self.not_before.year <= 2022:
for year_page in self.raa_page['2022']:
year_pages_to_parse.append(year_page)
if self.not_before.year <= 2021:
for year_page in self.raa_page['2021']:
year_pages_to_parse.append(year_page)
if self.not_before.year <= 2020:
for year_page in self.raa_page['2020']:
year_pages_to_parse.append(year_page)
if self.not_before.year <= 2019:
for year_page in self.raa_page['2019']:
year_pages_to_parse.append(year_page)
pages_to_parse = year_pages_to_parse
# Pour chaque année, on cherche les éventuelles sous-pages de mois
for year_page in year_pages_to_parse:
page_content = self.get_page(year_page, 'get').content
month_pages = self.get_sub_pages(
page_content,
'.fr-card.fr-card--sm.fr-card--grey.fr-enlarge-link div.fr-card__body div.fr-card__content h2.fr-card__title a',
self.hostname,
False
)[::-1]
# On filtre les pages de mois ne correspondant pas à la période analysée
for month_page in month_pages:
guessed_date = Attrap.guess_date(month_page['name'], '([a-zéû]* [0-9]{4})').replace(day=1)
if guessed_date >= self.not_before.replace(day=1):
pages_to_parse.append(month_page['url'])
# On parse les pages contenant des RAA
elements = []
for page in pages_to_parse:
page_content = self.get_page(page, 'get').content
for raa in self.get_raa_elements(page_content):
elements.append(raa)
self.parse_raa(elements, keywords)
self.mailer()
def get_raa_elements(self, page_content):
elements = []
# On charge le parser
soup = BeautifulSoup(page_content, 'html.parser')
# On récupère chaque balise a
for a in soup.select('a.fr-link.fr-link--download'):
if a.get('href') and a['href'].endswith('.pdf'):
if a['href'].startswith('/'):
url = f"{self.hostname}{a['href']}"
else:
url = a['href']
url = unquote(url)
name = a.find('span').previous_sibling.replace('Télécharger ', '').strip()
date = datetime.datetime.strptime(a.find('span').get_text().split(' - ')[-1].strip(), '%d/%m/%Y')
raa = Attrap.RAA(url, date, name, timezone=self.timezone)
elements.append(raa)
return elements
# Configuration des widgets à analyser
Attrap_prefdpt.grey_card['regex']['year'] = '([0-9]{4})'
......@@ -19,7 +19,7 @@ class Attrap_pref92(Attrap):
def __init__(self, data_dir):
super().__init__(data_dir, self.user_agent)
self.set_sleep_time(30)
self.set_sleep_time(5)
def get_raa(self, keywords):
# On récupère les pages d'années
......
......@@ -11,15 +11,7 @@ class Attrap_pref976(Attrap):
# Config
hostname = 'https://www.mayotte.gouv.fr'
raa_page = {
'default': f'{hostname}/Publications/Recueil-des-actes-administratifs-R.A.A',
'2024': f'{hostname}/Publications/Recueil-des-actes-administratifs-R.A.A/RAA-2024',
'2023': f'{hostname}/Publications/Recueil-des-actes-administratifs-R.A.A/RAA-2023',
'2022': f'{hostname}/Publications/Recueil-des-actes-administratifs-R.A.A/RAA-2022',
'2021': f'{hostname}/Publications/Recueil-des-actes-administratifs-R.A.A/RAA-2021',
'2020': f'{hostname}/Publications/Recueil-des-actes-administratifs-R.A.A/RAA-2020',
'2019': f'{hostname}/Publications/Recueil-des-actes-administratifs-R.A.A/RAA-2019'
}
raa_page = f'{hostname}/Publications/Recueil-des-actes-administratifs-R.A.A'
user_agent = 'Mozilla/5.0 (Windows NT 10.0; rv:109.0) Gecko/20100101 Firefox/115.0'
full_name = 'Préfecture de Mayotte'
short_code = 'pref976'
......@@ -27,27 +19,26 @@ class Attrap_pref976(Attrap):
def __init__(self, data_dir):
super().__init__(data_dir, self.user_agent)
self.set_sleep_time(30)
self.set_sleep_time(5)
def get_raa(self, keywords):
pages_to_parse = []
if self.not_before.year <= 2024:
pages_to_parse.append(self.raa_page['2024'])
if self.not_before.year <= 2023:
pages_to_parse.append(self.raa_page['2023'])
if self.not_before.year <= 2022:
pages_to_parse.append(self.raa_page['2022'])
if self.not_before.year <= 2021:
pages_to_parse.append(self.raa_page['2021'])
if self.not_before.year <= 2020:
pages_to_parse.append(self.raa_page['2020'])
if self.not_before.year <= 2019:
pages_to_parse.append(self.raa_page['2019'])
sub_pages_to_parse = [self.raa_page['default']]
year_pages_to_parse = []
# On récupère les pages d'années
page_content = self.get_page(self.raa_page, 'get').content
for card in self.get_sub_pages(
page_content,
'div.fr-card__body div.fr-card__content h2.fr-card__title a',
self.hostname,
False
):
if Attrap.guess_date(card['name'], '([0-9]{4})').year >= self.not_before.year:
year_pages_to_parse.append(card['url'])
pages_to_parse = [self.raa_page]
# Pour chaque année, on cherche les sous-pages de mois
for raa_page in pages_to_parse:
for raa_page in year_pages_to_parse:
page_content = self.get_page(raa_page, 'get').content
month_pages = self.get_sub_pages(
page_content,
......@@ -58,8 +49,8 @@ class Attrap_pref976(Attrap):
# On regarde aussi si sur la page de l'année il n'y aurait pas un
# RAA mal catégorisé
for page_to_parse in self.find_raa_card(raa_page):
sub_pages_to_parse.append(page_to_parse)
for page_to_parse in self.find_raa_card(page_content):
pages_to_parse.append(page_to_parse)
# Pour chaque mois, on cherche les pages des RAA
for month_page in month_pages:
......@@ -68,11 +59,11 @@ class Attrap_pref976(Attrap):
month_page['url'],
year
):
sub_pages_to_parse.append(page_to_parse)
pages_to_parse.append(page_to_parse)
# On parse les pages contenant des RAA
elements = []
for page in sub_pages_to_parse:
for page in pages_to_parse:
page_content = self.get_page(page, 'get').content
for element in self.get_raa_elements(page_content):
elements.append(element)
......
import datetime
import time
from bs4 import BeautifulSoup
from urllib.parse import unquote
from Attrap import Attrap
class Attrap_prefbretagne(Attrap):
# Config
hostname = 'https://www.prefectures-regions.gouv.fr'
raa_page = f'{hostname}/bretagne/Documents-publications/Recueils-des-actes-administratifs/Recueil-des-actes-administratifs'
user_agent = 'Mozilla/5.0 (X11; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/128.0'
full_name = 'Préfecture de la région Bretagne'
short_code = 'prefbretagne'
timezone = 'Europe/Paris'
def __init__(self, data_dir):
super().__init__(data_dir, self.user_agent)
self.enable_tor(10)
self.set_sleep_time(10)
def get_raa(self, keywords):
# page_content = self.get_page(self.raa_page, 'get').content
page_content = self.get_session(self.raa_page, 'main', 6)
elements = self.get_raa_elements(page_content)
time.sleep(10)
self.parse_raa(elements, keywords)
self.mailer()
def get_raa_elements(self, page_content):
elements = []
# On charge le parser
soup = BeautifulSoup(page_content, 'html.parser')
# Pour chaque balise a, on regarde si c'est un PDF, et si oui on le parse
for a in soup.select('main div.container.main-container div.col-main article.article div.texte div a.link-download'):
if a.get('href') and a['href'].endswith('.pdf'):
if a['href'].startswith('/'):
url = f"{self.hostname}{a['href']}"
else:
url = a['href']
url = unquote(url)
name = a.find('span').get_text().strip()
# On devine la date du RAA à partir du nom de fichier
guessed = Attrap.guess_date(name, '((?:[0-9]{2}|[0-9]{1})(?:er){0,1}[ _](?:[a-zéû]{3,9})[ _](?:[0-9]{4}|[0-9]{2}))')
if (guessed == datetime.datetime(9999, 1, 1, 0, 0)):
date = None
else:
date = guessed
raa = Attrap.RAA(url, date, name, timezone=self.timezone)
elements.append(raa)
return elements
import datetime
from bs4 import BeautifulSoup
from urllib.parse import unquote
from Attrap import Attrap
class Attrap_prefdpt(Attrap):
user_agent = 'Mozilla/5.0 (X11; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/128.0'
# Paramètres par défaut des cartes grises et blanches. Devrait la plupart du temps être surchargés par la classe de préfecture de département
grey_card = {
'regex': {
'year': None,
'month': None
},
'css_path': {
'title': 'div.fr-card.fr-card--sm.fr-card--grey.fr-enlarge-link div.fr-card__body div.fr-card__content h2.fr-card__title a'
},
'link_to_raa': False,
'autodetect_links_to_raa': True,
'follow_link_on_unrecognised_date': True,
'exclude': [],
'add_year_to_months': False
}
white_card = {
'regex': {
'year': None,
'month': None,
},
'css_path': {
'title': 'div.fr-card.fr-card--horizontal.fr-card--sm.fr-enlarge-link div.fr-card__body div.fr-card__content h2.fr-card__title a.fr-card__link', # Chemin CSS du titre des cartes blanches
'details': 'div.fr-card.fr-card--horizontal.fr-card--sm.fr-enlarge-link div.fr-card__body div.fr-card__content div.fr-card__end p.fr-card__detail', # Chemin CSS du détail des cartes blanches
'pager': 'ul.fr-pagination__list li a.fr-pagination__link.fr-pagination__link--next.fr-pagination__link--lg-label' # Chemin CSS du pager des cartes blanches
},
'link_to_raa': False,
'autodetect_links_to_raa': True,
'follow_link_on_unrecognised_date': True,
'exclude': [],
'add_year_to_months': False
}
# Liste des widgets à analyser (sera remplie au moment de l'initialisation, mais peut être surchargée par la classe de préfecture de département)
widgets = []
select_widgets = []
# Est-ce qu'on inclue les widgets des cartes blanches et grises ? Par défaut oui, mais il peut être nécessaire de les désactiver sur certaines préfectures
include_grey_card_widget = True
include_white_card_widget = True
# Chemin CSS vers un RAA
element_css_path = 'div.fr-downloads-group.fr-downloads-group--bordered ul li a,div a.fr-link.fr-link--download'
# Temporisation (en secondes) entre chaque requête (ne devrait pas avoir à être changée)
pref_sleep_time = 5
class DptWidget:
"""Une classe représentant un widget sur le site d'une préfecture de département."""
def __init__(self, name, regex=None, css_path=None, link_to_raa=False, autodetect_links_to_raa=True, follow_link_on_unrecognised_date=True, exclude=[], add_year_to_months=False):
self.name = name
self.regex = regex
self.css_path = css_path
self.link_to_raa = link_to_raa
self.autodetect_links_to_raa = autodetect_links_to_raa
self.follow_link_on_unrecognised_date = follow_link_on_unrecognised_date
self.exclude = exclude
self.add_year_to_months = add_year_to_months
def has_css_path(self, key):
return self.css_path and self.css_path.get(key, None) is not None
def get_css_path(self, key):
if not self.has_css_path(key):
return None
else:
return self.css_path.get(key, None)
def has_regex(self, key):
return self.regex and self.regex.get(key, None) is not None
def get_regex(self, key):
if not self.has_regex(key):
return None
else:
return self.regex.get(key, None)
class DptSelectWidget:
"""Une classe représentant un menu déroulant sur le site d'une préfecture de département."""
def __init__(self, name, regex=None, css_path=None, follow_link_on_unrecognised_date=True, exclude=[], type='year-month-day'):
self.name = name
self.regex = regex
self.css_path = css_path
self.follow_link_on_unrecognised_date = follow_link_on_unrecognised_date
self.exclude = exclude
self.type = type
def add_url(self, url, date=None):
if date and date.year == 9999:
date = None
self.page_urls_to_parse.append([url, date])
def get_urls_to_parse(self):
urls = []
for url in self.page_urls_to_parse:
urls.append(url[0])
return urls
def __init__(self, data_dir):
"""Une classe générique permettant d'analyser les préfectures de département en fonction de certains paramètres."""
super().__init__(data_dir, self.user_agent)
self.set_sleep_time(self.pref_sleep_time)
self.page_urls_to_parse = []
if isinstance(self.raa_page, str):
self.add_url(self.raa_page)
else:
for url in self.raa_page:
self.add_url(url)
self.elements = []
# On ajoute les cartes grises et blanches à la liste des widgets à parser
if self.include_grey_card_widget:
self.widgets.append(
Attrap_prefdpt.DptWidget(
'grey_card',
regex=self.grey_card['regex'],
css_path=self.grey_card['css_path'],
link_to_raa=self.grey_card['link_to_raa'],
autodetect_links_to_raa=self.grey_card['autodetect_links_to_raa'],
follow_link_on_unrecognised_date=self.grey_card['follow_link_on_unrecognised_date'],
exclude=self.grey_card['exclude'],
add_year_to_months=self.grey_card['add_year_to_months']
)
)
if self.include_white_card_widget:
self.widgets.append(
Attrap_prefdpt.DptWidget(
'white_card',
regex=self.white_card['regex'],
css_path=self.white_card['css_path'],
link_to_raa=self.white_card['link_to_raa'],
autodetect_links_to_raa=self.white_card['autodetect_links_to_raa'],
follow_link_on_unrecognised_date=self.white_card['follow_link_on_unrecognised_date'],
exclude=self.white_card['exclude'],
add_year_to_months=self.white_card['add_year_to_months']
)
)
def get_raa(self, keywords):
while not self.page_urls_to_parse == []:
page_url = self.page_urls_to_parse[-1]
page_content = self.get_page(page_url[0], 'get').content # On récupère le HTML de la page
self.parse_widgets(page_url, page_content) # On parse les cartes
self.parse_select_widgets(page_url, page_content) # On parse les menus déroulants
for element in self.get_raa_elements(page_content): # On cherche les RAA
self.elements.append(element)
self.page_urls_to_parse.remove(page_url) # On supprime la page de la liste de celles à parser
self.parse_raa(self.elements[::-1], keywords)
self.mailer()
def parse_widgets(self, page_url, page_content):
# Pour chaque widget paramétré qui n'est pas de type select, on le cherche sur la page
for widget in self.widgets:
cards = []
# Si n'appelle pas la même fonction le widget a prévu un pager ou non
if widget.has_css_path('pager'):
cards = self.get_sub_pages_with_pager(
page_content,
widget.get_css_path('title'), # Titre du lien
widget.get_css_path('pager'), # Pager
widget.get_css_path('details'), # Détails
self.hostname
)
else:
cards = self.get_sub_pages(
page_content,
widget.get_css_path('title'),
self.hostname,
False
)
for card in cards:
if card['url'] not in self.get_urls_to_parse() and card['name'].strip() not in widget.exclude:
date = None
date_is_correct = False
# Si un regex d'année est spécifié, on parse le titre avec
if widget.has_regex('year'):
date = Attrap.guess_date(card['name'].strip(), widget.get_regex('year')).replace(day=1, month=1)
# Si une date a été trouvée (l'année n'est pas 9999) et qu'elle est avant la valeur not_before, on la marque comme correcte
if date >= self.not_before.replace(day=1, month=1) and date.year < 9999:
date_is_correct = True
# Si un regex de mois est spécifié et qu'aucune date correcte n'a été trouvée, on teste avec le regex de mois sur le titre
if widget.has_regex('month') and (not date or date.year == 9999):
# On ajoute l'année au nom du mois à tester si configuré dans le widget
if widget.add_year_to_months and page_url[1]:
month = card['name'].strip() + ' ' + str(page_url[1].year)
else:
month = card['name'].strip()
date = Attrap.guess_date(month, widget.get_regex('month')).replace(day=1)
if date >= self.not_before.replace(day=1) and date.year < 9999:
date_is_correct = True
# Si un chemin CSS vers les détails du widget est spécifié et qu'aucune date correcte n'a été trouvée, on tente de parser la date présente dans les détails
if widget.has_css_path('details') and (not date or date.year == 9999):
try:
date = datetime.datetime.strptime(card['details'].replace('Publié le ', '').strip(), '%d/%m/%Y')
if date >= self.not_before:
date_is_correct = True
except Exception as e:
date = datetime.datetime(9999, 1, 1)
# Si la configuration indique que les liens renvoient vers un RAA, on ajoute le lien à la liste des éléments
if widget.link_to_raa or (widget.autodetect_links_to_raa and card['url'].endswith('.pdf')):
if date and date.year == 9999:
date = None
raa = Attrap.RAA(card['url'], date, card['name'].strip(), timezone=self.timezone)
self.elements.append(raa)
else:
# Si une date a été trouvée, on regarde s'il faut ajouter l'URL à la liste des pages à parser
if date_is_correct or ((date is None or date.year == 9999) and widget.follow_link_on_unrecognised_date):
self.add_url(card['url'], date)
def parse_select_widgets(self, page_url, page_content):
for select_widget in self.select_widgets:
# Les widgets select fonctionnent différemment : chaque valeur option doit être testée pour trouver une date, et si la date correspond
# à la date recherchée la requête POST est envoyée, puis le résultat est analysé par get_raa_elements()
# On charge le parser
soup = BeautifulSoup(page_content, 'html.parser')
# On récupère les select
for select in soup.select(select_widget.css_path):
# On récupère les option de chaque select
for option in select.find_all('option'):
if not option['value'] == "" and option['title'].strip() not in select_widget.exclude:
# On estime la date à partir du nom de fichier
date = Attrap.guess_date(option['title'].strip(), select_widget.regex)
match select_widget.type:
case 'year':
date = date.replace(day=1, month=1)
not_before = self.not_before.replace(day=1, month=1)
case 'year-month':
date = date.replace(day=1)
not_before = self.not_before.replace(day=1)
case _:
not_before = self.not_before
# Si la date estimée correspond à la plage d'analyse ou si follow_link_on_unrecognised_date est à True,
# on demande au serveur les détails du RAA
if (date.year < 9999 and date >= not_before) or (date.year == 9999 and select_widget.follow_link_on_unrecognised_date):
page_content = self.get_page(
page_url[0],
'post',
{
select['id']: option['value']
}
).content
for element in self.get_raa_elements(page_content):
self.elements.append(element)
def get_raa_elements(self, page_content):
elements = []
# On charge le parser
soup = BeautifulSoup(page_content, 'html.parser')
# On récupère chaque balise a
for a in soup.select(self.element_css_path):
if a.get('href'):
if a['href'].startswith('/'):
url = f"{self.hostname}{a['href']}"
else:
url = a['href']
url = unquote(url)
name = a.find('span').previous_sibling.replace('Télécharger ', '').strip()
if not name:
name = url.split('/')[-1].strip()
try:
date = datetime.datetime.strptime(a.find('span').get_text().split(' - ')[-1].strip(), '%d/%m/%Y')
except Exception:
date = None
raa = Attrap.RAA(url, date, name, timezone=self.timezone)
elements.append(raa)
return elements
......@@ -11,51 +11,44 @@ class Attrap_prefidf(Attrap):
# Config
hostname = 'https://www.prefectures-regions.gouv.fr'
raa_page = {
'2024': f'{hostname}/ile-de-france/ile-de-france/ile-de-france/Documents-publications/Recueil-des-actes-administratifs/RAA-de-la-region-Ile-de-France-2024',
'2023': f'{hostname}/ile-de-france/ile-de-france/ile-de-france/Documents-publications/Recueil-des-actes-administratifs/RAA-de-la-region-Ile-de-France-2023',
'2022': f'{hostname}/ile-de-france/ile-de-france/ile-de-france/Documents-publications/Recueil-des-actes-administratifs/RAA-de-la-region-Ile-de-France-2022',
'2021': f'{hostname}/ile-de-france/ile-de-france/ile-de-france/Documents-publications/Recueil-des-actes-administratifs/RAA-de-la-region-Ile-de-France-2021',
'2020': f'{hostname}/ile-de-france/ile-de-france/ile-de-france/Documents-publications/Recueil-des-actes-administratifs/RAA-de-la-region-Ile-de-France-2020',
'2019': f'{hostname}/ile-de-france/ile-de-france/ile-de-france/Documents-publications/Recueil-des-actes-administratifs/RAA-de-la-region-Ile-de-France-2019',
'2018': f'{hostname}/ile-de-france/ile-de-france/ile-de-france/Documents-publications/Recueil-des-actes-administratifs/RAA-de-la-region-Ile-de-France-2018'
}
user_agent = 'Mozilla/5.0 (Windows NT 10.0; rv:109.0) Gecko/20100101 Firefox/115.0'
full_name = 'Préfecture d\'Île-de-France'
raa_page = f'{hostname}/ile-de-france/tags/view/Ile-de-France/Documents+et+publications/Recueil+des+actes+administratifs'
user_agent = 'Mozilla/5.0 (X11; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/128.0'
full_name = 'Préfecture de la région Île-de-France'
short_code = 'prefidf'
timezone = 'Europe/Paris'
def __init__(self, data_dir):
super().__init__(data_dir, self.user_agent)
self.enable_tor(10)
self.set_sleep_time(10)
def get_raa(self, keywords):
year_pages_to_parse = []
# Les RAA de l'Île-de-France sont éparpillés sur des sous-pages par mois.
# Donc on parse la page principale à la recherche des sous-pages.
if self.not_before.year <= 2024:
year_pages_to_parse.append(self.raa_page['2024'])
if self.not_before.year <= 2023:
year_pages_to_parse.append(self.raa_page['2023'])
if self.not_before.year <= 2022:
year_pages_to_parse.append(self.raa_page['2022'])
if self.not_before.year <= 2021:
year_pages_to_parse.append(self.raa_page['2021'])
if self.not_before.year <= 2020:
year_pages_to_parse.append(self.raa_page['2020'])
if self.not_before.year <= 2019:
year_pages_to_parse.append(self.raa_page['2019'])
# On détermine quelles pages d'année parser
page_content = self.get_session(self.raa_page, 'main', 6)
year_pages = self.get_sub_pages(
page_content,
'article.news-list-item header h2.news-list-title a',
self.hostname,
False,
selenium=True
)
for year_page in year_pages:
year_date = Attrap.guess_date(year_page['name'].strip(), '(?:.*[ÎIiî]le-de-[Ff]rance.*)([0-9]{4})').replace(day=1, month=1)
if year_date.year >= self.not_before.year and year_date.year < 9999:
year_pages_to_parse.append(year_page['url'])
pages_to_parse = []
for year_page in year_pages_to_parse:
page_content = self.get_page(year_page, 'get').content
page_content = self.get_page(year_page, 'get', selenium=True).content
year = BeautifulSoup(page_content, 'html.parser').select('div.breadcrumb div.container p span.active')[0].get_text().split('-')[-1].strip()
month_pages = self.get_sub_pages(
page_content,
'div.sommaire-bloc div.sommaire-content ol li a',
self.hostname,
False
False,
selenium=True
)[::-1]
for month_page in month_pages:
month_date = Attrap.guess_date(f"{month_page['name']} {year}", "(.*)").replace(day=1)
......@@ -64,7 +57,7 @@ class Attrap_prefidf(Attrap):
elements = []
for page in pages_to_parse:
page_content = self.get_page(page, 'get').content
page_content = self.get_session(page, 'main', 6)
for element in self.get_raa_elements(page_content):
elements.append(element)
......
......@@ -12,24 +12,29 @@ class Attrap_prefpaca(Attrap):
# Config
hostname = 'https://www.prefectures-regions.gouv.fr'
raa_page = f'{hostname}/provence-alpes-cote-dazur/Documents-publications'
user_agent = 'Mozilla/5.0 (Windows NT 10.0; rv:109.0) Gecko/20100101 Firefox/115.0'
full_name = 'Préfecture de Provence-Alpes-Côte-d\'Azur'
user_agent = 'Mozilla/5.0 (X11; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/128.0'
full_name = 'Préfecture de la région Provence-Alpes-Côte-d\'Azur'
short_code = 'prefpaca'
timezone = 'Europe/Paris'
def __init__(self, data_dir):
super().__init__(data_dir, self.user_agent)
self.enable_tor(10)
self.set_sleep_time(10)
def get_raa(self, keywords):
# On récupère une session avec Selenium
page_content = self.get_session(self.raa_page, 'main', 6)
# On récupère les pages d'années
year_pages = []
for year_page in self.get_sub_pages_with_pager(
self.raa_page,
page_content,
'article.news-list-item header h2.news-list-title a',
'article.article div.content-pagination ul.pagination li.next a',
None,
self.hostname
self.hostname,
selenium=True
):
year = Attrap.guess_date(year_page['name'].strip(), 'RAA ([0-9]{4})').year
if year < 9999 and year >= self.not_before.year:
......@@ -37,7 +42,7 @@ class Attrap_prefpaca(Attrap):
elements = []
for year_page in year_pages:
page_content = self.get_page(year_page, 'get').content
page_content = self.get_session(year_page, 'main', 6)
for element in self.get_raa_elements(page_content):
elements.append(element)
......
make: ppparis pref2b pref03 pref04 pref05 pref06 pref09 pref10 pref13 pref25 pref31 pref33 pref34 pref35 pref38 pref39 pref42 pref44 pref59 pref62 pref63 pref64 pref65 pref66 pref69 pref73 pref75 pref80 pref81 pref83 pref87 pref91 pref92 pref93 pref94 pref976 prefidf prefpaca
make: ppparis pref01 pref02 pref03 pref04 pref05 pref06 pref09 pref10 pref11 pref13 pref2a pref2b pref25 pref29 pref30 pref31 pref33 pref34 pref35 pref38 pref39 pref42 pref44 pref49 pref50 pref52 pref54 pref55 pref59 pref61 pref62 pref63 pref64 pref65 pref66 pref69 pref73 pref75 pref76 pref77 pref80 pref81 pref83 pref87 pref91 pref92 pref93 pref94 pref976 prefbretagne prefidf prefpaca
ppparis:
bin/python3 cli.py ppparis
pref2b:
bin/python3 cli.py pref2b
pref01:
bin/python3 cli.py pref01
pref02:
bin/python3 cli.py pref02
pref03:
bin/python3 cli.py pref03
pref04:
......@@ -15,10 +17,20 @@ pref09:
bin/python3 cli.py pref09
pref10:
bin/python3 cli.py pref10
pref11:
bin/python3 cli.py pref11
pref13:
bin/python3 cli.py pref13
pref2a:
bin/python3 cli.py pref2a
pref2b:
bin/python3 cli.py pref2b
pref25:
bin/python3 cli.py pref25
pref29:
bin/python3 cli.py pref29
pref30:
bin/python3 cli.py pref30
pref31:
bin/python3 cli.py pref31
pref33:
......@@ -35,8 +47,20 @@ pref42:
bin/python3 cli.py pref42
pref44:
bin/python3 cli.py pref44
pref49:
bin/python3 cli.py pref49
pref50:
bin/python3 cli.py pref50
pref52:
bin/python3 cli.py pref52
pref54:
bin/python3 cli.py pref54
pref55:
bin/python3 cli.py pref55
pref59:
bin/python3 cli.py pref59
pref61:
bin/python3 cli.py pref61
pref62:
bin/python3 cli.py pref62
pref63:
......@@ -53,6 +77,10 @@ pref73:
bin/python3 cli.py pref73
pref75:
bin/python3 cli.py pref75
pref76:
bin/python3 cli.py pref76
pref77:
bin/python3 cli.py pref77
pref80:
bin/python3 cli.py pref80
pref81:
......@@ -71,6 +99,8 @@ pref94:
bin/python3 cli.py pref94
pref976:
bin/python3 cli.py pref976
prefbretagne:
bin/python3 cli.py prefbretagne
prefidf:
bin/python3 cli.py prefidf
prefpaca:
......
......@@ -57,15 +57,21 @@ Vous pouvez également activer le safe mode en spécifiant la variable d'environ
## Administrations supportées
- Préfecture de police de Paris (identifiant : `ppparis`)
- Préfecture de Haute-Corse (identifiant : `pref2b`)
- Préfecture de l'Ain (identifiant : `pref01`)
- Préfecture de l'Aisne (identifiant : `pref02`)
- Préfecture de l'Allier (identifiant : `pref03`)
- Préfecture des Alpes-de-Haute-Provence (identifiant : `pref04`)
- Préfecture des Hautes-Alpes (identifiant : `pref05`)
- Préfecture des Alpes-Maritimes (identifiant : `pref06`)
- Préfecture de l'Ariège (identifiant : `pref09`)
- Préfecture de l'Aube (identifiant : `pref10`)
- Préfecture de l'Aude (identifiant : `pref11`)
- Préfecture des Bouches-du-Rhône (identifiant : `pref13`)
- Préfecture de la Corse-du-Sud (identifiant : `pref2a`)
- Préfecture de Haute-Corse (identifiant : `pref2b`)
- Préfecture du Doubs (identifiant : `pref25`)
- Préfecture du Finistère (identifiant : `pref29`)
- Prefecture du Gard (identifiant : `pref30`)
- Préfecture de la Haute-Garonne (identifiant : `pref31`)
- Préfecture de la Gironde (identifiant : `pref33`)
- Préfecture de l'Hérault (identifiant : `pref34`)
......@@ -74,7 +80,13 @@ Vous pouvez également activer le safe mode en spécifiant la variable d'environ
- Préfecture du Jura (identifiant : `pref39`)
- Préfecture de la Loire (identifiant : `pref42`)
- Préfecture de la Loire-Atlantique (identifiant : `pref44`)
- Préfecture de Maine-et-Loire (identifiant : `pref49`)
- Préfecture de la Manche (identifiant : `pref50`)
- Préfecture de la Haute-Marne (identifiant : `pref52`)
- Préfecture de Meurthe-et-Moselle (identifiant : `pref54`)
- Préfecture de la Meuse (identifiant : `pref55`)
- Préfecture du Nord (identifiant : `pref59`)
- Préfecture de l'Orne (identifiant : `pref61`)
- Préfecture du Pas-de-Calais (identifiant : `pref62`)
- Préfecture du Puy-de-Dôme (identifiant : `pref63`)
- Préfecture des Pyrénées-Atlantiques (identifiant : `pref64`)
......@@ -83,6 +95,8 @@ Vous pouvez également activer le safe mode en spécifiant la variable d'environ
- Préfecture du Rhône (identifiant : `pref69`)
- Préfecture de la Savoie (identifiant : `pref73`)
- Préfecture de Paris (identifiant : `pref75`)
- Préfecture de la Seine-Maritime (identifiant : `pref76`)
- Préfecture de Seine-et-Marne (identifiant : `pref77`)
- Préfecture de la Somme (identifiant : `pref80`)
- Préfecture du Tarn (identifiant : `pref81`)
- Préfecture du Var (identifiant : `pref83`)
......@@ -92,8 +106,9 @@ Vous pouvez également activer le safe mode en spécifiant la variable d'environ
- Préfecture de Seine-Saint-Denis (identifiant : `pref93`)
- Préfecture du Val-de-Marne (identifiant : `pref94`)
- Préfecture de Mayotte (identifiant : `pref976`)
- Préfecture d'Île-de-France (identifiant : `prefidf`)
- Préfecture de Provence-Alpes-Côte-d'Azur (identifiant : `prefpaca`)
- Préfecture de la région Bretagne (identifiant : `prefbretagne`)
- Préfecture de la région Île-de-France (identifiant : `prefidf`)
- Préfecture de la région Provence-Alpes-Côte-d'Azur (identifiant : `prefpaca`)
## Contributions
......
......@@ -45,15 +45,21 @@ __MASTODON_INSTANCE = os.getenv('MASTODON_INSTANCE')
# Liste des administrations supportées
available_administrations = [
'ppparis',
'pref2b',
'pref01',
'pref02',
'pref03',
'pref04',
'pref05',
'pref06',
'pref09',
'pref10',
'pref11',
'pref13',
'pref2a',
'pref2b',
'pref25',
'pref29',
'pref30',
'pref31',
'pref33',
'pref34',
......@@ -62,7 +68,13 @@ available_administrations = [
'pref39',
'pref42',
'pref44',
'pref49',
'pref50',
'pref52',
'pref54',
'pref55',
'pref59',
'pref61',
'pref62',
'pref63',
'pref64',
......@@ -71,6 +83,8 @@ available_administrations = [
'pref69',
'pref73',
'pref75',
'pref76',
'pref77',
'pref80',
'pref81',
'pref83',
......@@ -80,6 +94,7 @@ available_administrations = [
'pref93',
'pref94',
'pref976',
'prefbretagne',
'prefidf',
'prefpaca'
]
......
#!/usr/bin/env python3
import argparse
import json
import os
import re
from urllib.parse import unquote
import hashlib
parser = argparse.ArgumentParser(
prog='./misc/fix-pref75-prefidf-url.py',
description='Met à jour les URL des RAA de Paris et d\'Idf'
)
parser.add_argument(
'--data-dir',
action='store',
help='dossier de données (par défaut: data/)'
)
parser.add_argument(
'--dry-run',
action='store_true',
help='ne modifie aucun fichier, affiche seulement les modifications nécessaires (par défaut: false)'
)
args = parser.parse_args()
if args.data_dir:
data_dir = args.data_dir
else:
data_dir = 'data/'
dry_run = args.dry_run
if data_dir.startswith('/'):
data_dir = os.path.abspath(data_dir)
else:
data_dir = os.path.abspath(os.path.dirname(os.path.abspath(__file__)) + '/../' + data_dir)
for administration in os.listdir(data_dir):
# On ne cherche que les dossiers prefidf et pref75
if administration == 'prefidf' or administration == 'pref75':
administration_path = os.path.abspath(data_dir + '/' + administration + '/raa/')
for raa in os.listdir(administration_path):
if raa.endswith('.json'):
raa_id = re.sub('\\.json$', '', raa)
fixed = False
raa_path = os.path.abspath(administration_path + '/' + raa)
txt_path = re.sub('\\.json$', '.txt', raa_path)
raa_file_read = open(raa_path, 'r')
raa_json = json.load(raa_file_read)
raa_file_read.close()
url = raa_json.get('url')
if url.startswith('https://www.prefectures-regions.gouv.fr/ile-de-france/ile-de-france/ile-de-france/irecontenu/telechargement/'):
raa_json['url'] = url.replace('https://www.prefectures-regions.gouv.fr/ile-de-france/ile-de-france/ile-de-france/irecontenu/telechargement/', 'https://www.prefectures-regions.gouv.fr/ile-de-france/irecontenu/telechargement/')
fixed_raa_json = {}
for key in raa_json:
fixed_raa_json[key] = raa_json[key]
fixed_raa_id = hashlib.sha256(unquote(raa_json['url']).encode('utf-8')).hexdigest()
fixed_raa_path = raa_path.replace(raa_id, fixed_raa_id)
fixed_txt_path = txt_path.replace(raa_id, fixed_raa_id)
print(f'{raa_id} -> {fixed_raa_id}:')
print(f" {raa_json['url']}")
print('')
if not dry_run:
raa_file_write = open(fixed_raa_path, 'w')
raa_file_write.write(json.dumps(fixed_raa_json))
raa_file_write.close()
os.remove(raa_path)
os.rename(txt_path, fixed_txt_path)
......@@ -109,8 +109,11 @@ def fix_json(raa_json, raa_id, administration):
pdf_modification_date = Attrap.get_aware_datetime(pdf_metadata.modification_date, timezone=Attrap_pref976.timezone)
raa_json['pdf_modification_date'] = pdf_modification_date.astimezone(pytz.utc).isoformat(timespec="seconds")
print(' Ajout du fuseau horaire Europe/Paris')
raa_json['timezone'] = 'Europe/Paris'
print(' Ajout du fuseau horaire')
if administration == 'pref976':
raa_json['timezone'] = Attrap_pref976.timezone
else:
raa_json['timezone'] = 'Europe/Paris'
raa_json['version'] = 2
return fix_json(raa_json, raa_id, administration)
......@@ -123,7 +126,7 @@ def fix_json(raa_json, raa_id, administration):
parser = argparse.ArgumentParser(
prog='./misc/repair_date_format_in_data.py',
prog='./misc/update_metadata_format.py',
description='Met à jour le format des fichiers de métadonnées'
)
......