Automator : indexation de fichiers + écriture de leur contenu

MojoIII

Membre enregistré
12 Juillet 2016
6
0
38
Bonjour à tous,

je me permets de poser la question à la communauté, car j'ai bien du mal à trouver une solution à mon problème.

Voilà mon objectif :
- J'ai un nombre élevé de fichiers qui contiennent tous deux sources d'informations. Ces informations sont contenus d'une part entre des balises <img> et d'autre part entre des balises <tags>.
- Le but est de créer un processus qui, pour chaque fichier, isole ces deux informations et les inscrit dans une liste (fichier texte ou autre) en face du nom dudit fichier.

Cela me donnerait par exemple une liste de ce type :
[nom_du_fichier] ; [texte_entre_balises_img] ; [texte_entre_balises_tags]

Et ça serait le bonheur...

Même si je rêve en secret que l'un de vous me mâche le travail, j'aimerais savoir pour le moment si automator (dont je ne me suis quasiment jamais servi) permet ce genre de choses.
Dans un second temps, je pourrai peut être combiner les indices que vous laisserez.

Merci, communauté.
 
Bonjour,


Ce n'est pas possible dans Automator sans un script, car Automator ne contient pas d'action pour extraire des données entre des balises.

Voici une solution simple:
Cela suppose que dans chaque fichier, le début et la fin de la balise sont sur la même ligne, que les fins de lignes soient Unix (pas Mac), que l'encodage des fichiers est identique et que le type de ces fichiers soit du "plain text" (pas des RTF, Word ou autre Office).

Dans Automator:
Ajoute des actions pour obtenir les fichiers désirés.
Ajoute l'action "Exécuter un script shell", sélectionnez "/bin/bash" et "comme arguments" dans les menus des deux boutons de l'action.
Copie/colle ce texte dans l'action "Exécuter un script shell".
Bloc de code:
for f in "$@"
do
    sed -En 's:.*<img>([^<]*)</img>:\1:p; s:.*<tags>([^<]*)</tags>:\1:p' "$f"
done

Les balises dans ce script sont <img></img> et <tags></tags>, change les noms des balises si cela est nécessaire.

Ajoute l'action "Créer un fichier texte".
C'est tout.​
 
Bonjour,

Tout d'abord merci pour la réponse rapide.
Il va donc falloir que je me penche sur la fabrication d'un script.

Le problème est que les balises ne sont pas sur la même ligne... J'aurais dû le préciser avant : il s'agit de récupérer les données de fichiers .json. Chacun d'eux liste une suite de propriétés relatives à une page web. Je n'ai besoin que de certaines d'entre elles...
Je vais fouiner du côté des possibilités offertes par les script_shell.
En espérant pouvoir bientôt poster une solution !
 
Pour des fichiers json, vous pouvez utiliser le module json dans un script Python:
Voir https://docs.python.org/2.7/library/json.html
Vous n'avez rien à installer, c'est standard dans OSX

Exemples:
Si le format est simple comme ceci:
{
"img": "xyz bla",
"ref1": "file",
"menu1": "sssssss",
"tags": "my tag x"
}
Ce sera ce script:
Bloc de code:
import json,sys
for f in sys.argv[1:]:
    with open(f, 'r') as f1:
        obj=json.load(f1)
        print obj['img']
        print obj['tags']
Un exemple plus complexe:
{
"menu": {
"img": "xyz bla",
"ref1": "file",
"menu1": "sssssss",
"tags": "my tag x"
}
}
Ce sera ce script:
Bloc de code:
import json,sys
for f in sys.argv[1:]:
    with open(f, 'r') as f1:
        obj=json.load(f1)
        print obj["menu"]["img"]
        print obj["menu"]["tags"]

Pour Automator, ce sera la même procédure que celui dans le message #2, sauf pour le script et ce sera "/usr/bin/python" au lieu de "/bin/bash"
 
Bonjour !
Encore merci pour les conseils en python. J'y connais rien en py mais j'avance doucement.
J'ai un problème d'encodage : le fichier de sortie ne comprend pas certains caractères et il m'arrive de recevoir une erreur du type : UnicodeEncodeError: 'ascii' codec can't encode character u'\ufffc' in position 0: ordinal not in range(128).
Pas top... Je continue à chercher.
 
