Contenu | Rechercher | Menus

Annonce

Si vous avez des soucis pour rester connecté, déconnectez-vous puis reconnectez-vous depuis ce lien en cochant la case
Me connecter automatiquement lors de mes prochaines visites.

À propos de l'équipe du forum.

#1 Le 14/01/2016, à 03:44

roger64

Reconstruire des liens manquants (python?)

Bonjour

Cette question concerne des fichiers EPUB écrits en html5. J'ai souhaité une solution en python (3.4, mais 2.7 est aussi OK) car ensuite elle serait mise en œuvre avec le logiciel opensource Calibre.

Il arrive à la suite d'une erreur de scan ou de conversion que les liens vers les notes d'un livre soient brisés ou manquants. C'est une petite catastrophe pour certains livres qui peuvent en avoir jusqu'à plusieurs centaines. On peut les rétablir à l'aide d'expressions régulières. Je bute cependant sur la toute dernière étape.

Description

Les liens existent par couple: le lien aller (appel de note) qui peut se trouver n'importe où dans le texte, et le lien retour (accompagnant le texte de la note elle-même) placé dans un fichier unique à la fin du texte. Le livre contient 99 fichiers numérotés de file1 à file99. Le fichier file99 est celui qui contient tous les liens retour. Chaque lien (aller ou retour) comprend une référence et un identifiant. Ces attributs sont incrémentés (ftn1, ftn2, etc.) - ftn pour footnote. Les lettres a et b distinguent les deux parties d'un couple. La dièse sert simplement de séparateur entre le numéro de fichier et la référence proprement dite.

Voici un exemple de lien aller:

href="file99#ftn1b" id=ftn1a

À ce lien aller devrait correspondre son alter ego retour (on croise les lettres a et b. Le numéro de fichier diffère.) par exemple

href="file14#ftn1a" id=ftn1b

Situation actuelle:

Tous les liens aller sont en place et pointent correctement vers le fichier file99 contenant les notes (et les liens retour)

href=file99#ftn1b" id=ftn1a

Les liens retour sont placés dans le fichier file99. Ils sont écrits ainsi de façon fautive:

href="file99#ftn1a" id=ftn1b

Tels quels, on voit qu'ils ne peuvent pas fonctionner puisqu'il faudrait qu'ils pointent vers le numéro du fichier du lien aller au lieu de pointer sur le numéro 99 qui est leur propre fichier.

Je cherche à corriger les liens retour (incrémentés) du fichier file99.

Dernière modification par roger64 (Le 14/01/2016, à 04:08)

Hors ligne

#2 Le 14/01/2016, à 09:45

pingouinux

Re : Reconstruire des liens manquants (python?)

Bonjour,
Normalement, ce script devrait déjà récupérer tous les liens apparaissant dans les fichiers file1 à file98. Si c'est bon, on pourra voir la suite.

#!/usr/bin/python3

import re

rec_lien=re.compile('(href="file(?P<fil>\d+)#ftn(?P<id>\d+)b"\s+id=ftn(?P=id)a)')
liste_liens=[]
for num_fic in range(1,99):
   try:
      with open('file%s'%num_fic,'r') as fic: liens=rec_lien.findall(fic.read())
   except FileNotFoundError: continue
   for lien in liens:
      num_fil=lien[1]
      num_id=lien[2]
      if num_fil=='99': liste_liens.append((num_fic,num_fil,num_id,lien[0]))

for num_fic,num_fil,num_id,lien in liste_liens: 
   print("file%-2s %2s %2s => %s"%(num_fic,num_fil,num_id,lien))

Hors ligne

#3 Le 14/01/2016, à 11:15

roger64

Re : Reconstruire des liens manquants (python?)

@pingouinux

Tu travailles à une vitesse incroyable!

Nous nous retrouvons une fois tous les dix-huit mois et pour ma part avec un plaisir renouvelé.  Pour ton information deux de tes scripts sont toujours en usage sous forme d'extensions de Calibre. Pour celui-ci, je vais te demander un peu de patience parce que je suis loin de tout comprendre et il va sans doute me falloir plus de temps pour tester qu'il ne t'en a fallu pour l'écrire.

Hors ligne

#4 Le 14/01/2016, à 11:36

pingouinux

Re : Reconstruire des liens manquants (python?)

Tu peux lancer le script sans risque dans le répertoire qui contient les fichiers file1, file2... Il ne modifie aucun fichier, et va juste lister les références.

