Esempio n. 1
0
def get_list_version():
    """Crée la collection de stockage des versions du scraper si elle n'existe pas.
	Récupère les résultats de tests finaux et les traite pour générer de nouvelles
	règles. Une nouvelle version du scraper est alors créée pour utiliser ces règles. 
	Toutes les versions sont envoyées à la page de lancement du scrape et sont
	proposées à l'utilisateur.
	"""

    dbfinder = mongo.MongoLoad(proj={'search_version': 1, '_id': 0})

    if not dbfinder.mongocheck('Versions_Scrape'):
        version_doc = mongo.MongoSave([{
            'search_version': '1.00',
            'submissions_scraped': 0,
            'accuracy': 0
        }])
        version_doc.storeindb('Versions_Scrape', search_version='D')

    proc.create_rule()

    version_list = []
    for doc in dbfinder.retrieve('Versions_Scrape'):
        version_list.append(doc['search_version'])

    return jsonify(version_list)
Esempio n. 2
0
def inscription():	
	if request.method == 'POST':
		pseudo = request.form['pseudo']
		email = request.form['email']
		password = request.form['password']
		password_confirmation = request.form['password_confirmation']
		is_admin = ('admin' in request.form)

		existing_name = list(mongo.MongoLoad({'pseudo': pseudo}).retrieve('users_accounts'))
		existing_mail = list(mongo.MongoLoad({'email': email}).retrieve('users_accounts'))

		if existing_name:
			error = 'Ce pseudo est déjà utilisé, veuillez en choisir un autre.'
		elif existing_mail:
			error = 'Cette adresse mail est déjà utilisée, veuillez vous-connectez.'
		elif password != password_confirmation:
			error = 'Les deux mots de passes sont différents.'

		else:
			#Cookies
			session['username'] = pseudo
			session['admin?'] = is_admin   

			#Cryptage du mot de passe
			hashpass= bcrypt.hashpw(password.encode('utf-8'),bcrypt.gensalt())
			
			#Stockage dans mongoDB
			dic = {
					'pseudo': pseudo,
					'email': email,
					'password': hashpass
				  }
			if session['admin?']:
				dic['admin?'] = 'YES'
				db_tester(session['username']) #Création d'un profil testeur
			else:
				dic['admin?'] = 'NO'
			documents = mongo.MongoSave([dic])
			documents.storeindb('users_accounts',pseudo='A',email='A')

			#redirection vers la map
			return redirect(url_for('map'))  

		return render_template('inscription.html',error=error)

	elif 'username' in session:
		return redirect(url_for('map'))

	else:
		return render_template('inscription.html')
Esempio n. 3
0
def db_tester(username):
	"""A partir de l'inscription d'un utilisateur en tant qu'admin, la fonction crée
	un profil testeur pour cet utilisateur dans la collection 'Testeurs' de la base
	de données. Chaque testeur reçoit un code unique qui sert à identifier les documents
	de 'Resultats_RGN' qu'il/elle doit tester.
	"""

	next_code = 0
	if mongo.Mongo.mongocheck('Testeurs'):
		next_code = mongo.Mongo.mongocount('Testeurs')

	dbloader = mongo.MongoSave([{'user_id': username, 'code': next_code, 'num_answers': 0}])
	dbloader.storeindb('Testeurs',user_id='A')
	print('Profil testeur créé.')
