{ "cells": [ { "cell_type": "markdown", "metadata": { "toc": true }, "source": [ "<h1>Table of Contents<span class=\"tocSkip\"></span></h1>\n", "<div class=\"toc\"><ul class=\"toc-item\"><li><span><a href=\"#Générateur-d'attestation-de-sortie-automatique---COVID-19\" data-toc-modified-id=\"Générateur-d'attestation-de-sortie-automatique---COVID-19-1\"><span class=\"toc-item-num\">1 </span>Générateur d'attestation de sortie automatique - COVID 19</a></span><ul class=\"toc-item\"><li><span><a href=\"#But-initial\" data-toc-modified-id=\"But-initial-1.1\"><span class=\"toc-item-num\">1.1 </span>But initial</a></span></li><li><span><a href=\"#Premier-tutoriel-pour-prendre-en-main-selenium\" data-toc-modified-id=\"Premier-tutoriel-pour-prendre-en-main-selenium-1.2\"><span class=\"toc-item-num\">1.2 </span>Premier tutoriel pour prendre en main selenium</a></span></li><li><span><a href=\"#Solution\" data-toc-modified-id=\"Solution-1.3\"><span class=\"toc-item-num\">1.3 </span>Solution</a></span><ul class=\"toc-item\"><li><span><a href=\"#Télécharger-une-attestation\" data-toc-modified-id=\"Télécharger-une-attestation-1.3.1\"><span class=\"toc-item-num\">1.3.1 </span>Télécharger une attestation</a></span></li><li><span><a href=\"#Envoyer-les-attestations-par-email-ou-autre\" data-toc-modified-id=\"Envoyer-les-attestations-par-email-ou-autre-1.3.2\"><span class=\"toc-item-num\">1.3.2 </span>Envoyer les attestations par email ou autre</a></span></li><li><span><a href=\"#Envoyer-les-attestations-sur-un-site-web\" data-toc-modified-id=\"Envoyer-les-attestations-sur-un-site-web-1.3.3\"><span class=\"toc-item-num\">1.3.3 </span>Envoyer les attestations sur un site web</a></span></li></ul></li><li><span><a href=\"#Exemple\" data-toc-modified-id=\"Exemple-1.4\"><span class=\"toc-item-num\">1.4 </span>Exemple</a></span><ul class=\"toc-item\"><li><span><a href=\"#Avec-les-données-d'exemple-du-site-web-:\" data-toc-modified-id=\"Avec-les-données-d'exemple-du-site-web-:-1.4.1\"><span class=\"toc-item-num\">1.4.1 </span>Avec les données d'exemple du site web :</a></span></li><li><span><a href=\"#Avec-mes-données\" data-toc-modified-id=\"Avec-mes-données-1.4.2\"><span class=\"toc-item-num\">1.4.2 </span>Avec mes données</a></span></li></ul></li><li><span><a href=\"#Automatisation-toutes-les-55-minutes\" data-toc-modified-id=\"Automatisation-toutes-les-55-minutes-1.5\"><span class=\"toc-item-num\">1.5 </span>Automatisation toutes les 55 minutes</a></span></li><li><span><a href=\"#Conclusion\" data-toc-modified-id=\"Conclusion-1.6\"><span class=\"toc-item-num\">1.6 </span>Conclusion</a></span></li></ul></li></ul></div>" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Générateur d'attestation de sortie automatique - COVID 19\n", "*Ceci est une expérimentation, et n'est pas encore terminé*\n", "\n", "## But initial\n", "\n", "1. utiliser [Selenium](https://www.selenium.dev/) et [selenium Python](https://selenium-python.readthedocs.io/installation.html) pour automatiser l'utilisation du site [media.interieur.gouv.fr/deplacement-covid-19/](https://media.interieur.gouv.fr/deplacement-covid-19/), \n", "2. sauvegarder le PDF localement, et l'envoyer par mail ou sur mon site web.\n", "\n", "TODO ajouter warning etc.\n", "\n", "- Auteur : [Lilian Besson](https://perso.crans.org/besson/) ([@Naereen](https://GitHub.com/Naereen) sur GitHub)\n", "- Licence : [MIT Licensed](https://lbesson.mit-license.org/)\n", "- Date : Samedi 31 octobre 2020" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "## Premier tutoriel pour prendre en main selenium" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note : je n'avais jamais utilisé selenium ou ce genre de module pour contrôler un navigateur en mode \"headless\".\n", "Ce n'est pas très compliqué, et j'ai trouvé que ce petit tutoriel est bien fait : https://pythonbasics.org/selenium-firefox-headless/\n", "[Cette documentation est bien complète, pour le module Python de selenium](https://selenium-python.readthedocs.io/)." ] }, { "cell_type": "code", "execution_count": 92, "metadata": { "ExecuteTime": { "end_time": "2020-10-31T12:52:07.241649Z", "start_time": "2020-10-31T12:52:03.024600Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Downloading 'https://GitHub.com/Naereen'...\n", "<html lang=\"en\"><head>\n", " <meta charset=\"utf-8\">\n", " <link rel=\"dns-prefetch\" href=\"https://github.githubassets.com\">\n", " <link rel=\"dns-prefetch\" href=\"https://avatars0.githubusercontent.com\">\n", " <link rel=\"dns-prefetch\" href=\"https://avatars1.githubusercontent.com\">\n", " <link rel=\"dns-prefetch\" href=\"https://avatars2.githubusercontent.com\">\n", " <link rel=\"dns-prefetch\" href=\"https://avatars3.githubusercontent.com\">\n", " <link rel=\"dns-prefetch\" href=\"https://github-cloud.s3.amazonaws.com\">\n", " <link rel=\"d\n" ] } ], "source": [ "from selenium import webdriver\n", "\n", "try:\n", " URL = \"https://GitHub.com/Naereen\"\n", " print(f\"Downloading '{URL}'...\")\n", " firefoxOptions = webdriver.FirefoxOptions()\n", " firefoxOptions.headless = True\n", " browser = webdriver.Firefox(options=firefoxOptions)\n", "\n", " browser.get('https://GitHub.com/Naereen')\n", " print(browser.page_source[:500])\n", "finally:\n", " try:\n", " browser.close()\n", " except:\n", " pass" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "J'ai bien réussi à installer et utiliser Selenium. Ca marche bien !" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Solution" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "J'aurai besoin de ces modules là :" ] }, { "cell_type": "code", "execution_count": 93, "metadata": { "ExecuteTime": { "end_time": "2020-10-31T12:52:11.558843Z", "start_time": "2020-10-31T12:52:11.550644Z" } }, "outputs": [], "source": [ "import time\n", "from datetime import datetime\n", "import urllib.request\n", "import subprocess\n", "from selenium import webdriver" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Et je vais avoir besoin de cette fonction là, qui vient de https://stackoverflow.com/a/47425305/, pour télécharger l'attestation générée par le site, qui est donnée sous la forme d'une adresse blob:https://media.interieur.gouv.fr/ca78c998-724b-4540-8152-2eb269b06eab" ] }, { "cell_type": "code", "execution_count": 94, "metadata": { "ExecuteTime": { "end_time": "2020-10-31T12:52:12.776489Z", "start_time": "2020-10-31T12:52:12.771639Z" } }, "outputs": [], "source": [ "import base64\n", "\n", "def get_file_content_chrome(browser, uri):\n", " \"\"\" Use selenium [browser] to download blob [uri].\n", "\n", " - Source https://stackoverflow.com/a/47425305/\n", " \"\"\"\n", " result = browser.execute_async_script(\"\"\"\n", " var uri = arguments[0];\n", " var callback = arguments[1];\n", " var toBase64 = function(buffer){for(var r,n=new Uint8Array(buffer),t=n.length,a=new Uint8Array(4*Math.ceil(t/3)),i=new Uint8Array(64),o=0,c=0;64>c;++c)i[c]=\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\".charCodeAt(c);for(c=0;t-t%3>c;c+=3,o+=4)r=n[c]<<16|n[c+1]<<8|n[c+2],a[o]=i[r>>18],a[o+1]=i[r>>12&63],a[o+2]=i[r>>6&63],a[o+3]=i[63&r];return t%3===1?(r=n[t-1],a[o]=i[r>>2],a[o+1]=i[r<<4&63],a[o+2]=61,a[o+3]=61):t%3===2&&(r=(n[t-2]<<8)+n[t-1],a[o]=i[r>>10],a[o+1]=i[r>>4&63],a[o+2]=i[r<<2&63],a[o+3]=61),new TextDecoder(\"ascii\").decode(a)};\n", " var xhr = new XMLHttpRequest();\n", " xhr.responseType = 'arraybuffer';\n", " xhr.onload = function(){ callback(toBase64(xhr.response)) };\n", " xhr.onerror = function(){ callback(xhr.status) };\n", " xhr.open('GET', uri);\n", " xhr.send();\n", " \"\"\", uri)\n", " if type(result) == int :\n", " raise Exception(\"Request failed with status %s\" % result)\n", " return base64.b64decode(result)\n", "\n", "# bytes = get_file_content_chrome(browser, \"blob:https://developer.mozilla.org/7f9557f4-d8c8-4353-9752-5a49e85058f5\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Télécharger une attestation" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Et maintenant je peux écrire une fonction qui génère une attestation et la sauvegarde, avec les détails (nom, adresse etc) donnés en argument.\n", "\n", "Il suffira ensuite de lancer cette fonction toutes les 55 minutes et m'envoyer un mail." ] }, { "cell_type": "code", "execution_count": 119, "metadata": { "ExecuteTime": { "end_time": "2020-10-31T13:01:41.590967Z", "start_time": "2020-10-31T13:01:41.552830Z" } }, "outputs": [], "source": [ "def download_attestation(details):\n", " \"\"\" Fill the form on https://media.interieur.gouv.fr/deplacement-covid-19/ with details, and save the PDF attestation.\"\"\"\n", " download_name = None\n", " try:\n", " firefoxOptions = webdriver.FirefoxOptions()\n", " firefoxOptions.headless = True\n", " browser = webdriver.Firefox(options=firefoxOptions)\n", "\n", " URL = \"https://media.interieur.gouv.fr/deplacement-covid-19/\"\n", " browser.get(URL)\n", "\n", " # keep this check, to be sure that the downloaded webpage was the correct one, update if needed!\n", " page_source = browser.page_source\n", " page_source_100 = '<html class=\"fontawesome-i2svg-active fontawesome-i2svg-complete\" lang=\"fr\"><head><meta charset=\"UTF'\n", " assert page_source[:100] == page_source_100\n", "\n", " # Now, let's fill with details from the input dictionnary details (see below for example)\n", " # - field-firstname\n", " # - field-lastname\n", " # - field-birthday\n", " # - field-placeofbirth\n", " # - field-address\n", " # - field-city\n", " # - field-zipcode\n", " # - field-datesortie : may be missing\n", " # - field-heuresortie : may be missing\n", " \n", " # automatically add current date/time if not present\n", " now = datetime.now()\n", " if 'datesortie' not in details:\n", " details['datesortie'] = f\"{now:%Y-%m-%d}\"\n", " if 'heuresortie' not in details:\n", " details['heuresortie'] = f\"{now:%H:%M}\"\n", "\n", " # fill #field-XXX with YYY, read from the input dictionnary\n", " for fieldname, value in details.items():\n", " hidden_value = '*' * len(value)\n", " print(f\"Filling the form '{fieldname}' with value '{hidden_value}'...\")\n", " input_field = browser.find_element_by_id(f\"field-{fieldname}\") \n", " input_field.clear()\n", " input_field.send_keys(value)\n", " # this check is useful, to be sure that we don't try to generate a PDF\n", " # if an input field was not correctly filled\n", " for fieldname, value in details.items():\n", " print(f\"Checking value of the form '{fieldname}'...\")\n", " input_field = browser.find_element_by_id(f\"field-{fieldname}\") \n", " its_new_value = input_field.get_attribute(\"value\")\n", " if its_new_value != value:\n", " print(f\"Error: the form '{fieldname}' has value '{its_new_value}' != '{value}'.\")\n", "\n", " # click on '#checkbox-achats'\n", " print(\"Clicking on '#checkbox-achats'...\")\n", " checkbox_achats = browser.find_element_by_id(\"checkbox-achats\")\n", " checkbox_achats.click()\n", "\n", " # click on '#generate-btn'\n", " print(\"Clicking on 'generate-btn'...\")\n", " generate_btn = browser.find_element_by_id(\"generate-btn\")\n", " # TODO how to configure the path of the file to save?\n", " generate_btn.click()\n", "\n", " # now wait 5 seconds (probably not mandatory...)\n", " print(\"New sleeping 5 seconds...\")\n", " time.sleep(5)\n", "\n", " # check that there is a new <a href=\"...\" download=\"...\"> link\n", " # <a href=\"blob:https://media.interieur.gouv.fr/712fc9d2-6967-4e63-b9c3-870175b6258f\" download=\"attestation-2020-10-31_12-40.pdf\"></a>\n", " all_a_links = browser.find_elements_by_css_selector(\"a\")\n", " # window.document.getElementsByTagName(\"a\")\n", " for link in all_a_links:\n", " try:\n", " href = link.get_attribute(\"href\")\n", " download = link.get_attribute(\"download\")\n", " if download:\n", " print(f\"Found a new <a href='...'> link! with href = {href}\")\n", " print(f\" and it has a download = {download}\")\n", " print(\"Downloading the file and save it!\")\n", " # 1st try...\n", " bytes_download = get_file_content_chrome(browser, href)\n", " download_name = download\n", " with open(download_name, \"wb\") as download_file:\n", " download_file.write(bytes_download)\n", " print(f\"The PDF file {download_name} is now saved!\")\n", " ## 2nd try... this was NOT working\n", " # download_name = download.replace(\".pdf\", \"_2.pdf\")\n", " #urllib.request.urlretrieve(href, download_name)\n", " except:\n", " pass\n", " # let's close the browser and finish\n", " finally:\n", " try:\n", " browser.close()\n", " except:\n", " pass\n", " return download_name" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Envoyer les attestations par email ou autre\n", "\n", "TODO?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Envoyer les attestations sur un site web" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Maintenant je peux envoyer les attestations téléchargées \"à la main\" (mais ça marche parce que IPython/Jupyter c'est magique!\n", "\n", "Je vais les mettre dans un dossier (privé, caché et protégé par mot de passe), sur mon site web, avec un sous-dossier par jour." ] }, { "cell_type": "code", "execution_count": 96, "metadata": { "ExecuteTime": { "end_time": "2020-10-31T12:56:23.079617Z", "start_time": "2020-10-31T12:56:23.072877Z" } }, "outputs": [], "source": [ "def send_attestations():\n", " now = datetime.now()\n", " today = f\"{now:%Y-%m-%d}\"\n", " !ls -larth *pdf\n", " !echo CP attestation-$(date '+%Y-%m-%d')_*.pdf ${Szam}attestations/$(date '+%Y-%m-%d')/\n", " !CP attestation-$(date '+%Y-%m-%d')_*.pdf ${Szam}attestations/$(date '+%Y-%m-%d')/" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "En gros, ça fait juste ça :" ] }, { "cell_type": "code", "execution_count": 97, "metadata": { "ExecuteTime": { "end_time": "2020-10-31T12:56:23.807601Z", "start_time": "2020-10-31T12:56:23.675460Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "ls: impossible d'accéder à '*pdf': Aucun fichier ou dossier de ce type\r\n" ] } ], "source": [ "!ls -larth *pdf" ] }, { "cell_type": "code", "execution_count": 98, "metadata": { "ExecuteTime": { "end_time": "2020-10-31T12:56:24.684695Z", "start_time": "2020-10-31T12:56:24.549694Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "CP attestation-2020-10-31_*.pdf besson@zamok.crans.org:~/www/attestations/2020-10-31/\r\n" ] } ], "source": [ "!echo CP attestation-$(date '+%Y-%m-%d')_*.pdf ${Szam}attestations/$(date '+%Y-%m-%d')/" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Exemple" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Avec les données d'exemple du site web :" ] }, { "cell_type": "code", "execution_count": 123, "metadata": { "ExecuteTime": { "end_time": "2020-10-31T13:08:23.835029Z", "start_time": "2020-10-31T13:08:23.829039Z" } }, "outputs": [], "source": [ "# TODO read from a file, like a .ini config file\n", "details = {\n", " 'firstname': \"Camille\",\n", " 'lastname': \"Dupont\",\n", " 'birthday': \"01/01/1970\",\n", " 'placeofbirth': \"Paris\",\n", " 'address': \"999 avenue de France\",\n", " 'city': \"Paris\",\n", " 'zipcode': \"75001\",\n", " #'datesortie': f\"{now:%Y-%m-%d}\",\n", " #'heuresortie': f\"{now:%H:%M}\",\n", "}" ] }, { "cell_type": "code", "execution_count": 124, "metadata": { "ExecuteTime": { "end_time": "2020-10-31T13:08:33.453148Z", "start_time": "2020-10-31T13:08:24.784689Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Filling the form 'firstname' with value '*******'...\n", "Filling the form 'lastname' with value '******'...\n", "Filling the form 'birthday' with value '**********'...\n", "Filling the form 'placeofbirth' with value '*****'...\n", "Filling the form 'address' with value '********************'...\n", "Filling the form 'city' with value '*****'...\n", "Filling the form 'zipcode' with value '*****'...\n", "Filling the form 'datesortie' with value '**********'...\n", "Filling the form 'heuresortie' with value '*****'...\n", "Checking value of the form 'firstname'...\n", "Checking value of the form 'lastname'...\n", "Checking value of the form 'birthday'...\n", "Checking value of the form 'placeofbirth'...\n", "Checking value of the form 'address'...\n", "Checking value of the form 'city'...\n", "Checking value of the form 'zipcode'...\n", "Checking value of the form 'datesortie'...\n", "Checking value of the form 'heuresortie'...\n", "Clicking on '#checkbox-achats'...\n", "Clicking on 'generate-btn'...\n", "New sleeping 5 seconds...\n", "Found a new <a href='...'> link! with href = blob:https://media.interieur.gouv.fr/2451a67f-5957-4ede-8fd2-9b8ef9d0f66c\n", " and it has a download = attestation-2020-10-31_14-08.pdf\n", "Downloading the file and save it!\n", "The PDF file attestation-2020-10-31_14-08.pdf is now saved!\n", "SUCCESS: the PDF attestation was saved to 'attestation-2020-10-31_14-08.pdf'!\n", "CPU times: user 95.5 ms, sys: 11.9 ms, total: 107 ms\n", "Wall time: 8.66 s\n" ] } ], "source": [ "%%time\n", "download_name = download_attestation(details)\n", "if download_name:\n", " print(f\"SUCCESS: the PDF attestation was saved to '{download_name}'!\")" ] }, { "cell_type": "code", "execution_count": 128, "metadata": { "ExecuteTime": { "end_time": "2020-10-31T13:18:14.601919Z", "start_time": "2020-10-31T13:18:14.480571Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "-rw-r--r-- 1 lilian lilian 42K oct. 31 14:08 exemple-attestation.pdf\r\n" ] } ], "source": [ "!ls -larth *.pdf" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "On peut afficher le document PDF ainsi produit à l'intérieur du notebook Jupyter ([merci à cette réponse StackOverflow](https://stackoverflow.com/a/35655134/)) :" ] }, { "cell_type": "code", "execution_count": 130, "metadata": { "ExecuteTime": { "end_time": "2020-10-31T13:18:25.734000Z", "start_time": "2020-10-31T13:18:25.724651Z" }, "scrolled": false }, "outputs": [ { "data": { "text/html": [ "\n", " <iframe\n", " width=\"800\"\n", " height=\"500\"\n", " src=\"exemple-attestation.pdf\"\n", " frameborder=\"0\"\n", " allowfullscreen\n", " ></iframe>\n", " " ], "text/plain": [ "<IPython.lib.display.IFrame at 0x7fe07d80c400>" ] }, "execution_count": 130, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from IPython.display import IFrame\n", "IFrame(\"exemple-attestation.pdf\", width=800, height=500)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Youpi j'ai réussi!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Avec mes données\n", "\n", "Pour ne pas montrer mes données personnelles dans ce notebook (public), je les ai écrite dans un petit [fichier JSON](http://json.org), lu avec le module json de Python." ] }, { "cell_type": "code", "execution_count": 114, "metadata": { "ExecuteTime": { "end_time": "2020-10-31T13:00:55.816455Z", "start_time": "2020-10-31T13:00:55.813690Z" } }, "outputs": [], "source": [ "import json" ] }, { "cell_type": "code", "execution_count": 116, "metadata": { "ExecuteTime": { "end_time": "2020-10-31T13:01:06.749124Z", "start_time": "2020-10-31T13:01:06.494674Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "details_lilian.json: ASCII text, with no line terminators\n", "-rw-r--r-- 1 lilian lilian 182 oct. 31 13:59 details_lilian.json\n" ] } ], "source": [ "!file details_lilian.json\n", "!ls -larth details_lilian.json" ] }, { "cell_type": "code", "execution_count": 117, "metadata": { "ExecuteTime": { "end_time": "2020-10-31T13:01:07.847566Z", "start_time": "2020-10-31T13:01:07.837865Z" } }, "outputs": [], "source": [ "with open(\"details_lilian.json\", \"r\") as f:\n", " details_lilian = json.load(f)" ] }, { "cell_type": "code", "execution_count": 121, "metadata": { "ExecuteTime": { "end_time": "2020-10-31T13:03:33.476333Z", "start_time": "2020-10-31T13:03:24.886533Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Filling the form 'firstname' with value '******'...\n", "Filling the form 'lastname' with value '******'...\n", "Filling the form 'birthday' with value '**********'...\n", "Filling the form 'placeofbirth' with value '********'...\n", "Filling the form 'address' with value '*************************'...\n", "Filling the form 'city' with value '******'...\n", "Filling the form 'zipcode' with value '*****'...\n", "Filling the form 'datesortie' with value '**********'...\n", "Filling the form 'heuresortie' with value '*****'...\n", "Checking value of the form 'firstname'...\n", "Checking value of the form 'lastname'...\n", "Checking value of the form 'birthday'...\n", "Checking value of the form 'placeofbirth'...\n", "Checking value of the form 'address'...\n", "Checking value of the form 'city'...\n", "Checking value of the form 'zipcode'...\n", "Checking value of the form 'datesortie'...\n", "Checking value of the form 'heuresortie'...\n", "Clicking on '#checkbox-achats'...\n", "Clicking on 'generate-btn'...\n", "New sleeping 5 seconds...\n", "Found a new <a href='...'> link! with href = blob:https://media.interieur.gouv.fr/986c4c9d-9608-4020-a2da-05f488886ca3\n", " and it has a download = attestation-2020-10-31_14-03.pdf\n", "Downloading the file and save it!\n", "The PDF file attestation-2020-10-31_14-03.pdf is now saved!\n" ] }, { "data": { "text/plain": [ "'attestation-2020-10-31_14-03.pdf'" ] }, "execution_count": 121, "metadata": {}, "output_type": "execute_result" } ], "source": [ "download_attestation(details_lilian)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Et on peut les envoyer :" ] }, { "cell_type": "code", "execution_count": 120, "metadata": { "ExecuteTime": { "end_time": "2020-10-31T13:03:11.007206Z", "start_time": "2020-10-31T13:03:09.700472Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "-rw-r--r-- 1 lilian lilian 42K oct. 31 13:56 attestation-2020-10-31_13-56.pdf\n", "-rw-r--r-- 1 lilian lilian 42K oct. 31 13:57 attestation-2020-10-31_13-57.pdf\n", "-rw-r--r-- 1 lilian lilian 42K oct. 31 14:01 attestation-2020-10-31_14-01.pdf\n", "CP attestation-2020-10-31_13-56.pdf attestation-2020-10-31_13-57.pdf attestation-2020-10-31_14-01.pdf besson@zamok.crans.org:~/www/attestations/2020-10-31/\n", "rsync: receiving the argument(s) \u001b[01;30mattestation-2020-10-31_13-56.pdf attestation-2020-10-31_13-57.pdf attestation-2020-10-31_14-01.pdf besson@zamok.crans.org:~/www/attestations/2020-10-31/\n", "Host key fingerprint is SHA256:EJib/9V3VjjkUX6w8bk2zt8BKxmG0JK6D+PDEyLtNb0\n", "+---[ECDSA 256]---+\n", "| o. o..|\n", "| o .o o*.|\n", "| o.+ . o.++|\n", "| o ..o . + +|\n", "| . o. S. + . =.|\n", "| . o +o. o + B +|\n", "| o ++o... o o * |\n", "| ..++E. . +|\n", "| .o. o|\n", "+----[SHA256]-----+\n", "\u001b[4;01;32m\u001b[Ksending incremental file list\u001b[m\u001b[K\n", "created directory /home/besson/www/attestations/2020-10-31\n", "\u001b[37m\u001b[Kattestation-2020-10-31_13-56.pdf\u001b[m\u001b[K\n", " 42.89K \u001b[7;01;34m\u001b[K100%\u001b[m\u001b[K \u001b[01;33m\u001b[K9.65MB/s\u001b[m\u001b[K \u001b[01;36m\u001b[K0:00:00\u001b[m\u001b[K (xfr#1, to-chk=2/3)\n", "\u001b[37m\u001b[Kattestation-2020-10-31_13-57.pdf\u001b[m\u001b[K\n", " 42.87K \u001b[7;01;34m\u001b[K100%\u001b[m\u001b[K \u001b[01;33m\u001b[K6.81MB/s\u001b[m\u001b[K \u001b[01;36m\u001b[K0:00:00\u001b[m\u001b[K (xfr#2, to-chk=1/3)\n", "\u001b[37m\u001b[Kattestation-2020-10-31_14-01.pdf\u001b[m\u001b[K\n", " 42.83K \u001b[7;01;34m\u001b[K100%\u001b[m\u001b[K \u001b[01;33m\u001b[K3.40MB/s\u001b[m\u001b[K \u001b[01;36m\u001b[K0:00:00\u001b[m\u001b[K (xfr#3, to-chk=0/3)\n", "\n", "\u001b[4;01;32m\u001b[Ksent 116.28K bytes received 136 bytes 77.61K bytes/sec\u001b[m\u001b[K\n", "\u001b[4;01;32m\u001b[Ktotal size is 128.59K speedup is 1.10\u001b[m\u001b[K\n" ] } ], "source": [ "send_attestations()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Automatisation toutes les 55 minutes\n", "\n", "Je ne ferai pas ça dans Python mais avec un simple script bash et un `watch`" ] }, { "cell_type": "code", "execution_count": 71, "metadata": { "ExecuteTime": { "end_time": "2020-10-31T12:43:36.432203Z", "start_time": "2020-10-31T12:43:36.312822Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\r\n", "Usage:\r\n", " watch [options] commande\r\n", "\r\n", "Options:\r\n", " -b, --beep émet un bip si la commande sort avec un code non nul\r\n", " -c, --color interprète les séquences de couleurs et de styles ANSI\r\n", " -d, --differences[=<permanent>]\r\n", " met en évidence les changements entre mises à jours\r\n", " -e, --errexit termine si la commande sort avec un code non nul\r\n", " -g, --chgexit termine quand la sortie de la commande change\r\n", " -n, --interval <sec> secondes de délai entre mises à jours\r\n", " -p, --precise essaie d'exécuter la commande à intervalles réguliers\r\n", " -t, --no-title masque l'en-tête\r\n", " -x, --exec passe la commande à exec au lieu de « sh -c »\r\n", "\r\n", " -h, --help affiche cette aide et termine\r\n", " -v, --version affiche les informations de version et sort\r\n", "\r\n", "Pour plus de détails, consultez watch(1).\r\n" ] } ], "source": [ "!watch -help" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Conclusion\n", "\n", "C'était drôle. C'était une expérimentation. Mais ne vous servez pas de ça !" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.9" }, "toc": { "base_numbering": 1, "nav_menu": {}, "number_sections": true, "sideBar": true, "skip_h1_title": false, "title_cell": "Table of Contents", "title_sidebar": "Contents", "toc_cell": true, "toc_position": {}, "toc_section_display": true, "toc_window_display": true }, "varInspector": { "cols": { "lenName": 16, "lenType": 16, "lenVar": 40 }, "kernels_config": { "python": { "delete_cmd_postfix": "", "delete_cmd_prefix": "del ", "library": "var_list.py", "varRefreshCmd": "print(var_dic_list())" }, "r": { "delete_cmd_postfix": ") ", "delete_cmd_prefix": "rm(", "library": "var_list.r", "varRefreshCmd": "cat(var_dic_list()) " } }, "types_to_exclude": [ "module", "function", "builtin_function_or_method", "instance", "_Feature" ], "window_display": false } }, "nbformat": 4, "nbformat_minor": 4 }