Hors ligne

#5 Le 14/01/2016, à 11:51

roger64

Re : Reconstruire des liens manquants (python?)

J'ai décompressé un EPUB. J'ai donc maintenant un dossier OEBPS comprenant 45 fichiers html. Le fichier 45 a une liste de 37 notes.

J'ai copié le texte de ton script avec Gedit et l'ai baptisé pingouinux.py. J'ai modifié les valeurs 99 en 45 et rendu le script exécutable dans Propriétés.
Je le place dans le dossier OEBPS. Je me mets sur le chemin de ce dossier, j'ouvre un terminal, je lance (avec ou sans sudo)

./pingouinux.py

mais rien ne se passe.

(tu vois que mon niveau ne s'est pas amélioré)

Edit: attends, je renomme les fichiers (grr)

Dernière modification par roger64 (Le 14/01/2016, à 11:56)

Hors ligne

#6 Le 14/01/2016, à 12:23

roger64

Re : Reconstruire des liens manquants (python?)

Je n'ai malheureusement rien obtenu de mieux. Pour éviter d'entamer une partie de ping-pong, je t'envois un lien vers le fichier file46.html qui devrait te permettre d'essayer plus rapidement qu'avec moi. Il contient 37 notes et s'affiche correctement avec gedit..

Dernière modification par roger64 (Le 14/01/2016, à 15:07)

Hors ligne

#7 Le 14/01/2016, à 14:25

pingouinux

Re : Reconstruire des liens manquants (python?)

As-tu reçu mon message privé ?

Hors ligne

#8 Le 14/01/2016, à 15:06

roger64

Re : Reconstruire des liens manquants (python?)

Maintenant que tu me préviens, oui. Si tu me donnes une adresse perso, je t'enverrai deux livres en pièces jointes.

Sinon, effectivement je n'avais pas prêté attention aux changements de dénomination. Mes file d'ordinaire sont des chapter ou Chapitre, parfois il y a un préfixe (genre body). Peut-être serait-il souhaitable de définir des variables pour adapter le script avant le lancement?

Hors ligne

#9 Le 14/01/2016, à 15:10

roger64

Re : Reconstruire des liens manquants (python?)

Pour le moment je suis en Asie.

Hors ligne

#10 Le 14/01/2016, à 15:11

pingouinux

Re : Reconstruire des liens manquants (python?)

Normalement, quand tu reçois un MP, tu as l'adresse de retour.

Hors ligne

#11 Le 14/01/2016, à 16:07

roger64

Re : Reconstruire des liens manquants (python?)

Effectivement. Fait. smile

Hors ligne

#12 Le 14/01/2016, à 17:27

pingouinux

Re : Reconstruire des liens manquants (python?)

J'ai bien reçu tes fichiers, mais les références ne correspondent absolument pas aux spécifications que tu as données en #1, même en remplaçant filen par chaptern.xhtml.

Avec des spécifications précises, je pourrai éventuellement regarder à nouveau, si ce n'est pas trop compliqué. hmm

Hors ligne

#13 Le 14/01/2016, à 18:26

pingouinux

Re : Reconstruire des liens manquants (python?)

Bon ! J'ai regardé un peu, et ai testé ce script sur les fichiers .xhtml contenus dans indochine-modif.epub.zip. Le script ne modifie aucun fichier, et génère un fichier .bis correspondant au dernier fichier de la liste (ici, c'est chapter106.xhtml.bis).

#!/usr/bin/python3

import re, sys, glob

pref,suff='chapter','.xhtml'

fichiers=glob.glob('%s*[0-9]%s'%(pref,suff))
def num_fichier(fic):
   k=re.search('%s(\d+)%s'%(pref,suff),fic)
   if k: return int(k.group(1))
fichiers.sort(key=num_fichier)
der=num_fichier(fichiers[-1])
print("der=%d"%(der))

rec_lien=re.compile('(href="%s(?P<fil>\d+)%s#ftn(?P<id>\d+)"\s+id="bodyftn(?P=id)")'%(pref,suff))
rec_lien99=re.compile('(href="%s%s%s#ftn(?P<id>\d+)"\s+id="bodyftn(?P=id)")'%(pref,der,suff))
lien99='(href="%s)%s(%s#bodyftn%%s"\s+id="ftn%%s")'%(pref,der,suff)
liste_liens=[]
for num_fic in range(1,der):
   try:
      with open('%s%s%s'%(pref,num_fic,suff),'r') as fic: liens=rec_lien.findall(fic.read())
   except FileNotFoundError: continue
   for lien in liens:
      num_fil=lien[1]
      num_id=lien[2]
      if num_fil=='%s'%der: liste_liens.append((num_fic,num_fil,num_id,lien[0]))

