Projet informatique en commun - guide racial des villes

Oskar Schindler

SA- aspirant
Membre
Joined
Aug 14, 2020
Messages
97
Reaction score
244
Je reviens après avoir utiliser un peu Spacy et re-analyser les postes.
Je ne pense pas qu'il faille Spacy si nous nous basons sur les URL de FDS puisque le site est au préalable orienté criminalité allogène.
Avec la liste de mots-clés que j'ai posté plus haut, cela ferrait amplement l'affaire(la liste pourrait être mis à jour pour plus de précision).
Spacy est seulement bénéfique si nous entendons les recheches sur d'autres sites(voir la structure de ceux-ci), dans ce cas, il serait intéressant de faire de la machine learning.
Autre problème concernant la catégorisation raciale est qu'en France, les articles ne précisent jamais la race de l'individu ce qui complique grandement la détection, particulièrement pour les allogènes nègres ayant des noms/prénoms Français comme Ludovic Bertin.

J'attends ton retour sur la proposition.
Spacy permet de faire de la Named Entity Recognition, et donc de localiser les noms de villes, par exemple. Le regex est utile mais on oubliera beaucoup de posts mal formatés, ce qui est parfois le cas avec fdesouche.

Pour ce qui est de la catégorisation des crimes, la liste est utile pour créer des données d'entraînement et ensuite généraliser en utilisant un réseau de neurones. Ce sera dans un second temps.

Enfin, pour ce qui est de la race des agresseurs... Je pense que ce sera complexe, d'autant que trouver le nom de l'aggresseur parmi les autres est contextuel et les réseaux de neurones ont généralement du mal pour ce genre de chose.

J'avance sur le sujet, j'ai eu du travail récemment, désolé de te faire attendre. Je t'envoie une première mouture ce soir ou demain.

PS : tu as utilisé un retardateur (genre "attend 1sec entre les requêtes") pour scraper les adresses ?
 
Last edited:

Un Four Pour Tous

SA- aspirant
Membre
Joined
Aug 2, 2020
Messages
126
Reaction score
219
Pour ce qui est de la catégorisation des crimes, la liste est utile pour créer des données d'entraînement et ensuite généraliser en utilisant un réseau de neurones. Ce sera dans un second temps.
Est ce qu'il serait possible d'avoir la doc parce que je ne vois pas de quoi tu parles.

Sinon OK, j'attends.

Pour les requêtes sur fds, j'avais mis 250 millisecondes entre chaques.
 

Oskar Schindler

SA- aspirant
Membre
Joined
Aug 14, 2020
Messages
97
Reaction score
244
Tu peux retrouver le cours de l'aryenne à l'origine du package :

https://course.spacy.io/en/

Son github : https://github.com/ines/spacy-course

Ce dont je parlais est au chapitre 4 / partie 9 :

Un autre problème courant est que ton modèle n'apprenne pas ce que tu veux qu'il apprenne.

Les modèles de spaCy effectuent des prédictions basées sur le contexte local - par exemple, pour les entités nommées, ce sont les mots adjacents qui sont les plus importants.

Si la décision est difficile à prendre en se basant sur le contexte, le modèle pourra avoir des difficultés à l'apprendre.

Le schéma de labellisation doit également être cohérent et pas trop spécifique.

Par exemple, il pourrait être très difficile d'apprendre à un modèle à prédire si quelque chose est un vêtement pour adulte ou un vêtement pour enfant en se basant sur le contexte. En revanche, prédire simplement le label "clothing" (vêtement) pourrait mieux fonctionner.
L'entity recognition de spaCy est utile pour ce genre de texte où le regex se fait avoir et matche "Ornellas" : "Charlotte d’Ornellas : Ce qui me choque le plus dans ces images là, c’est qu’un commissariat est attaqué pendant de longues minutes et qu’il n’y a aucune riposte"

Néanmoins c'est pour un second temps, d'abord je vais créer un dataset d'entraînement avec les villes faciles à trouver (ce qui te permettra d'avancer sur ta partie, aussi).
 
Last edited:

Oskar Schindler

SA- aspirant
Membre
Joined
Aug 14, 2020
Messages
97
Reaction score
244
Voilà un premier script python qui retourne 'results.json' avec [url, titre, [ville, localisation]] pour les articles de fdesouche. Si le regex ne fonctionne pas (nom de ville illisible, pas de nom de ville) la valeur [NaN, NaN] est renvoyée à la place de [ville, localisation] pour cet article.