Esempio n. 4
0
def scraping():
    """Si l'utilisateur n'a pas demandé un scraping, recherche de documents du pays sélectionné
	dans la base de données; ces documents et leurs liens vers les photos seront renvoyés.
	Si l'utilisateur a demandé un scraping, ou s'il n'y a pas ou pas assez de documents du pays
	sélectionné dans la base de données, configuration et lancement du scrape sur Reddit, puis
	étiquetage des titres des soumissions résultats par TreeTagger, et analyse des étiquettes
	pour obtenir une liste de lieux potentiels.
	Ces lieux sont recherchés sur geonames. Les résultats de cette dernière recherche sont chargés
	dans deux dictionnaires, l'un pour l'affichage des photos sur le site et l'autre pour stocker
	les résultats dans la base de données sur mongoDB.
	NB: le scraping tente toujours d'obtenir de nouvelles photos (absentes de mongoDB).
	"""

    #Configuration Geoscape
    geokey = current_app.config['GEOKEY']
    geoauth = current_app.config['GEOAUTH']

    #Paramètres de la requête Javascript
    rgnversion = request.args.get('search_version')
    country = request.args.get('country')
    country_code = request.args.get('country_code')
    limit = int(request.args.get('nombre_image'))
    scrape_requested = True if request.args.get(
        'scraping') == 'true' else False

    #Dico de résultats pour l'affichage sur le site
    search_res = geo.GeoQuery(geokey, geoauth, country, country_code, 'E')
    dic_results = {
        'head': {
            'total': 0,
            'country': {
                'name': country,
                'lng': search_res.result.lng,
                'lat': search_res.result.lat
            }
        },
        'results': []
    }
    #Liste de chargement pour la base de données
    database_list = []

    if scrape_requested:  #On ne charge que les img_url
        load_arg = {'img_url': 1, '_id': 0}
    else:  #On charge le document pour l'affichage
        load_arg = {
            'scraped_title': 0,
            'location_list': 0,
            'feature_class': 0,
            'testers': 0,
            '_id': 0
        }

    existing_urls = []
    check_db = mongo.Mongo.mongocheck('Resultats_RGN')

    #Initialisation de la collection des résultats si elle n'existe pas
    if not check_db:
        dbstart = mongo.MongoSave([{
            'key':
            'Initialisation de la collection Resultats_RGN.'
        }])
        dbstart.storeindb('Resultats_RGN', img_url='A', search_version='D')
        dbstart.nonunique_index('Resultats_RGN',
                                country='A',
                                search_version='D')

    #Les documents pris dans la base de données sont chargés dans le dictionnaire de résultats
    else:
        dbfinder = mongo.MongoLoad(
            {
                'search_version': rgnversion,
                'country': country
            }, load_arg)
        for doc in dbfinder.retrieve('Resultats_RGN', limit=limit):
            if not scrape_requested:
                dic_results['head']['total'] += 1
                dic_results['results'].append(doc)
            existing_urls.append('-url:' + doc['img_url'])

    if scrape_requested or dic_results['head']['total'] < limit:
        #Configuration recherche reddit, profil chargé depuis praw.ini
        reddit = praw.Reddit('current_user')

        target_sub = reddit.subreddit('EarthPorn')
        query = country if country != 'United States' else 'USA'
        print(
            '\033[92m' + target_sub.display_name + '\033[0m'
            '\nRésultats de recherche pour les soumissions reddit avec:',
            query, '\n')

        #Exclure les documents déjà récupérés
        user_limit = limit

        if len(query) + len(existing_urls) + sum(
                len(url) for url in existing_urls) <= 512:
            query += (' ' + ' '.join(existing_urls)).rstrip()
            limit -= dic_results['head']['total']
        else:  #512 caractères max dans une requête Reddit
            limit = 1000  #Max permis par Reddit

        existing_urls = [url[5:] for url in existing_urls]

        #Config TreeTagger. Le dossier Treetagger doit être dans le dossier d'où le programme est exécuté
        if sys.platform.startswith('linux'):
            reddit_tagger = TreeTagger(TAGLANG='en',
                                       TAGDIR=join(getcwd(), 'Treetagger',
                                                   'TreeTagger_unix'))
        elif sys.platform.startswith('win'):
            reddit_tagger = TreeTagger(TAGLANG='en',
                                       TAGDIR=join(getcwd(), 'Treetagger',
                                                   'TreeTagger_windows'))
        else:
            sys.exit('Système d\'exploitation non compatible avec Geoscape.')

        #Résultats de la recherche dans le subreddit
        test_posts = target_sub.search(query, limit=limit)

        for post in test_posts:
            try:
                attempt = post.url
            except prawcore.exceptions.NotFound:
                continue  #Problème avec la photo; éliminé

            if post.url in existing_urls:
                continue  #Déjà stocké dans la base de données; éliminé

            if search('\W' + country + '\W',
                      post.title):  #Pays comme mot distinct
                #Saute aux plus une fois des caractères entre [] ou () au début du texte et s'arrête au premier [ ou (
                res = search('^(?:[\[(].*[\])])?([^\[(]+)', post.title)
                if (res):
                    print(res.group(1))

                    #Tagging: génère une liste de triplets: (word=..., pos=..., lemma=...)
                    reddit_tags = make_tags(reddit_tagger.tag_text(
                        res.group(1)),
                                            exclude_nottags=True)

                    #Le nom du pays est exclu des lieux potentiels; rajouté seulement en dernier recours
                    country_split = country.casefold().split(' ')
                    size = len(country_split)
                    indexes = []
                    if size > 1:
                        name_tags = [t[0].casefold() for t in reddit_tags]
                        for window in enumerate(windowed(name_tags, size)):
                            if all(window[1][i] == country_split[i]
                                   for i in range(size)):
                                indexes.extend([
                                    i
                                    for i in range(window[0], window[0] + size)
                                ])

                    for index, tag in enumerate(reddit_tags):
                        if tag[1] == 'NP':  #Tag nom propre sous Windows
                            reddit_tags[index] = (tag[0], 'NP0', tag[2])
                        if tag[0].casefold() == country.casefold(
                        ) or index in indexes:
                            reddit_tags[index] = (tag[0], 'CTY', tag[2])
                    pprint(reddit_tags)

                    #Recherche des lieux potentiels, avec stocké entre les lieux le nombre de mots non choisis
                    location_list = location_finder(country, rgnversion,
                                                    reddit_tags)

                    print('Lieux trouvés:', end='')
                    print(location_list, '\n')

                    #Geonames
                    date = gmtime(post.created_utc)
                    dic_mongo = {
                        'link': 'https://www.reddit.com' + post.permalink,
                        'img_url': post.url,
                        'search_version': rgnversion,
                        'country': country,
                        'country_code': country_code,
                        'scraped_title': res.group(1).strip(),
                        'text': post.title,
                        'tag_list': reddit_tags,
                        'location_list': location_list,
                        'date': {
                            'year': date.tm_year,
                            'month': date.tm_mon,
                            'day': date.tm_mday,
                            'hour': date.tm_hour,
                            'min': date.tm_min,
                            'sec': date.tm_sec
                        }
                    }

                    try:
                        attempt = post.author.icon_img
                    except prawcore.exceptions.NotFound:
                        pass
                    else:
                        dic_mongo['author'] = {
                            'name':
                            post.author.name,
                            'icon':
                            post.author.icon_img,
                            'profile':
                            'https://www.reddit.com/user/' + post.author.name
                        }
                    """ R: recherche standard
						RF: recherche fuzzy
						E: recherche exacte
						EH: recherche exacte sur ensembles humains
						EN: recherche exacte sur ensembles naturels
					"""

                    placefinder = geo.LocationList(country_code, location_list)
                    geo_res = placefinder.geo_search(geokey, geoauth, 'EN EH',
                                                     'R')  #Objet GeoQuery

                    #En dernier recours, le pays lui-même s'il est dans le titre
                    if geo_res.result is None and country in res.group(1):
                        placefinder.reinit(country_code, [country])
                        geo_res = placefinder.geo_search(geokey, geoauth, 'E')

                    if geo_res.result is not None:
                        dic_results['head']['total'] += 1
                        print('Résultat GeoNames:',
                              geo_res.result.address,
                              end='')
                        print('. Après', placefinder.counter, 'requêtes.')

                        dic_mongo['name'] = geo_res.result.address  #Nom
                        dic_mongo['lng'] = geo_res.result.lng
                        dic_mongo['lat'] = geo_res.result.lat
                        dic_mongo[
                            'feature_class'] = geo_res.result.feature_class
                        dic_mongo['location'] = geo_res.location

                        dic_results['results'].append(dic_mongo)

                        dic_tostore = deepcopy(dic_mongo)
                        database_list.append(dic_tostore)

                        user_limit -= 1
                        if not user_limit:
                            break

                print('\n###############')

        #Chargement dans la base de données des documents générés par le scrape
        documents = mongo.MongoSave(database_list)
        documents.storeindb('Resultats_RGN')

    return jsonify(dic_results)