fichier={}
for num_fic,num_fil,num_id,lien in liste_liens:
 # print("%s%-2s%s %2s %2s => %s"%(pref,num_fic,suff,num_fil,num_id,lien))
   fichier[num_id]=str(num_fic)

with open('%s%s%s'%(pref,der,suff),'r') as fic: f99=fic.read()
f99bis=f99
for id in fichier:
   k=re.search(lien99%(id,id),f99bis)
   if k:
      f99bis=f99bis[:k.start(0)]+k.group(1)+fichier[id]+k.group(2)+f99bis[k.end(0):]

out='%s%s%s.bis'%(pref,der,suff)
try:
   with open(out,'r') as fic:
      sys.stderr.write("\nAttention : le fichier %s existe déjà\n\n"%out)
except FileNotFoundError:
   with open(out,'w') as fic: fic.write(f99bis)

Remarque : Il reste des 99 dans le script, mais uniquement dans des noms de variables. Cela correspondait à la demande initiale où tu avais 99 fichiers.

Édité : Correction suite à la remarque de roger64 #25

Dernière modification par pingouinux (Le 17/01/2016, à 07:46)

Hors ligne

#14 Le 15/01/2016, à 04:00

roger64

Re : Reconstruire des liens manquants (python?)

Bonjour

Je te remercie beaucoup pour ton aide. Ton script s'exécute en un clin d'œil alors que mon ordinateur n'est pas un foudre de guerre.
Je te prie de bien vouloir excuser les imprécisions agaçantes de l'énoncé. J'avais fait un test avec des expressions régulières comme je te l'ai dit, et j'avais effectivement employé cette formulation a et b. Je ne savais pas qu'il existait la variable der qui est bien pratique dans ce cas-là, car c'est toujours le dernier fichier qui contient les notes retour.