Les noms d'articles et l'url est enregistrée sur ton disque par paquets de 100 pages au nom de 'data_xxx.json`. Tu peux modifier l'incrément ici :

Code:
    if page % 100 == 0:

        print(page)

        with open(f"data_{page}.json", 'w') as fp:

            json.dump(articles, fp)

            fp.close()
Python n'étant pas multithreadé...ça prend du temps.

Je dois un peu l'améliorer mais c'est ce que j'ai eu le temps de faire aujourd'hui.

J'ai refait le scraper d'adresse pour des questions de sécurité : j'ai réalisé que la liste la liste envoyée peut contenir des adresses malveillantes révèlant mon ip.

Tu devras probablement importer bs4 (pip install bs4) pour faire fonctionner le script. Les coordonnées n'ont pas été inversées.

Python:
import requests
from bs4 import BeautifulSoup
import re
import urllib.request
import json

start = 'https://www.fdesouche.com/category/securite/page/'
page = 2571
articles = dict()
n = 0

while page != 0:
 
    soup = BeautifulSoup(requests.get(f"{start}{page}/").text)
    title_box = soup.find_all("h2", {"class":"entry-title h3"})
 
    for title_link in title_box:
        title = title_link.select_one("a").text
        link = title_link.select_one("a")['href']
        articles[title] = link

    if page % 100 == 0:
        print(page)
        with open(f"data_{page}.json", 'w') as fp:
            json.dump(articles, fp)
            fp.close()
     
        articles = dict()
    page -= 1


with urllib.request.urlopen("https://geo.api.gouv.fr/communes?fields=nom,code,codesPostaux,codeDepartement,codeRegion,centre,population&format=json&geometry=centre")as url:
    data = json.loads(url.read().decode())  
 
comm_list = [commune['nom'] for commune in data ]

def position_geo_commune(url, title, liste_communes, donnees_geo):

    # On cherche toutes les mentions de communes :
    regex ="[A-Z]+[\w]*\S*\s*\([0-9]{0,2}\)|[A-Z]\w+(?=\s{1}\:)|(?:[A-Z]+[\w]*\S\s)+\([0-9]{0,2}\)|(?:[A-Z]+[\w]*[\S|\s])+(?=\s{1}\:)"

    # En priorité dans le titre...
    localisation = re.search(regex, title)

    # Sinon dans le texte, que l'on va chercher.
    if localisation is None:
     
        soup = BeautifulSoup(requests.get(url).text)
        article_html = BeautifulSoup(requests.get(url).text).\
                                    find('div', {"class":"entry-content"}).\
                                    findChildren()
     
        output = '. '.join([element.text for element in article_html])
        localisation = re.search(regex, output)

    if localisation is not None:
     
        # Isolation du nom de la commune et du département, si présent
        regex_nom_commune = "(?:[A-Z]+[\w]* ?-?)+(?! \()"

        localisation_commune = re.search(regex_nom_commune, localisation[0])[0].rstrip()
        regex_dept = "\d{2}"
     
        localisation_dept = re.search(regex_dept, localisation[0])
        if localisation_dept is not None :
            localisation_dept = localisation_dept[0]

        # On cherche l'index de la commune dans la liste téléchargée pour le récupérer ensuite dans le dictionnaire.
        index_list = list([i for i, x in enumerate(liste_communes) if x == localisation_commune])
     
        # Au cas où plusieurs communes existent avec le même nom, on tente de les départager avec le code département.
     
        if (localisation_dept is not None) and (len(index_list) > 1):
            for i in index_list:
                if data[i]['codeDepartement'] == localisation_dept[0]:
                    index_list = i
                    break
             

        # On retourne la position géo de la commune :
        if index_list is not None and len(index_list) > 0:
         
            return [localisation_commune, data[index_list[0]]['centre']['coordinates']]
     
        else :
            return ['NaN', 'NaN']
 
    else:
        return ['NaN','NaN']   
     
result = list()

for i in range(100,2500,100):
 
    with open(f"data_{i}.json") as file:
        fdesouche_dict = json.load(file)
        file.close()

    for titre, url in fdesouche_dict.items():
        x = [url, titre, position_geo_commune(url ,titre, comm_list, fdesouche_dict)]
        result.append(x)
     