Esempio n. 5
0
def send_results():
    """Réception des résultats du test-expert et stockage dans la base de données;
	décrémentation de la champ 'testers' des documents qui viennent d'être testés
	de la collection 'Resultats_RGN', et incrémentation du champ 'num_answers' du
	testeur dans la collection 'Testeurs'.
	Si tous les tests sur un document ont été réalisés, lance la sélection des
	résultats finaux à partir des choix des testeurs, puis stocke ce résultat final
	dans la collection 'Resultats_Final_Expert_1'.
	"""

    response = json.loads(request.data.decode('utf-8'))
    tester = session['username']
    version = response['search_version']
    test_results = response['results']
    url_list = response['img_url']

    result_docs = []
    for url, test_item in zip(url_list, test_results):
        if test_item[
                'lieux_choisis']:  #Si la liste est vide, le testeur n'a pas su répondre
            result_docs.append({
                'tester': tester,
                'search_version': version,
                'img_url': url,
                'locations_selected': test_item['lieux_choisis'],
                'sufficient': test_item['suffisant'],
                'geoname': test_item['geonames_chosen_result']
            })

    documents = mongo.MongoSave(result_docs)
    documents.storeindb('Resultats_Test_Expert_1',
                        tester='A',
                        img_url='A',
                        search_version='D')

    update = mongo.MongoUpd({'user_id': tester}, {'$inc': {'num_answers': 1}})
    update.singleval_upd('Testeurs')

    dbfinder = mongo.MongoLoad({'user_id': tester}, {'code': 1, '_id': 0})
    test_code = next(dbfinder.retrieve('Testeurs'))['code']

    dbfinder.reinit({
        'img_url': {
            '$in': url_list
        },
        'search_version': version
    }, {
        'testers': 1,
        '_id': 0
    })
    sum_list = []
    done_list = []
    for url, doc in zip(url_list, dbfinder.retrieve('Resultats_RGN')):
        tester_sum = int.from_bytes(
            doc['testers'],
            byteorder='big')  #classmethod, appelée sans instance
        tester_sum &= (~(1 << test_code))

        if tester_sum == 0:
            done_list.append(url)
            bytesize = 1
        else:
            bytesize = floor(log2(tester_sum) / 8) + 1
        tester_sum = tester_sum.to_bytes(bytesize, byteorder='big')
        sum_list.append(tester_sum)

    update.reinit({
        'img_url': '',
        'search_version': version
    }, {'$set': {
        'testers': ''
    }}, url_list, sum_list)
    update.multval_upd('Resultats_RGN', 'img_url')

    if done_list:
        final_list = proc.select_results(version, done_list)
        documents.reinit(final_list)
        documents.nonunique_index('Resultats_Final_Expert_1', processed='A')
        documents.storeindb('Resultats_Final_Expert_1',
                            img_url='A',
                            search_version='D')

    return jsonify(status='OK')