Bonjour,


Quand on utilise la commande print dans un script python, l'encodage de sortie doit-être toujours en 'utf-8'.
Normalement, dans le Terminal, l'encodage de sortie (sys.stdout.encoding pour python) est définie en 'utf-8'.
Mais, dans Automator, l'encodage de sortie (sys.stdout.encoding pour python) n'est pas définie, il est à None, donc un caractère autre que de l'ascii donnera une erreur si on utilise la commande print.
Donc, il faut utiliser .encode('utf-8'), alors que c'est pas nécessaire quand on exécute le script dans le terminal.
Exemple:
print obj["menu"]["img"].encode('utf-8')
print obj['menu']['tags'].encode('utf-8')


Si l'encodage des fichiers n'est pas en "utf-8"
Il y aura une erreur avec la commande json.load(f1)
Il faut utiliser with codecs.open(f, 'r', 'the encoding name') as f1: au lieu de with open(f, 'r') as f1:
Important, il faut importer codecs dans la première ligne du script python.

Example pour des fichiers en Occidental (Mac OS Roman)
Bloc de code:
import json,sys,codecs
for f in sys.argv[1:]:
    with codecs.open(f, 'r', 'macroman') as f1:
        obj=json.load(f1)
        print obj['menu']['img'].encode('utf-8')
        print obj['menu']['tags'].encode('utf-8')

Exemple pour des fichiers en Unicode (UTF-16)
Bloc de code:
    with codecs.open(f,'r', encoding='utf-16') as f1:
 
Bonjour JacqR,

C'est beaucoup mieux pour l'encodage !
Cependant, un problème n'arrivant jamais seul, j'ai maintenant une autre erreur :
AttributeError: 'list' object has no attribute 'encode'.
Effectivement une partie des des obj contiennent eux-mêmes des listes sous cette forme :

Bloc de code:
{
"tags": [
    "a",
    "b",
    "c",
    "d",]
}

En effet, j'arrive à avoir un retour en faisant
Bloc de code:
print obj['tags']
Mais ce n'est pas encodé correctement...

Par ailleurs, un de mes objets me retourne :
Bloc de code:
<center><img src="https://www.zzz.net/aaa/b.png"><font size="2pt">z</font></center>

Vous me voyez venir : est il possible de faire en sorte que seule l'url soit écrite ?

Keep searching !
Merci en tout cas !
 
Bonjour,

Oui, cela ne fonctionne pas pour une liste, car il faut utiliser .encode() que sur un texte.

Donc, il faut utiliser la commande .join() sur la liste, exemples :
Si vous voulez que chaque élément dans la liste soit séparée par une ligne:
Bloc de code:
print '\n '.join(obj['tags']).encode('utf-8')
La sortie sera
Si vous voulez que chaque élément dans la liste soit sur la même ligne, séparée par un espace:
Bloc de code:
print ' '.join(obj['tags']).encode('utf-8')

Si vous voulez que chaque élément dans la liste soit sur la même ligne, séparée par une virgule et un espace:
Bloc de code:
print ', '.join(obj['tags']).encode('utf-8')


Pour un code HTML, vous pouvez utiliser le module HTMLParser :
Exemple de script:
Bloc de code:
import json,sys; from HTMLParser import HTMLParser

class myhtmlparser(HTMLParser):
    def __init__(self):
        HTMLParser.__init__(self)
    def handle_starttag(self, tag, attrs):
        if tag == mytag:
            for name, value in attrs:
                if name == myAttr: print value

mytag = 'img'   ### nom de la balise à recherché dans un texte HTML
myAttr = 'src'   ### nom de l'attribut à recherché dans la balise img
parser = myhtmlparser()   ### crée une instance

for f in sys.argv[1:]:
    with open(f, 'r') as f1:
        obj=json.load(f1)
        htmlString = obj["img"].encode('utf-8') ### on récupère le HTML
        parser.feed(htmlString) ### la sortie sera la valeur de src dans le tag img
        print ', '.join(obj['tags']).encode('utf-8')
 
Dernière édition: