MMOON commited on
Commit
d553d20
·
verified ·
1 Parent(s): dd18a20

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +40 -78
src/streamlit_app.py CHANGED
@@ -1,11 +1,11 @@
1
- # streamlit_app_cxc_with_pdf_fixed.py
2
  import streamlit as st
3
  import requests
4
  from bs4 import BeautifulSoup
5
  import re
6
- import time
7
  import pandas as pd
8
  from datetime import datetime
 
9
 
10
  # --- Configuration ---
11
  CODEX_URL = "https://www.fao.org/fao-who-codexalimentarius/codex-texts/codes-of-practice/fr/"
@@ -21,7 +21,7 @@ st.set_page_config(page_title="Codex CXC Viewer", page_icon="📋", layout="wide
21
  @st.cache_data(ttl=3600)
22
  def extract_cxc_documents():
23
  """
24
- Fonction pour extraire les Codes de Pratique (CXC) avec leurs liens PDF correctement décodés.
25
  """
26
  st.info("Extraction des documents depuis le site Codex...")
27
  documents = []
@@ -41,10 +41,12 @@ def extract_cxc_documents():
41
  rows = table.find_all('tr')
42
  for row in rows:
43
  cells = row.find_all(['td', 'th'])
44
- if len(cells) >= 4:
45
- # Extraire les données de base
46
- cell_texts = [cell.get_text(strip=True) for cell in cells]
 
47
  code_candidate = cell_texts[0] if cell_texts else ""
 
48
  code_match = re.match(r'^(CXC)\s+([\w\-R]*\d+(?:-\d+)?[R]?)$', code_candidate)
49
 
50
  if code_match:
@@ -63,98 +65,57 @@ def extract_cxc_documents():
63
  except ValueError:
64
  year = 0
65
 
66
- # --- EXTRACTION DES LIENS PDF CORRECTEMENT DECODÉS ---
67
- # Le lien PDF est dans la dernière cellule (<td class="alignCenter">)
68
- pdf_cell = cells[4] if len(cells) > 4 else None
69
  pdf_url = None
70
 
71
- if pdf_cell:
72
- # Trouver tous les liens <a> dans cette cellule
73
- links = pdf_cell.find_all('a')
74
- for link in links:
75
- href = link.get('href')
76
- if href and 'pdf' in href.lower():
77
- # Décoder l'URL encodée
78
- decoded_href = requests.utils.unquote(href)
79
- # L'URL décrite commence par /fao-who-codexalimentarius/sh-proxy/fr/?lnk=1&url=...
80
- # On extrait la partie après url=
81
- # Exemple: https://www.fao.org/fao-who-codexalimentarius/sh-proxy/fr/?lnk=1&url=https%3A%2F%2Fworkspace.fao.org%2Fsites%2Fcodex%2FStandards%2FCXC%2B1-1969%2FCXC_001c.pdf
82
- # Il faut extraire: https://workspace.fao.org/sites/codex/Standards/CXC%2B1-1969/CXC_001c.pdf
83
- # Puis décoder encore une fois si nécessaire
84
- if 'url=' in decoded_href:
85
- # Extraire la partie après 'url='
86
- url_part = decoded_href.split('url=', 1)[1]
87
- # Décoder à nouveau
88
- final_pdf_url = requests.utils.unquote(url_part)
89
- # Vérifier que c'est bien un lien HTTPS
90
- if final_pdf_url.startswith('https://'):
91
- pdf_url = final_pdf_url
92
- break
93
- else:
94
- # Si pas de 'url=', on utilise directement le lien
95
- pdf_url = decoded_href
96
- break
97
-
98
- # Si on n'a pas trouvé de lien PDF valide, générer un lien plausible
99
  if not pdf_url:
100
- pdf_url = generate_pdf_link_simple(full_code, year)
101
 
102
  documents.append({
103
  'code': full_code,
104
  'title': title,
105
  'committee': committee,
106
  'year': year,
107
- 'pdf_url': pdf_url
108
  })
109
  st.success(f"Extraction terminée. {len(documents)} documents trouvés.")
110
  return documents
111
 
112
  except Exception as e:
113
  st.error(f"Erreur lors de l'extraction : {e}")
 
 
114
  return []
115
 
116
- def generate_pdf_link_simple(code, year):
117
- """
118
- Génère un lien PDF plausible basé sur le code et l'année.
119
- Utilisé comme fallback si aucun lien n'est trouvé dans le HTML.
120
- """
121
- try:
122
- parts = code.split()
123
- prefix = parts[0]
124
- number_part = parts[1]
125
-
126
- if '-' in number_part:
127
- num_year_parts = number_part.split('-', 1)
128
- main_num_str = num_year_parts[0]
129
- suffix_year = num_year_parts[1]
130
- # Pad le numéro principal
131
- main_num = int(main_num_str.rstrip('R'))
132
- padded_main_num = f"{main_num:03d}"
133
- if main_num_str.endswith('R'):
134
- padded_main_num += 'R'
135
- clean_code_for_url = f"{prefix}_{padded_main_num}-{suffix_year}"
136
- else:
137
- # Pas de tiret
138
- main_num = int(number_part.rstrip('R'))
139
- padded_main_num = f"{main_num:03d}"
140
- if number_part.endswith('R'):
141
- padded_main_num += 'R'
142
- clean_code_for_url = f"{prefix}_{padded_main_num}"
143
-
144
- # URL de base la plus courante
145
- return f"https://www.fao.org/fileadmin/templates/codexalimentarius/pdf/CODEX_STANDARDS/{clean_code_for_url}.pdf"
146
- except:
147
- # En cas d'erreur, lien de recherche
148
- search_term = code.replace(' ', '%20')
149
- return f"https://www.fao.org/fao-who-codexalimentarius/search/en/?q={search_term}"
150
-
151
  # Initialisation de l'état de session
152
  if 'documents' not in st.session_state:
153
  st.session_state.documents = []
154
 
155
  # --- Interface Utilisateur ---
156
  st.title("📋 Visualiseur de Codes de Pratique Codex (CXC)")
157
- st.markdown("Extraction et affichage des documents CXC avec liens de téléchargement.")
158
 
159
  # Bouton de chargement
160
  col1, col2 = st.columns([1, 3])
@@ -189,7 +150,8 @@ if st.session_state.documents:
189
  st.link_button("📄 Télécharger le PDF", doc['pdf_url'], type="primary", use_container_width=True)
190
 
191
  # Afficher l'URL du PDF en petit (optionnel, pour débogage)
192
- # st.caption(f"PDF: {doc['pdf_url']}")
 
193
 
194
  st.divider() # Ligne de séparation entre les documents
195
 
@@ -198,7 +160,7 @@ if st.session_state.documents:
198
  st.subheader("💾 Exporter les données")
199
  col1, col2 = st.columns(2)
200
  with col1:
201
- csv = df.to_csv(index=False)
202
  st.download_button(
203
  label="📄 Télécharger en CSV",
204
  data=csv,
@@ -215,4 +177,4 @@ if st.session_state.documents:
215
  )
216
 
217
  else:
218
- st.info("Cliquez sur le bouton 'Charger/Recharger les Documents' pour démarrer l'extraction.")
 
1
+ # streamlit_app_cxc_final.py
2
  import streamlit as st
3
  import requests
4
  from bs4 import BeautifulSoup
5
  import re
 
6
  import pandas as pd
7
  from datetime import datetime
8
+ import urllib.parse # Pour le décodage d'URL
9
 
10
  # --- Configuration ---
11
  CODEX_URL = "https://www.fao.org/fao-who-codexalimentarius/codex-texts/codes-of-practice/fr/"
 
21
  @st.cache_data(ttl=3600)
22
  def extract_cxc_documents():
23
  """
24
+ Fonction pour extraire les Codes de Pratique (CXC) avec leurs liens PDF directs depuis le HTML.
25
  """
26
  st.info("Extraction des documents depuis le site Codex...")
27
  documents = []
 
41
  rows = table.find_all('tr')
42
  for row in rows:
43
  cells = row.find_all(['td', 'th'])
44
+ # Vérifier s'il y a au moins 5 cellules (données + cellule PDF)
45
+ if len(cells) >= 5:
46
+ # Extraire les données de base (cellules 1 à 4)
47
+ cell_texts = [cell.get_text(strip=True) for cell in cells[:4]]
48
  code_candidate = cell_texts[0] if cell_texts else ""
49
+ # Pattern pour CXC
50
  code_match = re.match(r'^(CXC)\s+([\w\-R]*\d+(?:-\d+)?[R]?)$', code_candidate)
51
 
52
  if code_match:
 
65
  except ValueError:
66
  year = 0
67
 
68
+ # --- EXTRACTION DU LIEN PDF DIRECT ---
69
+ # Le lien PDF est dans la 5ème cellule (index 4)
70
+ pdf_cell = cells[4]
71
  pdf_url = None
72
 
73
+ # Trouver le premier lien <a> dans cette cellule qui contient 'pdf'
74
+ link_tag = pdf_cell.find('a', href=re.compile(r'.*\.pdf', re.IGNORECASE))
75
+ if link_tag:
76
+ href = link_tag.get('href')
77
+ if href:
78
+ # 1. Décoder l'URL encodée (ex: &amp; -> &)
79
+ decoded_href = urllib.parse.unquote(href)
80
+
81
+ # 2. Extraire l'URL réelle après 'url='
82
+ if 'url=' in decoded_href:
83
+ # Extraire la partie après 'url='
84
+ url_part = decoded_href.split('url=', 1)[1]
85
+ # 3. Décoder à nouveau l'URL extraite
86
+ final_pdf_url = urllib.parse.unquote(url_part)
87
+ pdf_url = final_pdf_url
88
+ else:
89
+ # Si pas de 'url=', utiliser le href décodé directement
90
+ pdf_url = decoded_href
91
+
92
+ # Si aucun lien PDF n'a été trouvé, on met un placeholder
 
 
 
 
 
 
 
 
93
  if not pdf_url:
94
+ pdf_url = "https://www.fao.org/fao-who-codexalimentarius/search/en/?q=" + full_code.replace(' ', '%20')
95
 
96
  documents.append({
97
  'code': full_code,
98
  'title': title,
99
  'committee': committee,
100
  'year': year,
101
+ 'pdf_url': pdf_url # Lien PDF extrait et nettoyé, ou lien de recherche
102
  })
103
  st.success(f"Extraction terminée. {len(documents)} documents trouvés.")
104
  return documents
105
 
106
  except Exception as e:
107
  st.error(f"Erreur lors de l'extraction : {e}")
108
+ import traceback
109
+ st.text_area("Traceback", traceback.format_exc(), height=200) # Pour aider au débogage
110
  return []
111
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
112
  # Initialisation de l'état de session
113
  if 'documents' not in st.session_state:
114
  st.session_state.documents = []
115
 
116
  # --- Interface Utilisateur ---
117
  st.title("📋 Visualiseur de Codes de Pratique Codex (CXC)")
118
+ st.markdown("Extraction et affichage des documents CXC avec liens de téléchargement directs.")
119
 
120
  # Bouton de chargement
121
  col1, col2 = st.columns([1, 3])
 
150
  st.link_button("📄 Télécharger le PDF", doc['pdf_url'], type="primary", use_container_width=True)
151
 
152
  # Afficher l'URL du PDF en petit (optionnel, pour débogage)
153
+ # with st.expander("Voir l'URL du PDF"):
154
+ # st.code(doc['pdf_url'])
155
 
156
  st.divider() # Ligne de séparation entre les documents
157
 
 
160
  st.subheader("💾 Exporter les données")
161
  col1, col2 = st.columns(2)
162
  with col1:
163
+ csv = df.to_csv(index=False, sep=';') # ';' pour compatibilité Excel FR
164
  st.download_button(
165
  label="📄 Télécharger en CSV",
166
  data=csv,
 
177
  )
178
 
179
  else:
180
+ st.info("Cliquez sur le bouton 'Charger/Recharger les Documents' pour démarrer l'extraction.")