with open('result.json','w') as file:
    json.dump(result, file)
    file.close()
 
Last edited:

Un Four Pour Tous

SA- aspirant
Membre
Joined
Aug 2, 2020
Messages
126
Reaction score
219
Python:
soup = BeautifulSoup(requests.get(
        f"{start}{page}/").text, features="html.parser")
Python-lint m'oblige d'ajouter features="html.parser" dans le constructeur BeautifulSoup
J'ai lu que Scrapy était plus performant que bs4, peut-être le remplacer à l'avenir.

Voici l'erreur que le script me retourne: https://pastebin.com/4P9PYc7y
 

Oskar Schindler

SA- aspirant
Membre
Joined
Aug 14, 2020
Messages
97
Reaction score
244
Python:
soup = BeautifulSoup(requests.get(
        f"{start}{page}/").text, features="html.parser")
Python-lint m'oblige d'ajouter features="html.parser" dans le constructeur BeautifulSoup
J'ai lu que Scrapy était plus performant que bs4, peut-être le remplacer à l'avenir.

Voici l'erreur que le script me retourne: https://pastebin.com/4P9PYc7y

Je vais regarder l'erreur, c'est étonnant, ça ne pose pas problème chez moi. J'espère avoir un peu de temps ce w.e pour améliorer le programme (il y a des bugs possibles et je dois ajouter un typage pour que ça soit plus clair).

Il y a plus de 45 000 articles à parser.

L'optimisation entre scrapy et bs4 n'est pas forcément nécessaire : une fois les articles extraits, il n'y a pas besoin de le refaire à nouveau. Je pense que le goulet d'étranglement vient surtout du regex et de la recherche dans le dictionnaire des communes.
 
Last edited:

Un Four Pour Tous

SA- aspirant
Membre
Joined
Aug 2, 2020
Messages
126
Reaction score
219
J'ai réussi à lancer la deuxième partie du code en ajoutant ceci au début:
Python:
import ssl

ssl._create_default_https_context = ssl._create_unverified_context
Après 4 heures d'exécution, j'ai annulé le processus. Je pense qu'il faudrait ajouter un indicateur afin de savoir si le code tourne toujours ou est bloqué.
 

Oskar Schindler

SA- aspirant
Membre
Joined
Aug 14, 2020
Messages
97
Reaction score
244
Une substring search cherche toutes les occurences d'une chaine de caractères précises (ex "Paris") tandis qu'un regex cherche toutes les occurrences d'un pattern général (ex : "[email protected]" ou dans notre cas "Xxxxx (xx) :").

Une solution pour accélerer le traitement est de lancer plusieurs programmes depuis un script bash, ce qui le fera tourner en parallèle. Je reviens vers toi lorsque j'ai fini.
 
Last edited:

Narbo du dimanche

SA- aspirant
Membre
Joined
May 2, 2020
Messages
84
Reaction score
338
Il y avait une carte des faits divers sur fds a une époque, certes l'édition était manuelle mais il y avait déjà une bonne base.
il y a 16000 articles avec catégorie, données géographiques et lien de la source.