La seule modification que j'ai apportée à ton script est python3.5 qui m'a été installé fin décembre (je n'y avais pas prêté attention).

[roger@anterg ~]$ whereis python
python: /usr/bin/python2.7 /usr/bin/python3.5 /usr/bin/python3.5-config /usr/bin/python3.5m-config /usr/bin/python2.7-config /usr/bin/python /usr/bin/python3.5m /usr/lib/python2.7 /usr/lib/python3.5 /usr/include/python2.7 /usr/include/python3.5m /usr/share/man/man1/python.1.gz
[roger@anterg ~]$

J'obtiens un fichier chapter106.xhtml.bis parfaitement normal quand je l'ouvre avec gedit avec des liens entièrement réparés. Toutefois, le suffixe .bis provoque des difficultés quand je veux le réimporter dans l'EPUB en utilisant l'éditeur de Calibre car celui-ci gère mal ce suffixe. (Je supprime sur l'EPUB l'ancien fichier fautif 106.xhtml et j'importe 106.xhtml.bis). Si je renomme directement 106.xhtml.bis en 106.xhtml sur mon bureau je provoque des problèmes d'entité &lt; et autres bien compliqués.

Serait-il possible d'avoir un fichier de sortie avec un suffixe uniquement en .xhtml? (pas de .bis) Son nom et numéro importent peu car ils sont aisément modifiables sur l'éditeur de Calibre. Par exemple: chapter106modif.xhtml?

Dernière modification par roger64 (Le 15/01/2016, à 04:17)

Hors ligne

#15 Le 15/01/2016, à 08:54

pingouinux

Re : Reconstruire des liens manquants (python?)

Serait-il possible d'avoir un fichier de sortie avec un suffixe uniquement en .xhtml? (pas de .bis) Son nom et numéro importent peu car ils sont aisément modifiables sur l'éditeur de Calibre. Par exemple: chapter106modif.xhtml?

Il suffit de remplacer la ligne 40

out='%s%s%s.bis'%(pref,der,suff)

par

out='%s%smodif%s'%(pref,der,suff)

Hors ligne

#16 Le 15/01/2016, à 09:57

roger64

Re : Reconstruire des liens manquants (python?)

Merci beaucoup, avec toi tout semble si simple... smile

J'obtiens cependant le même type d'erreurs que précédemment. Mais ceci échappe désormais à ton contrôle puisqu'il me semble rien ne distingue désormais  le fichier .xhtml nouvellement créé des précédents sinon son intitulé.

Je vais me renseigner sur la procédure à adopter pour réinstaller proprement ce fichier dans l'EPUB. Me connaissant, ce peut tout aussi bien être une étourderie de ma part. Cela pourra demander un peu de temps même si j'espère ne pas être contraint à recréer un fichier de test.

De toute façon, je reprendrai contact dès que possible pour t'informer de la suite donnée.

Hors ligne

#17 Le 15/01/2016, à 10:10

pingouinux

Re : Reconstruire des liens manquants (python?)

Dernière version du script, avec quelques commentaires, et test dès le début de l'existence du fichier de sortie.

#!/usr/bin/python3

import re, os, sys, glob

pref,suff='chapter','.xhtml'

# Recherche du fichier de numéro le plus élevé
fichiers=glob.glob('%s*[0-9]%s'%(pref,suff))
def num_fichier(fic):
   k=re.search('%s(\d+)%s'%(pref,suff),fic)
   if k: return int(k.group(1))
fichiers.sort(key=num_fichier)
der=num_fichier(fichiers[-1])
print("der=%d"%(der))

# On vérifie que le fichier de sortie n'existe pas déjà
out='%s%smodif%s'%(pref,der,suff)
if os.path.lexists(out):
   sys.stderr.write("\nAttention : le fichier %s existe déjà\n\n"%out)
   exit(1)

# Recherche de : href="fichier#ftnx" id="bodyftnx"
rec_lien=re.compile('(href="%s(?P<fil>\d+)%s#ftn(?P<id>\d+)"\s+id="bodyftn(?P=id)")'%(pref,suff))
# Recherche de : href="dernier_fichier#ftnx" id="bodyftnx"
rec_lien99=re.compile('(href="%s%s%s#ftn(?P<id>\d+)"\s+id="bodyftn(?P=id)")'%(pref,der,suff))
# Recherche de : href="dernier_fichier#bodyftnx" id="ftnx"
lien99='(href="%s)%s(%s#bodyftn%%s"\s+id="ftn%%s")'%(pref,der,suff)

# Liste des liens dans tous les fichiers sauf le dernier
liste_liens=[]
for num_fic in range(1,der):
   try:
      with open('%s%s%s'%(pref,num_fic,suff),'r') as fic: liens=rec_lien.findall(fic.read())
   except FileNotFoundError: continue
   for lien in liens:
      num_fil=lien[1]
      num_id=lien[2]
      if num_fil=='%s'%der: liste_liens.append((num_fic,num_fil,num_id,lien[0]))

# fichier[id] : numéro du fichier qui contient le lien de numéro id
fichier={}
for num_fic,num_fil,num_id,lien in liste_liens:
 # print("%s%-2s%s %2s %2s => %s"%(pref,num_fic,suff,num_fil,num_id,lien))
   fichier[num_id]=str(num_fic)

# Modification des liens du dernier fichier
with open('%s%s%s'%(pref,der,suff),'r') as fic: f99=fic.read()
f99bis=f99
for id in fichier:
   k=re.search(lien99%(id,id),f99bis)
   if k:
      f99bis=f99bis[:k.start(0)]+k.group(1)+fichier[id]+k.group(2)+f99bis[k.end(0):]

# Écriture du résultat
with open(out,'w') as fic: fic.write(f99bis)

Édité : Correction suite à la remarque de roger64 #25

Dernière modification par pingouinux (Le 17/01/2016, à 07:47)

Hors ligne

#18 Le 15/01/2016, à 10:49

roger64

Re : Reconstruire des liens manquants (python?)

J'ai testé sur le deuxième livre, préalablement modifié. Il a 71 chapitres. Lorsque j'ouvre avec gedit le fichier qui vient d'être créé, j'ai plein de soulignements rouges que je ne comprends pas. Lorsque j'ouvre un autre fichier xhtml, toujours avec gedit, pas de soulignements.

Cela se produisait avant et continue de se produire avec la dernière version.

1452846896.png

Hors ligne

#19 Le 15/01/2016, à 11:09

roger64

Re : Reconstruire des liens manquants (python?)

En continuant à chercher, je me suis aperçu qu'il manquait un signe " juste avant le style de paragraphe BlancUn (au premier souligné rouge sur l'image). En le rajoutant et en sauvegardant, j'ai fait effacer tous les soulignements. Bizarre.. smile

Je continue à tester.

Hors ligne

#20 Le 15/01/2016, à 11:09

pingouinux

Re : Reconstruire des liens manquants (python?)

La dernière version est identique à la précédente quant au résultat; seul la présentation du script a changé.

Quand je teste sur ton exemple à 71 chapitres (tel que tu me l'as envoyé), le fichier généré chapter71modif.xhtml est identique à chapter71.xhtml.

N'utilisant pas gedit, je ne sais aps à quoi correspondent ces surlignements en rouge.

Hors ligne

#21 Le 15/01/2016, à 11:39

roger64

Re : Reconstruire des liens manquants (python?)

Firefox m'avait d'abord signalé un xml mal formé (le signe " qui manquait) au lieu d'ouvrir le fichier xhtml et ensuite cela avait effacé tout le rouge.

Mais pour l'Indochine, il me signale comme mal formé la première "erreur" un banal tag ouvrant signalé lui aussi en rouge par gedit. Je n'arrive pas à faire disparaître cette erreur même en le remplaçant par un tag signalé comme valide et le souligné rouge reste. Si je continue à me servir du fichier, pour l'importer, je me retrouve avec des entités &lt; &gt;

...

Hors ligne

#22 Le 15/01/2016, à 12:02

roger64

Re : Reconstruire des liens manquants (python?)

J'ai recommencé le essais à neuf, au cas où j'aurais corrompu le fichier, même symptômes aux mêmes endroits.

Ne perds pas plus de temps avec cette histoire, je vais me renseigner, j'ai du rater quelque chose.

Hors ligne

#23 Le 16/01/2016, à 09:51

roger64

Re : Reconstruire des liens manquants (python?)

ll me semble que l'erreur de sortie que l'on observe peut venir du fait que, sans que ton script ne soit en cause, la procédure employée pour décompresser l'EPUB, puis pour réinsérer le fichier modifié n'est pas correcte.

Voici une réponse que j'ai obtenue à ce sujet.

http://www.mobileread.com/forums/showpo … ostcount=2

Ainsi, avant de manipuler directement les fichiers xhtml, il y aurait ainsi une technique précise de décompression. Une fois le fichier modifié (et remplacé tant qu'à faire) il y aurait une autre phase spécifique de compression.

Hors ligne

#24 Le 16/01/2016, à 14:55

roger64

Re : Reconstruire des liens manquants (python?)

Je pense qu'un spécialiste de l'EPUB pourrait se saisir de l'affaire. (à suivre)  smile

Hors ligne

#25 Le 17/01/2016, à 03:05

roger64

Re : Reconstruire des liens manquants (python?)

L'erreur était causée par une parenthèse mal placée .


Doitsu a écrit :

Hi Roger,

There's a typo in your friend's script that causes it to generate invalid html files that neither Sigil nor Calibre like. BTW, you can test the validity with HTML Tidy Online.

line #27

needs to be changed from:

lien99='(href="%s)%s(%s#bodyftn%%s"\s+id="ftn%%s)"'%(pref,der,suff)

to:

lien99='(href="%s)%s(%s#bodyftn%%s"\s+id="ftn%%s")'%(pref,der,suff)

J'ai testé à nouveau sur l'EPUB Indochine en dézippant simplement puis en réimportant directement avec l'éditeur de Calibre le fichier modifié. Cette fois aucune erreur n'a été générée et tout fonctionne comme prévu.

Sinon Tidy semble être un outil à double tranchant qui signale beaucoup de faux positifs et qu'il faut se garder de suivre aveuglément. Mais il semble qu'un spécialiste puisse encore en tirer quelques infos utiles.

A l'heure actuelle, l'éditeur de Calibre détecte les liens fautifs de l'EPUB non réparé mais est incapable de les réparer comme ton script sait le faire. Je vais maintenant voir comment  intégrer ce script pour travailler directement depuis l'EPUB.

Encore bravo pour ton script génial! Merci pour ton aide et  pardonne mes imprécisions de très vieux débutant.

Dernière modification par roger64 (Le 17/01/2016, à 04:05)

Hors ligne