From 62a20a4350493a2eb023780ca1486ec2a1f76cb7 Mon Sep 17 00:00:00 2001
From: Bastien Le Querrec <blq@laquadrature.net>
Date: Wed, 6 Mar 2024 15:39:36 +0100
Subject: [PATCH] =?UTF-8?q?utilise=20requests=20pour=20t=C3=A9l=C3=A9charg?=
 =?UTF-8?q?er=20les=20PDF,=20attend=20l'affichage=20du=20contenu=20au=20li?=
 =?UTF-8?q?eu=20d'un=20sleep?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Les PDF sont téléchargés à partir de la session obtenue par le
navigateur. Cela permet de pouvoir éteindre le navigateur une fois la
session obtenue, et d'aller plus vite (car avec moins de ressources)
dans le téléchargement des documents.
---
 ppparis.py       | 54 +++++++++++++++++++++++++++---------------------
 requirements.txt |  1 +
 2 files changed, 32 insertions(+), 23 deletions(-)

diff --git a/ppparis.py b/ppparis.py
index 919adee..fcd1c5c 100755
--- a/ppparis.py
+++ b/ppparis.py
@@ -6,8 +6,13 @@ from bs4 import BeautifulSoup
 import argparse
 from urllib.parse import unquote
 import logging
+import requests
 
 from selenium import webdriver
+from selenium.webdriver.common.by import By
+from selenium.webdriver.support.wait import WebDriverWait
+from selenium.webdriver.support import expected_conditions
+
 from pyvirtualdisplay import Display
 
 from pdfminer.high_level import extract_text
@@ -16,7 +21,6 @@ from pdfminer.high_level import extract_text
 __RAA_PAGE = 'https://www.prefecturedepolice.interieur.gouv.fr/actualites-et-presse/arretes/accueil-arretes'
 __USER_AGENT = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36'
 __headless_mode = True
-__WAITING_TIME = int(os.getenv('WAITING_TIME') or 5)
 __LIST = os.getenv('LIST') or 'vidéoprotection,caméras,captation,aéronef'
 __DATA_DIR = os.path.dirname(os.path.abspath(__file__))+'/data/ppparis/'
 
@@ -30,16 +34,24 @@ def print_output(data):
   f.write(data+"\n")
   f.close()
 
+# On charge l'URL avec la liste des fichiers
 def get_html(url):
   browser.get(url)
-  time.sleep(int(__WAITING_TIME*10))
-  page_content = browser.page_source
 
-  return page_content
+  # On attend que le navigateur ait passé les tests anti-robots et que le contenu s'affiche
+  element = WebDriverWait(browser, 120).until(expected_conditions.presence_of_element_located((By.ID, "block-decree-list-block")))
 
-def download_file(url):
-  browser.get(url)
-  time.sleep(__WAITING_TIME)
+  return browser.page_source
+
+def download_file(url, dest):
+  try:
+    os.makedirs(os.path.dirname(dest), exist_ok=True)
+    file = session.get(url)
+    f = open(dest,'wb')
+    f.write(file.content);
+    f.close()
+  except Exception as exc:
+    logging.warning(f'ATTENTION: Impossible de télécharger le fichier {url}: {exc}')
 
 def parse_pdf(filename, name, date):
   if not os.path.isfile(__DATA_DIR+filename):
@@ -64,7 +76,6 @@ def parse_pdf(filename, name, date):
 # Début du script
 parser = argparse.ArgumentParser(prog='ppparis.py', description='Télécharge les RAA de la Préfecture de police de Paris et recherche des mots-clés')
 parser.add_argument('-n', '--noheadless', action='store_true', help='ne lance pas le navigateur en mode headless (pratique pour débugguer ou en dehors d\'une CI)')
-parser.add_argument('-w', '--waiting-time', type=int, action='store', help='délai (en secondes) d\'attente de chargement d\'une page, la durée du premier chargement étant cette valeur multipliée par 10 (par défaut : 5)')
 parser.add_argument('-l', '--list', action='store', help='liste des termes recherchés, séparés par une virgule (par défaut : vidéoprotection,caméras,captation,aéronef)')
 parser.add_argument('-v', action='store_true', help='relève le niveau de verbosité à INFO')
 parser.add_argument('-vv', action='store_true', help='relève le niveau de verbosité à DEBUG')
@@ -82,11 +93,6 @@ if args.noheadless:
 if not __headless_mode:
   logging.debug('Mode noheadless')
 
-if args.waiting_time:
-  __WAITING_TIME = args.waiting_time
-
-logging.debug(f'WAITING_TIME: {__WAITING_TIME}')
-
 if args.list:
   __LIST = args.list
 
@@ -123,6 +129,17 @@ browser = webdriver.Chrome(options=webdriver_options)
 # Téléchargement des RAA
 page_content = get_html(__RAA_PAGE)
 
+# On récupère les cookies du navigateur pour les réutiliser lors du téléchargement des PDF
+session = requests.Session()
+for cookie in browser.get_cookies():
+  session.cookies.set(cookie['name'], cookie['value'])
+session.headers.update({'User-Agent': __USER_AGENT})
+
+# On arrête le navigateur
+browser.quit()
+if __headless_mode:
+  display.stop()
+
 # On charge le parser
 soup = BeautifulSoup(page_content, 'html.parser')
 
@@ -142,11 +159,7 @@ for a in soup.find_all('a', href=True):
     # Si le fichier n'a pas été téléchargé, on le télécharge et on le parse
     if not os.path.isfile(__DATA_DIR+filename):
       logging.info(f'Nouveau fichier : {name} ({date}). URL : {url}')
-      try:
-        download_file(url)
-      except Exception:
-        logging.warning('ATTENTION: Impossible de télécharger le fichier '+url)
-
+      download_file(url, __DATA_DIR+filename)
 
       cmd = ['ocrmypdf', '-l', 'eng+fra', '--output-type', 'pdfa', '--redo-ocr', __DATA_DIR+filename, __DATA_DIR+filename]
       logging.debug(f'Lancement de ocrmypdf: {cmd}')
@@ -157,8 +170,3 @@ for a in soup.find_all('a', href=True):
           logging.warning('ATTENTION : Impossible d\'OCRiser le document', exc.returncode, exc.output)
 
       parse_pdf(filename, name, date)
-
-# On arrête le navigateur
-browser.quit()
-if __headless_mode:
-  display.stop()
diff --git a/requirements.txt b/requirements.txt
index 3126eb6..9f7e72e 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -2,3 +2,4 @@ beautifulsoup4
 selenium
 pyvirtualdisplay
 pdfminer.six
+requests
-- 
GitLab