IDETATDATEANNEEMOISTITRESRC_LIENSRC_NOMFD_CATGEO_CATGEO_INFOCOMDEPREGPAYSLATLNGGEOM
277041298507742131214960000020117Deux jeunes filles violées a la Fête de Bayonne (64)http://www.sudouest.fr/2011/08/01/fetes-de-bayonne-deux-jeunes-filles-ont-porte-plainte-pour-viols-465042-719.phpSud OuestVIOLundefinedundefined<Point><coordinates>undefined,undefined</coordinates></Point>
277041311665981131214960000020117Colombes: un dabiste forcé à porter des ‘explosifshttp://www.leparisien.fr/colombes-92700/colombes-un-dabiste-agresse-et-force-a-porter-une-ceinture-d-explosifs-01-08-2011-1551989.phpLe ParisienBRAQUAGEGEO_COM025;COLOMBES92;HAUTS-DE-SEINE11;ILE-DE-FRANCEFRANCE48.9311792.248307000000068<Point><coordinates>2.248307000000068,48.931179</coordinates></Point>
277041322065542131214960000020117Un ‘jeune’ s’en prend aux forces de l’ordre a Bollenehttp://www.ledauphine.com/actualite/2011/07/31/un-adolescent-de-15-ans-s-en-prend-aux-forces-de-l-ordreLe Dauphiné libéréARRESTATIONGEO_RUECITE LE VELODROME019;BOLLENE84;VAUCLUSE93;PROVENCE-ALPES-COTE D'AZURFRANCE44.28557474.751602800000001<Point><coordinates>4.751602800000001,44.2855747</coordinates></Point>
277041334139551131214960000020117Interpellé, il blesse un gendarme a Selens (02)http://www.lunion.presse.fr/article/faits-divers/gendarme-blesse-lors-dune-interpellationL'UnionARRESTATIONGEO_COM217;COUCY-LE-CHATEAU-AUFFRIQUE02;AISNE22;PICARDIEFRANCE49.520509999999993.3236659000000373<Point><coordinates>3.3236659000000373,49.52050999999999</coordinates></Point>
277041344847051131214960000020117Sa voiture incendiée devant son domicilehttp://www.lunion.presse.fr/article/aisne/sa-voiture-incendiee-devant-son-domicileL'UnionINCENDIEGEO_RUERUE DU CHATEAU305;FERE-EN-TARDENOIS02;AISNE22;PICARDIEFRANCE49.20727293.5167555000000448<Point><coordinates>3.5167555000000448,49.2072729</coordinates></Point>
277041355426241131214960000020117Nuit de tourmente pour des voleurs à Nanteshttp://www.nantes.maville.com/actu/actudet_-Nuit-de-tourmente-pour-les-voleurs-a-Nantes_loc-1893186_actu.HtmNantes ma villeVOLGEO_RUERUE DU TISSERAND162;SAINT-HERBLAIN44;LOIRE-ATLANTIQUE52;PAYS DE LA LOIREFRANCE47.2212256-1.6457103999999845<Point><coordinates>-1.6457103999999845,47.2212256</coordinates></Point>


Le dernier dump date de fin 2013.

Ça peut servir base pour un apprentissage supervisé.
 

Sylvester Staline

SA- soldat
Membre confirmé
Membre
Joined
Apr 27, 2020
Messages
301
Reaction score
734
Je suis en train de regarder en détail la doc de spaCy, si on a suffisamment de données labellisées pour entraîner un réseau de neurones ce devrait peut-être être possible.

Ce sera dans un second temps, mais dans ce cas on peut appeler les membres du forum à nous aider (repérer les mots utiles dans le texte) et utiliser les données pour entraîner le modèle.

Laisse-moi un peu de temps stp, c'est assez touffu mais si on y arrive ça peut être vraiment très efficace.

En attendant, une image :

View attachment 31185
J'ai pas trop suivi le topic mais j'adore ta photo. notre rêve à tous ici, notre paradis Blanc !
 

Un Four Pour Tous

SA- aspirant
Membre
Joined
Aug 2, 2020
Messages
126
Reaction score
219

st-nazi

SA- aspirant
Membre
Joined
Apr 4, 2020
Messages
37
Reaction score
80
L'optimisation entre scrapy et bs4 n'est pas forcément nécessaire.
En fait, scrapy est tres puissant pour regler precisement un scraping sans reinventer la roue: gestion des redirections, nombre de threads, taille du process, attente entre les retries, algorithmes anti-blacklisting, et plein de parametres dont vous ignoriez l'existence.
Mais scrapy est capricieux. Scrapy exige d'etre dans le thread python principal, il lui faut son process a lui. Ce qui complique la recuperation des logs et le debugging en general. Il est aussi assez violent avec la base de donnees donc un sqlite se retrouve vite en vrac. Et puis pour resourdre certains bugs, il faut comprendre la plate-forme sous-jacente qu'est Twisted et c'est assez douloureux.
Bref je vous le conseille, mais seulement si l'optimisation du scraping devient critique.
PS. excellente idee que ce thread, j'approuve totalement
 

Oskar Schindler

SA- aspirant
Membre
Joined
Aug 14, 2020
Messages
97
Reaction score
244
J'ai couché ma femme, je m'y remet 😅

Le code tentait de requêter fdesouche à la recherche du nom de la ville dans le texte de l'article, ce qui prend du temps et crée un risque de bug. Partie inutile pour l'instant vu que le but est simplement de créer une première liste pour faire de l'apprentissage supervisé.

Par ailleurs, les TOM n'ont pas de géolocalisation, ce qui crée des problèmes. Tu peux voir la liste ici :

Python:
import re
import urllib.request, json

