On est parti du Service Géoplateforme de téléchargement https://geoservices.ign.fr/services-geoplateforme-telechargement
Prendre le zip ign_files_list.zip. Il contient
Les filtres listés sur le point d'entrée principal
zones_rss_search_geopf.csv
formats_rss_search_geopf.csv
categories_rss_search_geopf.csv
Les fichiers correspondants au listing des ressources, sous-ressources et fichiers de téléchargement associés avec
ressources_search_geopf.csv
sub_ressources_search_geopf.csv
download__from_sub_ressources_search_geopf_with_stats.csv
download__from_sub_ressources_search_geopf_with_stats_no_pva.csv
L'intérêt du download__from_sub_ressources_search_geopf_with_stats.csv
est qu'il permet d'anticiper l'espace disque compressé pour le téléchargement et de faire une recherche via un tableur. Attention, il y a 1.8 millions de lignes (avec 1 877 614 lignes sans l'en tête du csv). La majorité sont les PVA (prises de vue aériennes historiques non calées, approximativement placées) qui sont au nombre 1 862 115 lignes) et 15499 lignes pour les autres données.
Nous avons de ce fait filtrer les données hors PVA dans un fichier à part download__from_sub_ressources_search_geopf_with_stats_no_pva.csv
.
La taille totale des fichiers disponibles sur les serveurs pour les fichiers listés est de 73,44TiB dont 22,98TiB qui ne sont pas des PVA. Il faut aussi noter que le nombre de fichiers réelllement utilisable est inférieur. Nous n'avons pas filtré les fichiers md5 qui permettent de vérifier si un fichier a été corrompu lors du téléchargement.
Nous déroulons la recette et des remarques techniques associées ayant permis d'avoir les fichiers ci-dessus
On s'appuie sur curl, yq, jq, xmllint, xq fournit par yq
curl -s https://data.geopf.fr/telechargement/capabilities?pageSize=200 | xmllint --format - >| geopf-download-capabilities.xml
Cela correspond à ceux qui sont mentionnés dans https://geoservices.ign.fr/documentation/services/services-geoplateforme/telechargement#72127
echo '"term","label"' >| zones_rss_search_geopf.csv
xq -c -r --xml-force-list "gpf_dl:zone" '.feed.entry[]."gpf_dl:zone"' geopf-download-capabilities.xml | grep -v '^null' | jq -c -r '.[] | [."@term", ."@label"] | @csv' | grep -v '"",""' | sort | uniq >> zones_rss_search_geopf.csv
echo '"term","label"' >| formats_rss_search_geopf.csv
xq -c -r --xml-force-list "gpf_dl:format" '.feed.entry[]."gpf_dl:format"' geopf-download-capabilities.xml | grep -v '^null' | jq -c -r '.[] | [."@term", ."@label"] | @csv' | grep -v '"",""' | sort | uniq >> formats_rss_search_geopf.csv
echo '"term","label"' >| categories_rss_search_geopf.csv
xq -c -r --xml-force-list "category" '.feed.entry[]."category"' geopf-download-capabilities.xml | grep -v '^null' | jq -c -r '.[] | [."@term", ."@label"] | @csv' | grep -v '"",""' | sort | uniq >> categories_rss_search_geopf.csv
Attention, dans la doc, les pages devraient commencer avec le numero 1. Dans les faits, cela commence avec 0. Soit c'est un problème dans l'implémentation soit dans la doc.
curl 'https://data.geopf.fr/telechargement/resource/ADMIN-EXPRESS-COG?pageSize=20&page=1' >| page_1.txt
curl 'https://data.geopf.fr/telechargement/resource/ADMIN-EXPRESS-COG?pageSize=20&page=0' >| page_0.txt
curl 'https://data.geopf.fr/telechargement/resource/ADMIN-EXPRESS-COG?pageSize=20' >| page_default.txt
# Ce qui suit ne retourne rien donc page 0 = page par défaut
diff page_0.txt page_default.txt
diff page_1.txt page_default.txt
Reprenons le listing des ressources
echo '"title","id","link","summary"' >| ressources_search_geopf.csv
xq -c -r '.feed.entry[] | [.title, .id, .link."@href", .summary] | @csv' geopf-download-capabilities.xml >> ressources_search_geopf.csv
Boucler sur les ressources pour obtenir les infos associées aux sous-ressources
ressources_url=$(xsv select id ressources_search_geopf.csv | sed '1d')
echo '"sub_res_id","title","id","href","summary","category_term","category_label","zone_term","zone_label","format_term","format_label"' >| sub_ressources_search_geopf.csv
for url in $ressources_url;
do count_pages=$(curl -s "$url?pageSize=200" | xq -r '.feed | ."@gpf_dl:pagecount"');
end_seq_pages=$((count_pages - 1));
for i in $(seq 0 $end_seq_pages);
do echo "${url}?pageSize=200&page=${i}";
curl -s "${url}?pageSize=200&page=${i}" | xq -c -r --xml-force-list "entry" '.feed.id as $res_id | .feed.entry[] | [$res_id, if has("title") then .title else "notitle" end , .id, .link."@href", .summary, .category."@term", .category."@label", ."gpf_dl:zone"."@term", ."gpf_dl:zone"."@label", ."gpf_dl:format"."@term", ."gpf_dl:format"."label"] | @csv' >> sub_ressources_search_geopf.csv;
done;
done;
Ressources non disponibles ci-dessous (ou bien protégée?). Heureusement les dernières dans la liste donc n'a rien planté car je ne teste pas les 404 par défaut...
- https://data.geopf.fr/telechargement/resource/pack_psmv
- https://data.geopf.fr/telechargement/resource/pack_scot
- https://data.geopf.fr/telechargement/resource/pack_sup
Il faut aussi noter que pour les gpf_dl:format
, on a des cas particuliers où un fichier retourne plusieurs types alors que globalement, il y a un seule type, un shp (nous n'avons pas géré ce cas). A priori, il doit avoir une forme de détection de fichiers compressés pour remplir ce champ.
curl -s https://data.geopf.fr/telechargement/resource/RPG/RPG_2-0__SHP_LAMB93_R93_2021-01-01 | xq .
retourne (partie tronquée)
...
"gpf_dl:format": [
{
"@term": "application/octet-stream",
"@label": "application/octet-stream"
},
{
"@term": "application/x-shapefile",
"@label": "application/x-shapefile"
},
{
"@term": "image/x-prj",
"@label": "image/x-prj"
}
]
...
Pour chacune des sous-ressources, récupérer les fichiers associés
sub_ressources_url=$(xsv select id sub_ressources_search_geopf.csv | sed '1d')
>| download__from_sub_ressources_search_geopf_temp.csv
for url in $sub_ressources_url;
do count_pages=$(curl -s "$url?pageSize=200" | xq -r '.feed | ."@gpf_dl:pagecount"');
end_seq_pages=$((count_pages - 1));
for i in $(seq 0 $end_seq_pages);
do echo "${url}?pageSize=200&page=${i}";
curl -s "${url}?pageSize=200&page=${i}" | xq -c -r --xml-force-list "entry" '.feed.id as $res_id | .feed.entry[] | [$res_id, if has("title") then .title else "notitle" end , .id, .link."@href", .summary, .category."@term", .category."@label", ."gpf_dl:zone"."@term", ."gpf_dl:zone"."@label", ."gpf_dl:format"."@term", ."gpf_dl:format"."label"] | @csv' >> download__from_sub_ressources_search_geopf_temp.csv;
done;
done;
# On nettoye quelques doublons qui posaient problème lors de la jointure ultérieure
echo '"sub_res_id","title","id","href","summary","category_term","category_label","zone_term","zone_label","format_term","format_label"' >| download__from_sub_ressources_search_geopf.csv
sort download__from_sub_ressources_search_geopf_temp.csv | uniq >> download__from_sub_ressources_search_geopf.csv
rm download__from_sub_ressources_search_geopf_temp.csv
>| configfile.txt
for i in $(xsv select href <(cat download__from_sub_ressources_search_geopf.csv) | sed '1d');
do echo 'url = "'$i'"' >> configfile.txt;
done;
echo "url,content_length,response_code" >| files_stats.txt
curl -L --head --parallel --parallel-immediate --parallel-max 4 --write-out '%output{>>files_stats.txt}%{url},%header{content-length},%{response_code}\n' --config configfile.txt > /dev/null
On a eu quelques erreurs 503, qu'on a géré en appliquant le flag -L
de redirection de "curl".
On a identifié une erreur 404 sur https://data.geopf.fr/telechargement/download/pva/92PHQ9651/263562_IGNF_PVA_1-0__1954-06-08__C92PHQ9651_1954_NOUVELLE-CALEDONIE14_19X22_0127.tif.aux.xml
xsv search -s response_code 200 files_stats.txt | xsv select content_length | sed '1d' | paste -s -d+ - | bc | numfmt --to=iec-i --suffix=B --format="%9.2f"
# 73,44TiB
xsv join --no-case id download__from_sub_ressources_search_geopf.csv url files_stats.txt | xsv select 'sub_res_id,title,id,summary,category_term,category_label,zone_term,zone_label,content_length,response_code' >| download__from_sub_ressources_search_geopf_with_stats.csv
grep -v '/pva/' download__from_sub_ressources_search_geopf_with_stats.csv >| download__from_sub_ressources_search_geopf_with_stats_no_pva.csv
Taille hors PVA
xsv search -s response_code 200 download__from_sub_ressources_search_geopf_with_stats_no_pva.csv | xsv select content_length | sed '1d' | paste -s -d+ - | bc | numfmt --to=iec-i --suffix=B --format="%9.2f"
# 22,98TiB
On zippe tout
zip ign_files_list.zip categories_rss_search_geopf.csv download__from_sub_ressources_search_geopf_with_stats.csv download__from_sub_ressources_search_geopf_with_stats_no_pva.csv formats_rss_search_geopf.csv ressources_search_geopf.csv sub_ressources_search_geopf.csv zones_rss_search_geopf.csv
Un truc très ennuyeux du point de vue fonctionnel pour moi: il n'y a pas de date "Last-Modified" du type "Fri, 05 Apr 2024 15:58:59 GMT" dans les flux. Les noms de fichiers sont daté mais cela reste nettement moins pratique. L'intérêt de cette fonctionnalité c'est de permettre la reprise des téléchargements et savoir si fichier changé (exemple d'un fichier réuploadé suite à des corrections). Cela semble être caché par l'outil Kong (déduit des en-têtes http) utilisé en front des services de l'IGN.
J'aimerais aussi avoir des dates pour pouvoir filtrer par date. C'est à priori prévu via les filtres (mentionné dans la documentation) mais ce n'est pas encore disponible.