Esempio n. 6
0
def create_rule():
    """Recherche d'erreurs et création de nouvelles règles à partir de celles-ci.
	Récupère dans la base de données les résultats finaux des tests si le champ
	'sufficient' est vrai, c'est-à-dire s'il est possible de récupérer le lieu dans le
	titre.
	La liste des lieux potentiels est converti en liste de mots distincts correctement
	indiciés. Cette liste est ensuite fusionnée avec les listes de résultat du test et
	d'étiquettes TreeTagger.
	Sont extraites de cette liste de comparaison les sous-listes contenant les erreurs
	détectées et les noms propres voisins.
	Les nouvelles règles sont construites à partir de ces sous-listes.
	"""

    dbfinder = mongo.MongoLoad(proj={'search_version': 1, '_id': 0})
    max_version = max(doc['search_version']
                      for doc in dbfinder.retrieve('Versions_Scrape'))
    next_version = str(float(max_version) + 0.01)

    dbfinder.reinit({
        'processed': {
            '$eq': False
        },
        'sufficient': {
            '$eq': True
        }
    }, {
        'search_version': 0,
        '_id': 0
    })

    rule_list = []
    for doc in dbfinder.retrieve('Resultats_Final_Expert_1'):
        words = chain(
            *(loc.split(' ') if type(loc) == str else [0 for i in range(loc)]
              for loc in doc['location_list']))

        tags = doc['tag_list']
        comp_list = list(
            zip(doc['locations_selected'], words, (t[1] for t in tags),
                (t[0] for t in tags)))

        bad_results = []
        good_neighbors = []
        err = []
        i = 0

        while i < len(comp_list):
            if comp_list[i][0] and comp_list[i][0] == bool(comp_list[i][1]):
                good_neighbors.append(
                    list(takewhile(lambda x: x[0], comp_list[i:])))
                i += len(good_neighbors)

            if i < len(comp_list) and comp_list[i][0] != bool(comp_list[i][1]):
                errpos = len(good_neighbors)
                errtype = comp_list[i][0]
                err = list(
                    takewhile(lambda x: x[0] != bool(x[1]) and x[0] == errtype,
                              comp_list[i:]))
                badlen = len(err)

                err.extend(
                    list(takewhile(lambda x: x[0], comp_list[i + badlen:])))
                good_neighbors.extend(err)

                bad_results.append({
                    'errpos': errpos,
                    'errlen': badlen,
                    'errlist': good_neighbors,
                    'errtype': errtype
                })
                good_neighbors = []
                err = []
                i += badlen

            else:
                good_neighbors.clear()
                i += 1

        for res in bad_results:
            errpos = res['errpos']
            errlen = res['errlen']
            errlist = res['errlist']
            errtype = res['errtype']
            rule_vect = errlist[errpos:errpos + errlen]
            take = 0 if errtype else 'X'

            if len(errlist) - errlen > 0:
                take = 2 if errtype else 'X'

                if errpos == len(errlist) - 1:
                    rule_vect = errlist[:errpos]
                    take = 1 if errtype else 'R'

                elif errpos == 0:
                    rule_vect = errlist[errpos + errlen:]
                    take = -1 if errtype else 'L'

            new_rule = {
                'country': doc['country'],
                'expr': ' '.join(i[3] for i in rule_vect),
                'pos': [i[2] for i in rule_vect],
                'take': take,
                'search_version': next_version,
                'img_url': doc['img_url'],
                'verified': False
            }
            rule_list.append(new_rule)

    if rule_list:
        db = mongo.MongoSave(rule_list)
        db.nonunique_index('Nouvelles_Regles', country='A', search_version='D')
        db.storeindb('Nouvelles_Regles',
                     country='A',
                     expr='A',
                     pos='A',
                     take='A')

        db.reinit([{
            'search_version': next_version,
            'submissions_scraped': 0,
            'accuracy': 0
        }])
        db.storeindb('Versions_Scrape')

        upd = mongo.MongoUpd({'processed': {
            '$eq': False
        }}, {'$set': {
            'processed': True
        }})
        upd.singleval_upd('Resultats_Final_Expert_1')