with urllib.request.urlopen("https://geo.api.gouv.fr/communes?fields=nom,code,codesPostaux,codeDepartement,codeRegion,centre,population&format=json&geometry=centre")as url:
    data = json.loads(url.read().decode())

for dict in data:
    try :
        if dict['centre'] is None:
            print(dict)
    except KeyError:
        print(dict)

Voila le fichier final, qui tourne chez moi en moins de 3 minutes. Si tu as déjà les fichiers data_xxx.json dans le dossier d'exécution, tu peux juste coller la seconde partie dans ton fichier .py :

Python:
############## Partie 1 : Récupération des urls et des titres ################
import requests
from bs4 import BeautifulSoup
import json

start = 'https://www.fdesouche.com/category/securite/page/'
page = 2571
articles = dict()
n = 0

while page != 0:

    soup = BeautifulSoup(requests.get(f"{start}{page}/").text)
    title_box = soup.find_all("h2", {"class":"entry-title h3"})

    for title_link in title_box:
        title = title_link.select_one("a").text
        link = title_link.select_one("a")['href']
        articles[title] = link

    if page % 100 == 0:
        print(page)
        with open(f"data_{page}.json", 'w') as fp:
            json.dump(articles, fp)
            fp.close()
  
        articles = dict()
    page -= 1

############# Partie 2 : Extraction des villes et de leur localisation ##########
import re
import urllib.request, json
import re

with urllib.request.urlopen("https://geo.api.gouv.fr/communes?fields=nom,code,codesPostaux,codeDepartement,codeRegion,centre,population&format=json&geometry=centre")as url:
    data = json.loads(url.read().decode())

comm_list = [commune['nom'] for commune in data ]

def position_geo_commune(url, title, liste_communes, donnees_geo):

    # On cherche toutes les mentions de communes :
    regex ="[A-Z]+[\w]*\S*\s*\([0-9]{0,2}\)|[A-Z]\w+(?=\s{1}\:)|(?:[A-Z]+[\w]*\S\s)+\([0-9]{0,2}\)|(?:[A-Z]+[\w]*[\S|\s])+(?=\s{1}\:)"

    # En priorité dans le titre...
    localisation = re.search(regex, title)

    # Sinon dans le texte, que l'on va chercher.
    if localisation is None:
  
        #soup = BeautifulSoup(requests.get(url).text)
        #article_html = BeautifulSoup(requests.get(url).text).\
                                    #find('div', {"class":"entry-content"}).\
                                    #findChildren()
  
        #output = '. '.join([element.text for element in article_html])
        #localisation = re.search(regex, output)
        return 'NaN'

    else:
  
        # Isolation du nom de la commune et du département, si présent
        regex_nom_commune = "(?:[A-Z]+[\w]* ?-?)+(?! \()"

        localisation_commune = re.search(regex_nom_commune, localisation[0])[0].rstrip()
        regex_dept = "\d{2}"
  
        localisation_dept = re.search(regex_dept, localisation[0])
        if localisation_dept is not None :
            localisation_dept = localisation_dept[0]

        # On cherche l'index de la commune dans la liste téléchargée pour le récupérer ensuite dans le dictionnaire.
        index_list = list([i for i, x in enumerate(liste_communes) if x == localisation_commune])
  
        # Au cas où plusieurs communes existent avec le même nom, on tente de les départager avec le code département.
  
        if (localisation_dept is not None) and (len(index_list) > 1):
            for i in index_list:
                if data[i]['codeDepartement'] == localisation_dept[0]:
                    index_list = i
                    break
          

        # On retourne la position géo de la commune :
        try:
            if index_list is not None and len(index_list) > 0:

                return [localisation_commune, data[index_list[0]]['centre']['coordinates']]
  
        except KeyError:
      
            return 'NaN'

     else:
        return 'NaN'

result = list()
total = 0
k = 0

import time
start_time = time.time()

for i in range(100,2500,100):

    with open(f"data_{i}.json") as file:
        fdesouche_dict = json.load(file)
        file.close()

    for titre, url in fdesouche_dict.items():
        x = [url, titre, position_geo_commune(url ,titre, comm_list, fdesouche_dict)]
        result.append(x)

        if k%1000 == 0:
            print(k)
        k+=1


with open('result.json','w') as file:
    json.dump(result, file)
    file.close()

