Compare commits
	
		
			8 Commits
		
	
	
		
			feat/rest-
			...
			feat-parse
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					10422d0499 | ||
| 
						 | 
					51d71b748f | ||
| 
						 | 
					2653d088c4 | ||
| 
						 | 
					262bf0c1b1 | ||
| 
						 | 
					c1073451fd | ||
| 
						 | 
					0b9fe19b3a | ||
| 
						 | 
					2feb6219f7 | ||
| 
						 | 
					b56cbf66a0 | 
							
								
								
									
										43
									
								
								experimentations/get_acolab_events.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										43
									
								
								experimentations/get_acolab_events.py
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,43 @@
 | 
				
			|||||||
 | 
					#!/usr/bin/env python3
 | 
				
			||||||
 | 
					# coding: utf-8
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					import json
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# getting the name of the directory
 | 
				
			||||||
 | 
					# where the this file is present.
 | 
				
			||||||
 | 
					current = os.path.dirname(os.path.realpath(__file__))
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					# Getting the parent directory name
 | 
				
			||||||
 | 
					# where the current directory is present.
 | 
				
			||||||
 | 
					parent = os.path.dirname(current)
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					# adding the parent directory to 
 | 
				
			||||||
 | 
					# the sys.path.
 | 
				
			||||||
 | 
					sys.path.append(parent)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from src.agenda_culturel.import_tasks.downloader import *
 | 
				
			||||||
 | 
					from src.agenda_culturel.import_tasks.extractor import *
 | 
				
			||||||
 | 
					from src.agenda_culturel.import_tasks.importer import *
 | 
				
			||||||
 | 
					from src.agenda_culturel.import_tasks.custom_extractors import *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == "__main__":
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    u2e = URL2Events(SimpleDownloader(), acolab.CExtractor())
 | 
				
			||||||
 | 
					    url = "https://forum.acolab.fr/c/genericactivity/ouverture/15.rss"
 | 
				
			||||||
 | 
					    url_human = "https://forum.acolab.fr/c/genericactivity/ouverture/15"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        events = u2e.process(url, url_human, cache = "cache-acolab.html", default_values = {"location": "AcoLab"}, published = True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        exportfile = "events-acolab.json"
 | 
				
			||||||
 | 
					        print("Saving events to file {}".format(exportfile))
 | 
				
			||||||
 | 
					        with open(exportfile, "w") as f:
 | 
				
			||||||
 | 
					            json.dump(events, f, indent=4, default=str)
 | 
				
			||||||
 | 
					    except Exception as e:
 | 
				
			||||||
 | 
					        print("Exception: " + str(e))
 | 
				
			||||||
							
								
								
									
										205
									
								
								src/agenda_culturel/import_tasks/custom_extractors/acolab.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										205
									
								
								src/agenda_culturel/import_tasks/custom_extractors/acolab.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,205 @@
 | 
				
			|||||||
 | 
					import re
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from datetime import datetime, date, timedelta
 | 
				
			||||||
 | 
					from bs4 import BeautifulSoup, MarkupResemblesLocatorWarning
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from ..extractor import *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from celery.utils.log import get_task_logger
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					logger = get_task_logger(__name__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Timeslot:
 | 
				
			||||||
 | 
					    def __init__(self, start_time, end_time):
 | 
				
			||||||
 | 
					        self.start_time = start_time
 | 
				
			||||||
 | 
					        self.end_time = end_time
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def merge(self, hours):
 | 
				
			||||||
 | 
					        self.start_time = min(self.start_time, hours.start_time)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if not hours.end_time is None:
 | 
				
			||||||
 | 
					            if not self.end_time is None:
 | 
				
			||||||
 | 
					                self.end_time = max(self.end_time, hours.end_time)
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                self.end_time = hours.end_time
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class CExtractor(Extractor):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    title_ouverture = 'Permanence AcoLab'
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    def __init__(self):
 | 
				
			||||||
 | 
					        super().__init__()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def find_date(text):
 | 
				
			||||||
 | 
					        splited_text = text.split(' ')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if len(splited_text) < 3:
 | 
				
			||||||
 | 
					            return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        month = Extractor.guess_month(splited_text[1])
 | 
				
			||||||
 | 
					        if month is None:
 | 
				
			||||||
 | 
					            return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        year = splited_text[2]
 | 
				
			||||||
 | 
					        if not year.isnumeric():
 | 
				
			||||||
 | 
					            return None
 | 
				
			||||||
 | 
					        year = int(year)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return (year, month)
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    def find_hours(text):
 | 
				
			||||||
 | 
					        text = re.split(r"[ -/=>]+", text)
 | 
				
			||||||
 | 
					        text = [Extractor.parse_french_time(k) for k in text]
 | 
				
			||||||
 | 
					        text = [k for k in text if not k is None]
 | 
				
			||||||
 | 
					        match len(text):
 | 
				
			||||||
 | 
					            case 0:
 | 
				
			||||||
 | 
					                return None
 | 
				
			||||||
 | 
					            case 1:
 | 
				
			||||||
 | 
					                return Timeslot(text[0], None)
 | 
				
			||||||
 | 
					            case 2:
 | 
				
			||||||
 | 
					                return Timeslot(text[0], text[1])
 | 
				
			||||||
 | 
					            case _:
 | 
				
			||||||
 | 
					                return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    def is_nickname(text):
 | 
				
			||||||
 | 
					        return '@' in text
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    def is_canceled(text):
 | 
				
			||||||
 | 
					        text = Extractor.remove_accents(text.lower())
 | 
				
			||||||
 | 
					        words = ['annule']
 | 
				
			||||||
 | 
					        for word in words:
 | 
				
			||||||
 | 
					            if word in text:
 | 
				
			||||||
 | 
					                return True
 | 
				
			||||||
 | 
					        return False
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    def find_timeslot(text):
 | 
				
			||||||
 | 
					        text = re.sub(' +', ' ', text).split(' ')
 | 
				
			||||||
 | 
					        if len(text) < 3:
 | 
				
			||||||
 | 
					            return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        day_name = text[0]
 | 
				
			||||||
 | 
					        day_num = text[1]
 | 
				
			||||||
 | 
					        hours = text[2]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if not Extractor.guess_day_name(day_name):
 | 
				
			||||||
 | 
					            return None
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        day_num = [c for c in re.split(r'\D+', day_num) if c != ""]
 | 
				
			||||||
 | 
					        if len(day_num) == 0:
 | 
				
			||||||
 | 
					            return None
 | 
				
			||||||
 | 
					        day_num = int(day_num[0])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        hours = CExtractor.find_hours(hours)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if hours is None:
 | 
				
			||||||
 | 
					            return None
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        return (day_num, hours)
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #['Samedi 12', '@Manon', '14:30-18:00', 'Dimanches 13', '@gaeldu63', '14h30 (j utilise la scie a format)']
 | 
				
			||||||
 | 
					    #['Mercredi 16 :']
 | 
				
			||||||
 | 
					    #['Samedi 19', '@Manon', '14:30-18:00']
 | 
				
			||||||
 | 
					    #['Samedi 22', ': ANNULE', '@Manon', '14h30 - 18h00']
 | 
				
			||||||
 | 
					    def find_timeslots(p):
 | 
				
			||||||
 | 
					        result = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        date = None
 | 
				
			||||||
 | 
					        slot = None
 | 
				
			||||||
 | 
					        is_open = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # for each element in the paragraph
 | 
				
			||||||
 | 
					        for e in p.stripped_strings:
 | 
				
			||||||
 | 
					            day = CExtractor.find_timeslot(e)
 | 
				
			||||||
 | 
					            if not day is None:
 | 
				
			||||||
 | 
					                print('on a une date', day)
 | 
				
			||||||
 | 
					                if not date is None and is_open:
 | 
				
			||||||
 | 
					                    # we reach a new day
 | 
				
			||||||
 | 
					                    result.append((date, slot))
 | 
				
			||||||
 | 
					                if isinstance(day, tuple):
 | 
				
			||||||
 | 
					                    date = day[0]
 | 
				
			||||||
 | 
					                    slot = day[1]
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    date = day
 | 
				
			||||||
 | 
					                    slot = None
 | 
				
			||||||
 | 
					                is_open = False
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					            elif not is_open:
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            if CExtractor.is_nickname(e):
 | 
				
			||||||
 | 
					                print('on a un nickname', e)
 | 
				
			||||||
 | 
					                # we found a nickname
 | 
				
			||||||
 | 
					                is_open = True
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            hours = CExtractor.find_hours(e)
 | 
				
			||||||
 | 
					            if not hours is None:
 | 
				
			||||||
 | 
					                print('on a une heure', hours)
 | 
				
			||||||
 | 
					                if slot is None:
 | 
				
			||||||
 | 
					                    slot = hours
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    slot.merge(hours)
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            if CExtractor.is_canceled(e):
 | 
				
			||||||
 | 
					                print('on a un cancel')
 | 
				
			||||||
 | 
					                is_open = False
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if not date is None and is_open:
 | 
				
			||||||
 | 
					            # we reach a new day
 | 
				
			||||||
 | 
					            result.append((date, slot))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return result
 | 
				
			||||||
 | 
					        # [(10, time(14, 0, 0), time(17, 0, 0)), ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def extract(self, content, url, url_human=None, default_values=None, published=False):
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        soup = BeautifulSoup(content, 'xml')
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        for item in soup.find_all('item'):
 | 
				
			||||||
 | 
					            item_url = item.link.text
 | 
				
			||||||
 | 
					            title_text = item.title.text.lower()
 | 
				
			||||||
 | 
					            if not 'ouverture' in title_text:
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					            title = CExtractor.title_ouverture
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            when = CExtractor.find_date(title_text)
 | 
				
			||||||
 | 
					            if when is None:
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					            description = BeautifulSoup(item.description.text, 'html.parser')
 | 
				
			||||||
 | 
					            # annule
 | 
				
			||||||
 | 
					            # menage
 | 
				
			||||||
 | 
					            for p in description.select('p'):
 | 
				
			||||||
 | 
					                ts = CExtractor.find_timeslots(p)
 | 
				
			||||||
 | 
					                print(ts, when, title)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # if title is not None:
 | 
				
			||||||
 | 
					        # luuids = [event_url]
 | 
				
			||||||
 | 
					        # if uuidrel is not None:
 | 
				
			||||||
 | 
					        #     luuids += [uuidrel]
 | 
				
			||||||
 | 
					        # self.add_event(
 | 
				
			||||||
 | 
					        #     title,
 | 
				
			||||||
 | 
					        #     category,
 | 
				
			||||||
 | 
					        #     start_day,
 | 
				
			||||||
 | 
					        #     location,
 | 
				
			||||||
 | 
					        #     description,ù
 | 
				
			||||||
 | 
					        #     tags,
 | 
				
			||||||
 | 
					        #     recurrences=recurrences,
 | 
				
			||||||
 | 
					        #     uuids=luuids,
 | 
				
			||||||
 | 
					        #     url_human=url_human,
 | 
				
			||||||
 | 
					        #     start_time=start_time,
 | 
				
			||||||
 | 
					        #     end_day=end_day,
 | 
				
			||||||
 | 
					        #     end_time=end_time,
 | 
				
			||||||
 | 
					        #     last_modified=last_modified,
 | 
				
			||||||
 | 
					        #     published=published,
 | 
				
			||||||
 | 
					        #     image=image
 | 
				
			||||||
 | 
					        # )
 | 
				
			||||||
 | 
					        return self.get_structure()
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
@@ -28,8 +28,38 @@ class Extractor(ABC):
 | 
				
			|||||||
        else:
 | 
					        else:
 | 
				
			||||||
            return start_day
 | 
					            return start_day
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def guess_startswith(text, strs):
 | 
				
			||||||
 | 
					        t = Extractor.remove_accents(text).lower()
 | 
				
			||||||
 | 
					        for i, s in enumerate(strs):
 | 
				
			||||||
 | 
					            if t.startswith(s):
 | 
				
			||||||
 | 
					                return i + 1
 | 
				
			||||||
 | 
					        return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def guess_day_name(text, exact=False):
 | 
				
			||||||
 | 
					        if exact:
 | 
				
			||||||
 | 
					            return Extractor.guess_startswith(text, [
 | 
				
			||||||
 | 
					                "lundi",
 | 
				
			||||||
 | 
					                "mardi",
 | 
				
			||||||
 | 
					                "mercredi",
 | 
				
			||||||
 | 
					                "jeudi",
 | 
				
			||||||
 | 
					                "vendredi",
 | 
				
			||||||
 | 
					                "samedi",
 | 
				
			||||||
 | 
					                "dimanche",
 | 
				
			||||||
 | 
					            ])
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            return Extractor.guess_startswith(text, [
 | 
				
			||||||
 | 
					                "lun",
 | 
				
			||||||
 | 
					                "mar",
 | 
				
			||||||
 | 
					                "mer",
 | 
				
			||||||
 | 
					                "jeu",
 | 
				
			||||||
 | 
					                "ven",
 | 
				
			||||||
 | 
					                "sa",
 | 
				
			||||||
 | 
					                "di",
 | 
				
			||||||
 | 
					            ])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def guess_month(text):
 | 
					    def guess_month(text):
 | 
				
			||||||
        mths = [
 | 
					        return Extractor.guess_startswith(text, [
 | 
				
			||||||
            "jan",
 | 
					            "jan",
 | 
				
			||||||
            "fe",
 | 
					            "fe",
 | 
				
			||||||
            "mar",
 | 
					            "mar",
 | 
				
			||||||
@@ -42,12 +72,7 @@ class Extractor(ABC):
 | 
				
			|||||||
            "oct",
 | 
					            "oct",
 | 
				
			||||||
            "nov",
 | 
					            "nov",
 | 
				
			||||||
            "dec",
 | 
					            "dec",
 | 
				
			||||||
        ]
 | 
					        ])
 | 
				
			||||||
        t = remove_accents(text).lower()
 | 
					 | 
				
			||||||
        for i, m in enumerate(mths):
 | 
					 | 
				
			||||||
            if t.startswith(m):
 | 
					 | 
				
			||||||
                return i + 1
 | 
					 | 
				
			||||||
        return None
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def parse_french_date(text):
 | 
					    def parse_french_date(text):
 | 
				
			||||||
        # format NomJour Numero Mois Année
 | 
					        # format NomJour Numero Mois Année
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user