@@ -477,102 +477,172 @@ def download_akoma_ntoso_via_opendata(url, output_path, session=None, quiet=Fals
477477 "modalita" : "C" ,
478478 "tipoRicerca" : "A" ,
479479 "parametriRicerca" : {
480- "dataInizioEmanazione " : f"{ export_meta ['dataGU_human' ]} T00:00:00.000Z" ,
481- "dataFineEmanazione " : f"{ export_meta ['dataGU_human' ]} T23:59:59.999Z" ,
480+ "dataInizioPubblicazione " : f"{ export_meta ['dataGU_human' ]} T00:00:00.000Z" ,
481+ "dataFinePubblicazione " : f"{ export_meta ['dataGU_human' ]} T23:59:59.999Z" ,
482482 "numeroProvvedimento" : int (numero ),
483483 "annoProvvedimento" : int (anno ),
484484 },
485485 }
486486
487- try :
488- ricerca_response = session .post (
489- nuova_ricerca_url ,
490- headers = {** headers , "Content-Type" : "application/json" },
491- data = json .dumps (payload ),
492- timeout = DEFAULT_TIMEOUT ,
493- )
494- ricerca_response .raise_for_status ()
495- except requests .RequestException as e :
496- print (f"❌ Errore avvio ricerca OpenData: { e } " , file = sys .stderr )
497- return False , None , session
498-
499- token = ricerca_response .text .strip ().strip ('"' )
500- if not token :
501- print ("❌ ERRORE: token ricerca OpenData non valido." , file = sys .stderr )
502- return False , None , session
503-
504- # Conferma ricerca (opzionale)
505- conferma_url = f"{ base_url } /api/v1/ricerca-asincrona/conferma-ricerca"
506- try :
507- session .put (
508- conferma_url ,
509- headers = {** headers , "Content-Type" : "application/json" },
510- data = json .dumps ({"token" : token }),
511- timeout = DEFAULT_TIMEOUT ,
512- )
513- except requests .RequestException :
514- pass
515-
516- status_url = f"{ base_url } /api/v1/ricerca-asincrona/check-status/{ token } "
517- stato = None
518-
519- if not quiet :
520- print ("⏳ Preparazione collezione OpenData" , end = "" , file = sys .stderr , flush = True )
487+ relaxed_payload = {
488+ "formato" : "AKN" ,
489+ "richiestaExport" : "M" ,
490+ "modalita" : "C" ,
491+ "tipoRicerca" : "A" ,
492+ "parametriRicerca" : {
493+ "numeroProvvedimento" : int (numero ),
494+ "annoProvvedimento" : int (anno ),
495+ },
496+ }
521497
522- for _ in range (60 ):
498+ def _run_async_search (search_payload ):
499+ try :
500+ ricerca_response = session .post (
501+ nuova_ricerca_url ,
502+ headers = {** headers , "Content-Type" : "application/json" },
503+ data = json .dumps (search_payload ),
504+ timeout = DEFAULT_TIMEOUT ,
505+ )
506+ ricerca_response .raise_for_status ()
507+ except requests .RequestException as e :
508+ print (f"❌ Errore avvio ricerca OpenData: { e } " , file = sys .stderr )
509+ return None , None , None
510+
511+ token = ricerca_response .text .strip ().strip ('"' )
512+ if not token :
513+ print ("❌ ERRORE: token ricerca OpenData non valido." , file = sys .stderr )
514+ return None , None , None
515+
516+ # Conferma ricerca (opzionale)
517+ conferma_url = f"{ base_url } /api/v1/ricerca-asincrona/conferma-ricerca"
523518 try :
524- status_response = session .get (
525- status_url , headers = headers , timeout = DEFAULT_TIMEOUT
519+ session .put (
520+ conferma_url ,
521+ headers = {** headers , "Content-Type" : "application/json" },
522+ data = json .dumps ({"token" : token }),
523+ timeout = DEFAULT_TIMEOUT ,
526524 )
527- if status_response .status_code == 303 :
528- stato = 3
529- break
530- status_response .raise_for_status ()
531- status_data = status_response .json ()
532- stato = status_data .get ("stato" )
533- if stato == 3 :
534- break
535525 except requests .RequestException :
536526 pass
537527
528+ status_url = f"{ base_url } /api/v1/ricerca-asincrona/check-status/{ token } "
529+ stato = None
530+ status_data = None
531+
532+ if not quiet :
533+ print (
534+ "⏳ Preparazione collezione OpenData" ,
535+ end = "" ,
536+ file = sys .stderr ,
537+ flush = True ,
538+ )
539+
540+ for _ in range (60 ):
541+ try :
542+ status_response = session .get (
543+ status_url , headers = headers , timeout = DEFAULT_TIMEOUT
544+ )
545+ if status_response .status_code == 303 :
546+ stato = 3
547+ break
548+ status_response .raise_for_status ()
549+ status_data = status_response .json ()
550+ stato = status_data .get ("stato" )
551+ if stato == 3 :
552+ break
553+ except requests .RequestException :
554+ pass
555+
556+ if not quiet :
557+ print ("." , end = "" , file = sys .stderr , flush = True )
558+ time .sleep (2 )
559+
538560 if not quiet :
539- print ("." , end = "" , file = sys .stderr , flush = True )
540- time .sleep (2 )
561+ print () # New line after progress dots
541562
542- if not quiet :
543- print () # New line after progress dots
563+ return stato , status_data , token
544564
545- if stato != 3 :
546- print ( "❌ ERRORE: ricerca OpenData non completata in tempo utile." , file = sys . stderr )
547- return False , None , session
565+ payloads = [ payload , relaxed_payload ]
566+ download_url = None
567+ selected = None
548568
549- download_url = (
550- f"{ base_url } /api/v1/collections/download/collection-asincrona/{ token } "
551- )
569+ for idx , current_payload in enumerate (payloads ):
570+ stato , status_data , token = _run_async_search (current_payload )
571+ if stato != 3 :
572+ if idx == 0 :
573+ continue
574+ print (
575+ "❌ ERRORE: ricerca OpenData non completata in tempo utile." ,
576+ file = sys .stderr ,
577+ )
578+ return False , None , session
579+
580+ if status_data and status_data .get ("totAtti" ) == 0 :
581+ if idx == 0 :
582+ if not quiet :
583+ print (
584+ "⚠️ Ricerca OpenData senza risultati, ritento senza filtro data..." ,
585+ file = sys .stderr ,
586+ )
587+ continue
588+ print (
589+ "❌ ERRORE: ricerca OpenData non ha restituito risultati." ,
590+ file = sys .stderr ,
591+ )
592+ return False , None , session
552593
553- try :
554- download_response = session .get (
555- download_url , headers = headers , timeout = DEFAULT_TIMEOUT
594+ download_url = (
595+ f"{ base_url } /api/v1/collections/download/collection-asincrona/{ token } "
556596 )
557- download_response .raise_for_status ()
558- except requests .RequestException as e :
559- print (f"❌ Errore download collezione OpenData: { e } " , file = sys .stderr )
560- return False , None , session
561597
562- try :
563- with zipfile .ZipFile (BytesIO (download_response .content )) as zf :
564- target_date = _parse_yyyymmdd (export_meta .get ("dataVigenza" ))
565- selected = _select_akoma_file_from_zip (zf , target_date )
566- if not selected :
567- print (
568- "❌ ERRORE: nessun XML Akoma Ntoso trovato nel pacchetto OpenData." ,
569- file = sys .stderr ,
570- )
571- return False , None , session
572- with zf .open (selected ) as src , open (output_path , "wb" ) as dst :
573- dst .write (src .read ())
574- except zipfile .BadZipFile :
575- print ("❌ ERRORE: file ZIP OpenData non valido." , file = sys .stderr )
598+ try :
599+ download_response = session .get (
600+ download_url , headers = headers , timeout = DEFAULT_TIMEOUT
601+ )
602+ download_response .raise_for_status ()
603+ except requests .RequestException as e :
604+ if idx == 0 :
605+ if not quiet :
606+ print (
607+ "⚠️ Errore download collezione OpenData, ritento senza filtro data..." ,
608+ file = sys .stderr ,
609+ )
610+ continue
611+ print (f"❌ Errore download collezione OpenData: { e } " , file = sys .stderr )
612+ return False , None , session
613+
614+ try :
615+ with zipfile .ZipFile (BytesIO (download_response .content )) as zf :
616+ target_date = _parse_yyyymmdd (export_meta .get ("dataVigenza" ))
617+ selected = _select_akoma_file_from_zip (zf , target_date )
618+ if not selected :
619+ if idx == 0 :
620+ if not quiet :
621+ print (
622+ "⚠️ ZIP OpenData senza XML AKN, ritento senza filtro data..." ,
623+ file = sys .stderr ,
624+ )
625+ continue
626+ print (
627+ "❌ ERRORE: nessun XML Akoma Ntoso trovato nel pacchetto OpenData." ,
628+ file = sys .stderr ,
629+ )
630+ return False , None , session
631+ with zf .open (selected ) as src , open (output_path , "wb" ) as dst :
632+ dst .write (src .read ())
633+ break
634+ except zipfile .BadZipFile :
635+ if idx == 0 :
636+ if not quiet :
637+ print (
638+ "⚠️ ZIP OpenData non valido, ritento senza filtro data..." ,
639+ file = sys .stderr ,
640+ )
641+ continue
642+ print ("❌ ERRORE: file ZIP OpenData non valido." , file = sys .stderr )
643+ return False , None , session
644+
645+ if not selected :
576646 return False , None , session
577647
578648 if not quiet :
0 commit comments