print("--- %s seconds ---" % (time.time() - start_time))
Tu peux coller le code suivant pour nettoyer les résultats dans un fichier `cleaned_results.json`:
Code:
with open('result.json', 'r') as file:
    uncleaned_results = json.load(file)
    file.close()
  
uncleaned_results = [entry for entry in uncleaned_results if entry[2] is not None]
cleaned_results = [entry for entry in uncleaned_results if entry[2] != 'NaN']

with open('cleaned_results.json', 'w') as file:
    json.dump(cleaned_results, file)
    file.close()
Au final j'ai 17 447 articles géolocalisés. Pas mal pour commencer !
 
Last edited:

Oskar Schindler

SA- aspirant
Membre
Joined
Aug 14, 2020
Messages
97
Reaction score
244
Merci pour ton retour St-nazi, je vais regarder un peu scrapy, ça a l'air très intéressant. Je m'y connais mal en programmation asynchrone, si jamais tu as des ressources intéressantes, n'hésite pas à partager.

Et sinon, tous les démocrates sont les bienvenus pour nous aider ! Si tu t'y connais en python, tu peux :

- Regarder pourquoi le scraper qui va chercher dans le texte foire :
Python:
    # Sinon dans le texte, que l'on va chercher.
    if localisation is None:
     
        #soup = BeautifulSoup(requests.get(url).text)
        #article_html = BeautifulSoup(requests.get(url).text).\
                                    #find('div', {"class":"entry-content"}).\
                                    #findChildren()
     
        #output = '. '.join([element.text for element in article_html])
        #localisation = re.search(regex, output)
- Améliorer le regex qui ne chope pas tout apparemment.
Code:
"[A-Z]+[\w]*\S*\s*\([0-9]{0,2}\)|[A-Z]\w+(?=\s{1}\:)|(?:[A-Z]+[\w]*\S\s)+\([0-9]{0,2}\)|(?:[A-Z]+[\w]*[\S|\s])+(?=\s{1}\:)"
Et si tu as des idées en plus, dis-nous !
 

Narbo du dimanche

SA- aspirant
Membre
Joined
May 2, 2020
Messages
84
Reaction score
338
Qui a redigé ce fichier ?
Je n'étais pas le principal producteur de contenu, seulement le réalisateur de l’outil.

Génial ! Tu l'as trouvé où ?
A ton avis ;)

J'ai repris les csv pour nettoyer un peu tout ça et vous préparer un dump postgres.
Vous trouverez les tables
  • article: titre, lien, catégorie, lat/lon, etc
  • content: texte ou image liés à l'article
  • cog: le code officiel géographique
  • insee: données insee (pop, emploi, revenu, etc)
  • annuaire: info mairie, etc
https://file.io/RB2MCfeYvbVB
 

Un Four Pour Tous

SA- aspirant
Membre
Joined
Aug 2, 2020
Messages
126
Reaction score
219
Au final j'ai 17 447 articles géolocalisés. Pas mal pour commencer !
C'est OK le code fonctionne chez moi.

Donc pour le frontend, je pars sur cette structure de donnée ?

Peut être ajouter par la même occasion, les plus de 2100 mosqués avec un toggle boutton pour les afficher ou les cacher ?
Avec le nom de celles-ci et la traduction en Français ?
 
Last edited:

Oskar Schindler

SA- aspirant
Membre
Joined
Aug 14, 2020
Messages
97
Reaction score
244
Donc pour le frontend, je pars sur cette structure de donnée ?
Oui, ce sera possible pour toi ensuite de rajouter des données ? Actuellement on a :

[url, titre, [commune, [long, lat]] mais on pourra passer à [url, titre, [commune, [long, lat], date, catégorie] par exemple.

J'actualise le code ce soir pour extraire la date de l'url, c'est possible, par exemple :

"https://www.fdesouche.com/2020/02/10/le-maire-de-moissac-82-appelle-au-calme-16-voitures-dont-de-grosses-berlines-toutes-immatriculees-en-bulgarie-degradees/"
 

Un Four Pour Tous

SA- aspirant
Membre
Joined
Aug 2, 2020
Messages
126
Reaction score
219
Aucun problème, je modifirai.

Je suis entrain de scrapper les mosquées de fr.w/i/k/i/p/e/d/i/a/.o/r/g/wiki/Liste_de_mosqu%C3%A9es_de_France.

Puis je commence à afficher les points sur leaflet.
 
Top