ERG::Code-2019-1
Introduction
Ce cours est destiné aux étudiant.e.s de BAC2. Cette année, nous nous concentrons sur le rapport du numérique au texte. Les interactions textuelles avec les machines, le code générateur de poésie, le code en tant que poésie, le code secret, le code caché. Nous serons amenés à créer des poésies algorithmiques, des générateurs de textes, des machines à plagier, des bots twitter, des ordinateurs qui parlent. À travers différentes expérimentations menées en atelier, nous aborderons plusieurs langages de programmation, concepts informatiques et exemples dans les champs de l'art, du design, de l'histoire de l'informatique et autres.
Pages des étudiants
Séances
15/03/2020: schémas
Pour cette première session à distance, je vous propose de réaliser un schéma le plus détaillé possible de votre programme. En partant du principe que le programme sera hébergé sur un serveur et qu'il sera lancé toutes les 5 minutes, le schéma doit détailler chaque étape de son fonctionnement. Vous pouvez réaliser le schéma à la main ou via un logiciel de dessin ou de création de diagrammes (draw.io - https://app.diagrams.net/ -, http://asciiflow.com/, etc.).
02/03/2020: web scraping
Librairies Python
- pour naviguer:
- pycurl (http://pycurl.io/)
- urllib2 (https://docs.python.org/2/library/urllib2.html)
- requests (https://requests.readthedocs.io/en/master/)
- mechanize (https://mechanize.readthedocs.io/en/latest/index.html)
- pour parser:
- beautifulsoup (https://www.crummy.com/software/BeautifulSoup/bs4/doc/)
- lxml (https://lxml.de/xpathxslt.html)
- cssselect (https://cssselect.readthedocs.io/en/latest/)
- User agent :
('User-agent', 'Mozilla/5.0 (X11; Linux x86_64; rv:69.0) Gecko/20100101 Firefox/69.0')
- What is my browser (https://www.whatismybrowser.com/guides/the-latest-user-agent/firefox)
#!/usr/bin/python
# -*- coding: utf-8 -*-
import mechanize
import lxml.html as parser
import cssselect
#01. naviguer sur le site cible
### on déclare un browser
br = mechanize.Browser()
### on ajoute des infos sur le navigateur
br.addheaders = [('User-agent', 'Mozilla/5.0 (X11; Linux x86_64; rv:69.0) Gecko/20100101 Firefox/69.0')]
### on ignore la gestion des robots du serveur
br.set_handle_robots(False)
### on récupère le code source de la page
data = br.open('https://poesie.webnet.fr/lesgrandsclassiques/Authors/B', timeout=10)
#print(data.read())
#02. parser la source pour récupérer les liens
source = data.read()
#unicode_src = source.decode('utf-8', 'ignore')
tree = parser.fromstring(source)
##pour chaque objet de type selector déduit du sélecteur css
for selector in cssselect.parse('.author-list__link'):
##on convertit l'objet selector en xpath
xpath_selector = cssselect.HTMLTranslator().selector_to_xpath(selector)
##pour chaque lien trouvé par ce xpath
for link in tree.xpath(xpath_selector):
print(link.get('href'))
print(link.text_content())
#!/usr/bin/python
# -*- coding: utf-8 -*-
import mechanize
import lxml.html as parser
import cssselect
import random
def getHtmlTree(url):
### on récupère le code source de la page
data = br.open(url, timeout=10)
#print(data.read())
#02. parser la source pour récupérer les liens
source = data.read()
#unicode_src = source.decode('utf-8', 'ignore')
tree = parser.fromstring(source)
return tree
def getRandomLink(url, cssSelector):
tree = getHtmlTree(url)
##pour chaque objet de type selector déduit du sélecteur css
for selector in cssselect.parse(cssSelector):
##on convertit l'objet selector en xpath
xpath_selector = cssselect.HTMLTranslator().selector_to_xpath(selector)
##pour chaque lien trouvé par ce xpath
links = tree.xpath(xpath_selector)
return random.choice(links).get('href')
#01. naviguer sur le site cible
### on déclare un browser
br = mechanize.Browser()
### on ajoute des infos sur le navigateur
br.addheaders = [('User-agent', 'Mozilla/5.0 (X11; Linux x86_64; rv:69.0) Gecko/20100101 Firefox/69.0')]
### on ignore la gestion des robots du serveur
br.set_handle_robots(False)
link1 = getRandomLink('https://poesie.webnet.fr/lesgrandsclassiques/Authors/B', '.author-list__link')
#print('https://poesie.webnet.fr'+link1)
url = '%s%s' % ('https://poesie.webnet.fr', link1)
poemeurl = '%s%s' % ('https://poesie.webnet.fr', getRandomLink(url, '.author-list__link'))
poemeTree = getHtmlTree(poemeurl)
#.poem__content
for selector in cssselect.parse('.poem__content'):
##on convertit l'objet selector en xpath
xpath_selector = cssselect.HTMLTranslator().selector_to_xpath(selector)
##pour chaque poème trouvé par ce xpath
poems = poemeTree.xpath(xpath_selector)
print(poems[0].text_content())
#print(poem.text_content())
09/02/2020: writing bot - Twitter API
- Créer un compte Twitter (https://twitter.com/)
- Convertir le compte en compte développeur (https://developer.twitter.com/en/apps)
- Attendre la validation de la conversion par Twitter
- Si Twitter envoie un mail demandant des précisions, répondre au mail.
- Une fois le compte validé, aller à nouveau sur https://developer.twitter.com et cliquer sur "créer une app".
- Générer les clés "access token" et "access token secret"
- Enregistrer les 4 clés "consumer API", "consumer API secret", "access token" et "access token secret".
Voir https://help.twitter.com/en/rules-and-policies/twitter-automation pour les règles de Twitter
http://docs.tweepy.org/en/latest/
from credentials import *
import tweepy
auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
auth.set_access_token(access_token, access_token_secret)
api = tweepy.API(auth)
'''
tweet = 'Tu veux un camembert?'
api.update_status(status=tweet)
'''
'''
for tweet in tweepy.Cursor(api.search, q='camembert', tweet_mode="extended").items(10):
print(tweet.full_text)
'''
'''for tweet in tweepy.Cursor(api.user_timeline, '@Lagarde').items(10):
print(tweet.text)'''
03/01/2020: writing bot: introduction
À propos de robots qui génèrent du texte.
Imaginer un robot qui intervient en postant du texte sur un ou plusieurs réseaux sociaux; mastodon, youtube, instagram, facebook, twitter, etc. Écrire une description de ce robot et la poster sur le wiki. La description doit répondre aux questions suivantes: - quelle(s) source(s) pour le texte - quels types de traitements sont utilisés pour générer le texte (penser aux traitements développés pendant le premier quadri) - qu'est-ce qui déclenche le post? - quel canal est utilisé pour le post?
@everyword, Allison Parrish: https://twitter.com/everyword
@nicetipsbot, Thricedotted: https://twitter.com/nice_tips_bot
@tinycarebot, Jonny Sun: https://twitter.com/tinycarebot
@infinite_scream, Nora Reed: https://twitter.com/infinite_scream
Darius Kazemi: http://tinysubversions.com/projects/
@predartbot, Maria Roszkowska et Nicolas Maigret: http://artbot.space/
Des bots qui n'écrivent pas mais qui agissent sur le web
https://wwwwwwwwwwwwwwwwwwwwww.bitnik.org/r/
09/12/2019: intro html css to print
Projet pour la fin du quadri
À partir d'une sélection de poèmes générés via les programmes écrits jusqu'ici en python, faire une édition à la fois en ligne et en print. La version en ligne doit être uploadée sur le serveur du cours. La version papier sera présentée au dernier cours; le 16/12.
Intro html/css
Démo: [1]
04/11/2019: Python suite et fin + INTERNET
Dernier énoncé
Le programme demande à l'utilisateur le nombre de vers à générer. Le programme génère autant de vers aléatoires que le nombre entré par l'utilisateur, à partir des mots du poème source et en utilisant la formule syntaxique "article + nom + complément + verbe" Une fois que ça marche deux améliorations possibles: * accorder en genre et en nombre les phrases (ortographe inclusive ou non) * avoir plusieurs formules syntaxiques et les choisir aléatoirement (ou selon une certaine logique) à chaque vers
#!/usr/bin/env python # -*- coding: utf-8 -*- import random with open('poeme', 'r') as tete: poeme = tete.read() article = ["la", "le", "Un", "Les" ] nom = ["voiture", "pied", "ceval", "ame", "vie", "flux", "nuit", "ciel", "Je", "tout", "j'", "Il", "jour", "oiseaux" ] verbe = ["bouge", "crisse", "etait", "est", "suis", "aime", "saigne", "va", "leve", "chantent"] complement = ["rose", "cosmique", "loin", "gris", "hauteur", "peu", "tot" ] print("Combien de vers souhaites tu génerer?") nombre = int(raw_input()) for compteur in range (0,nombre): print(random.choice(article) + " " + random.choice(nom)+ " " + random.choice(verbe)+ " " + random.choice(complement))
14/10/2019: écriture de programme Python
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#Un script qui suit l'idée du livre dont vous êtes le héros, avec des réponses OUI on NON. Ex: La voiture bouge OU le cheval rose? réponse:
#Le programme donne le choix entre le vers n°1 ou le vers n°3
#Selon le choix de l'utilisateur, il affiche le vers 1 et le vers 2 ou le vers 3 et le vers 4
#Le choix est gardé en mémoire pour afficher le poème résultant à la fin du script
#1 charger le poème dans une variable
with open('poeme', 'r') as tete:
poeme = tete.read()
'''
La voiture bouge
Le pied crisse
Le ceval rose
Perdant son ame
Qu'etait la vie
Le flux cosmique
La nuit est loin,
Le ciel est gris
Je suis tombee
Tout en hauteur
5lK5J 8.21JsMc1Js
j'aime la nuit
Il saigne peu,
Et s'Vk va tot
Un jour se leve
Les oiseaux chantent
'''
print(poeme)
'''
0 1 2 3 4 5 6 7
['La voiture bouge', 'Le pied crisse', 'Le ceval rose', 'La voiture bouge', 'Le pied crisse', 'Le ceval rose', 'Le pied crisse', 'Le ceval rose']
['v', 'o', 'i', 't', 'u', 'r', 'e']
'''
#2 décomposer le poème en lignes (et stocker le résultat dans un tableau)
lignes = poeme.splitlines()
'''
print("Choisissez entre ces deux vers:")
print(" Pour "+lignes[0]+" tapez 1")
print(" Pour "+lignes[2]+" tapez 2")
#choix = input()
choix = int(raw_input())
if(choix == 1):
print(lignes[0])
print(lignes[1])
else:
print(lignes[2])
print(lignes[3])
print("Choisissez entre ces deux vers:")
print(" Pour "+lignes[4]+" tapez 1")
print(" Pour "+lignes[6]+" tapez 2")
#choix = input()
choix = int(raw_input())
if(choix == 1):
print(lignes[4])
print(lignes[5])
else:
print(lignes[6])
print(lignes[7])
'''
reponses = ''
for compteur in range(0, len(lignes), 4):
print("Choisissez entre ces deux vers:")
print(" Pour "+lignes[compteur]+" tapez 1")
print(" Pour "+lignes[compteur+2]+" tapez 2")
#choix = input()
choix = int(raw_input())
if(choix == 1):
reponses = reponses + str(choix)
print(lignes[compteur])
print(lignes[compteur + 1])
else:
reponses = reponses + str(choix)
print(lignes[compteur + 2])
print(lignes[compteur + 3])
#reponses = 1212
'''
0 1 2 3
1 2 1 2
0 1 6 7 8 9 14 15
'''
print(reponses)
for compteur in range(0, len(reponses)):
choix = int(reponses[compteur])
#on affiche les lignes correspondantes
if(choix == 1):
#print(lignes[0])
#print(lignes[1])
#print(lignes[4])
#print(lignes[5])
print(lignes[compteur * 4])
print(lignes[compteur * 4 + 1])
else:
#print(lignes[2])
#print(lignes[3])
#print(lignes[6])
#print(lignes[7])
print(lignes[compteur * 4 + 2])
print(lignes[compteur * 4 + 3])
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#Le script decidera quelle phrase va le mieux avec la personalité de l'utilisateur en fonction de sa ville de naissance (addition de la valeur de chaque lettre). Si la valeur numérique de la ville est plus grande que le nombre de phrases disponibles, le compteur 'recommence'. Si l'utilisateur veut connaitre son mot préféré, il peut le faire en fonction de son âge multiplié par sa ville.
import string
import unicodedata
#1 charger le poème dans une variable
with open('poeme', 'r') as tete:
poeme = tete.read()
lignes = poeme.splitlines()
print("Où es-tu né(e)?")
#ville = input()
ville = raw_input()
ville = unicodedata.normalize('NFD', unicode(ville, 'utf-8')).encode('ascii', 'ignore')
ville = ville.lower()
asciiChars = list(string.ascii_lowercase)
'''
bruxelles
['a', 'b'...]
'''
nbreVille = 0
for compteur in range(0, len(ville)):
searchLettre = ville[compteur]
for compteur2 in range(0, len(asciiChars)):
laLettreQuonRegarde = asciiChars[compteur2]
if(laLettreQuonRegarde == searchLettre):
nbreVille = nbreVille + compteur2
break
'''
while nbreVille >= len(lignes):
nouveauNombre = 0
for compteur in range(0, len(str(nbrVille))):
nouveauNombre = nouveauNombre + int(nbrVille[compteur])
nbreVille = nouveauNombre
'''
nbreVille = nbreVille % len(ville)
print(lignes[nbreVille])
07/10/2019: introduction Python
Boucles et variables
#!/usr/bin/env python
#!python
# -*- coding: utf-8 -*-
'''
Un programme qui demande le prenom de l'utilisateur
dlkdsqjdsq
'''
print("Qui est-ce?")
#input()
bloup = raw_input()
'''
print("Salut "+bloup)
print("Salut "+bloup)
print("Salut "+bloup)
print("Salut "+bloup)
print("Salut "+bloup)
print("Salut "+bloup)
print("Salut "+bloup)
print("Salut "+bloup)
print("Salut "+bloup)
'''
#boucle infinie
'''while True:
print("Salut "+bloup)'''
#boucle while avec compteur
'''
compteur = 0
while compteur < 10:
print("Salut "+bloup)
compteur = compteur + 1
'''
#boucle for
'''
for compteur in range(0, 100):
print("Salut "+bloup+" "+str(compteur))
'''
'''
0 1 2 3 4 5
[L | i | o | n | e | l]
'''
#print(bloup[2])
#le nombre de cases (de caracteres) de la variable bloup
print(len(bloup))
Conditions
#!/usr/bin/env python
# coding: utf-8
'''
<
>
>=
<=
==
!=
'''
print("Quel est ton age?")
age = int(raw_input())
if age < 10:
for compteur in range(0, age):
print(compteur)
if compteur == 5:
print("déjà 5 ans!")
print "Oh ben t'es tout petit"
elif age < 20:
print("Oh ben t'es tout jeune")
elif age < 30:
print("Oh ben t'es presque vieux")
else:
print "Oh ben t'es tout vieux"
print("Tu vas mourir dans "+str(88 - age))
Exercice
Écrire un scénario de script python pour traiter le poème collectif; mettre ce scénario dans la page personnelle sur le wiki.
30/09/2019 :introduction langages
Poésie binaire: suite
1001100 1100001 1011111 1110110 1101111 1101001 1110100 1110101 1110010 1100101 1011111 1100010 1101111 1110101 1100111 1100101 1001100 1100101 1011111 1110000 1101001 1100101 1100100 1011111 1100011 1110010 1101001 1110011 1110011 1100101 1001100 1100101 0100000 1100011 1100101 1110110 1100001 1101100 0100000 1110010 1101111 1110011 1100101 1010000 1100101 1110010 1100100 1100001 1101110 1110100 0100000 1110011 1101111 1101110 0100000 1100001 1101101 1100101 1010001 1110101 0100111 1100101 1110100 1100001 1101001 1110100 0100000 1101100 1100001 0100000 1110110 1101001 1100101 1001100 1100101 0100000 1100110 1101100 1110101 1111000 0100000 1100011 1101111 1110011 1101101 1101001 1110001 1110101 1100101 1001100 1100001 0100000 1101110 1110101 1101001 1110100 0100000 1100101 1110011 1110100 0100000 1101100 1101111 1101001 1101110 0101100 1001100 1100101 0100000 1100011 1101001 1100101 1101100 0100000 1100101 1110011 1110100 0100000 1100111 1110010 1101001 1110011 1010011 1101111 1110101 1110011 0100000 1101100 0100111 1101111 1100011 1100101 1100001 1101110 0100000 1101100 1100101 0100000 1100011 1101111 1110010 1100001 1101001 1101100 0100000 1100100 1101111 1110010 1110100 10010101100101010000011100111110101110100111100110100000111010011011111101101110001011001011100101 101010011011111110101111010001000001100101110111001000001101000110000111101011110100110010111101011110010 1101010 0100111 1100001 1101001 1101101 1100101 1101100 1100001 1101110 1110101 1101001 1110100 1001001 1101100 0100000 1110011 1100001 1101001 1100111 1101110 1100101 0100000 1110000 1100101 1110101 0101100 1000101 1110100 0100000 1110011 0100111 1010110 1101011 0100000 1110110 1100001 0100000 1110100 1101111 1110100 1010101 1101110 1101010 1101111 1110101 1110010 1110011 1100101 1101100 1100101 1110110 1100101 1001100 1100101 1110011 1101111 1101001 1110011 1100101 1100001 1110101 11110001100011 1101000 1100001 1101110 1110100 1100101 1101110 1110100 1001010 0100111 1100001 1101001 0100000 1110110 1110101 0100000 1101100 1100001 0100000 1101101 1100101 1110010 1010011 1110101 1110010 0100000 1101100 0100111 1001001 1101110 1110100 1100101 1110010 1101110 1100101 1110100 1010001 1110101 1101001 0100000 1110110 1100101 1110101 1110100 0100000 1100010 1101001 1100101 1101110 0100000 1100100 1101111 1101110 1101110 1100101 1110010 0110001 0110000 1101000 0100000 1100100 1100100 0100000 1110011 1100101 1110011 0100000 1101010 1101111 1110101 1110010 1101110 1100101 1100101 1110011 0111111
Le code ci-dessus converti en caractères (binaire vers ASCII) grâce à moulinette.py:
La voiture bouge Le pied crisse Le ceval rose Perdant son ame Qu'etait la vie Le flux cosmique La nuit est loin, Le ciel est gris Je suis tombee Tout en hauteur 5lK5J 8.21JsMc1Js j'aime la nuit Il saigne peu, Et s'Vk va tot Un jour se leve Les oiseaux chantent
23/09/2019: texte et code
Notes
* spécificité numérique ** virtuel, intangible ** source d'énergie, réseau (électrique ou autre) ** information codée, binaire ----> 0 1 compter en: base 10 0 1 2 3 4 5 6 7 8 9 10 base 4 0 1 2 3 10 11 12 13 20 base 2 (binaire) 0 1 10 11 100 101 110 111 1000 à chaque colonne une valeur: 16 8 4 2 1 1 0 1 1 1 comme en base 10: 90 9 1 0 0 coder une couleur 128 64 32 16 8 4 2 1 1 1 1 1 1 1 1 1 0000 0000 0000 0010 = 256 valeurs possibles (en comptant le 0 comme une valeur) pour chaque canal de couleur (Rouge, Vert, Bleu) 1 canal est codé en 00000000 = 8 bits = 1 byte = 1 octet. on peut donc coder une couleur avec 3 octets, souvent représentés en base 16 (hexadécimal): FF0000
Slides
Voir: slides 01: texte et code
1. INTERNATIONAL MORSE CODE, HAND SENDING - https://archive.org/details/gov.archives.arc.36813 Department of Defense. Department of the Army. Office of the Chief Signal Officer. (09/18/1947 - 02/28/1964)
- Le code morse, inventé par Samuel F. B. Morse en 1832.
- Directions pour tracer les lettres
- Les confusions possibles si l'opérateur fait une erreur de rythme
2. TM 11-459 International Morse Code (Instruction) - 1959 - https://archive.org/details/Tm11-4591957/page/n3
- Le télégraphe "a contribué plutôt à lier inextricablement la technologie et la place de l'humain" (K. Hayles - Lire et penser en milieux numériques p. 223)
3. Direct service guide for telegraphic cipher - 1939 - https://archive.org/details/directservicegui00sldu/page/20
- Premier objectif: la compression (pour des raisons économiques)
- 2e objectif: la discrétion
- 3e objectif: le controle des erreurs
4. Bentley's second phrase code - 1929 - https://archive.org/details/bentleyssecondph00bent/page/778
- Les codes ne sont plus liés au langage naturel
5. Idem
- Ici, un "tableau de mutilation" qui permet de corriger un code mal transmis (qui contient une erreur d'une lettre)
6. Teleprinter n°7 - Creed & Company - 1930
- Frederick G. Creed, inventeur du téléscripteur (vers 1910), ancien télégraphiste, canadien
7. Un exemple de téléscripteur - 1932, Londres
8. Code baudot - 1888
- Un encodage des caractères sur 5 chiffres, 5 bits
- Utilisé (dans des versions ultérieures) sur les premiers téléscripteurs
- Nécessité de définir une vitesse de modulation, "baudrate" en anglais, qui définit le nombre de symboles envoyés en 1 seconde -> la question du début et de la fin!
- Donald Murray adapte le code baudot en 1902 et attribue aux lettres les plus utilisées de l'alphabet les positions impliquant le moins de trous
- En 1924, adaptation du code baudot-Murray par l'organisme International Telegraph Union en International Telegraph Alphabet No. 2 (ITA2)
9. ASCII - American Standard Code for Information Interchange - 1963 - pré 1971
- sur 7 bits
Exercice : poésie binaire
Chaque étudiant.e écrit sur un pad commun au moins deux vers de 4 pieds en binaire en utilisant le tableau de conversion ASCII suivant:
Fichier:Binarypoetry-2019-09-23 14.06.43 cut.mp4
Déroulement du cours
Le cours ne nécessite aucun prérequis si ce n'est une capacité d'attention pendant les séances. Cette attention implique qu'à certains moments, par exemple lors des moments de discussions ou de présentations, il sera demandé aux étudiant.e.s de fermer leur ordinateur, que l'usage des smartphones est interdit et que les étudiant.e.s doivent arriver à l'heure au cours (9h, le lundi matin).
Comme il s'agit d'un cours technique, les travaux se feront majoritairement en classe et il n'est pas absolument nécessaire de travailler en dehors du cours, à part pour documenter les travaux ou préparer leurs présentations (les cotations).
Le cours fonctionne en évaluation continue, ce qui signifie que chaque exercice réalisé en atelier aura une note attribuée. Pour réussir le cours, il faut essentiellement être présent.e.
À cette évaluation continue s'ajoute deux notes en décembre et en mai qui correspondent aux moments de cotations. Il est demandé pour ces cotations de présenter une sélection des travaux réalisés jusque là.
La difficulté technique, bien que présente, ne doit pas constituer une barrière pour assister au cours. Il ne sera pas demandé aux étudiant.e.s d'être performant.e.s mais plutôt de ne pas se braquer et d'accepter d'être inefficaces durant des périodes qui semblent parfois longues (voire trouver du plaisir dans ces périodes de recherches). L'entraide et le partage sont encouragés. Tout sera fait pour éviter des comportements de mise à distance du savoir entre celles et ceux "qui savent" et les "newbies".
Chaque étudiant.e a accès à ce wiki, qui servira durant toute l'année à documenter les travaux. La création des comptes pour le wiki se fait au début du deuxième cours (au moment de l'inscription au cours).