J'écris un robot d'exploration en Ruby (1.9) qui consomme beaucoup de HTML provenant de nombreux sites aléatoires.
En essayant d'extraire des liens, j'ai décidé d'utiliser simplement à la .scan(/href="(.*?)"/i)
place de nokogiri / hpricot (accélération majeure). Le problème est que je reçois maintenant beaucoup d' invalid byte sequence in UTF-8
erreurs " ".
D'après ce que j'ai compris, la net/http
bibliothèque n'a pas d'options spécifiques d'encodage et les éléments qui y sont fournis ne sont fondamentalement pas correctement étiquetés.
Quelle serait la meilleure façon de travailler réellement avec ces données entrantes? J'ai essayé .encode
avec l'ensemble d'options de remplacement et non valide, mais sans succès jusqu'à présent ...
109
'U*'
annuler'C*'
?Réponses:
Dans Ruby 1.9.3, il est possible d'utiliser String.encode pour "ignorer" les séquences UTF-8 invalides. Voici un extrait de code qui fonctionnera à la fois en 1.8 ( iconv ) et en 1.9 ( String # encode ):
ou si vous avez une entrée vraiment gênante, vous pouvez faire une double conversion de UTF-8 à UTF-16 et revenir à UTF-8:
la source
file_contents.encode!('UTF-16', 'UTF-8', :invalid => :replace, :replace => '')
file_contents.encode!('UTF-8', 'UTF-16')
force_encoding
. Si vous avez lu un ISO8859-1 comme UTF-8 (et que cette chaîne contient donc un UTF-8 invalide), vous pouvez le "réinterpréter" comme ISO8859-1 avec the_string.force_encoding ("ISO8859-1") et travailler simplement avec cette chaîne dans son codage réel..encode('UTF-8')
est un no-op et aucune vérification n'est exécutée. Documentation Ruby Core pour encoder . Cependant, le convertir en UTF-16 force d'abord toutes les vérifications de séquences d'octets non valides à être exécutées, et les remplacements sont effectués si nécessaire.La réponse acceptée ni l'autre réponse fonctionnent pour moi. J'ai trouvé ce post qui suggérait
Cela a résolu le problème pour moi.
la source
Ma solution actuelle est d'exécuter:
Cela éliminera au moins les exceptions qui étaient mon principal problème
la source
valid_encoding?
qui semble détecter quand quelque chose ne va pas.val.unpack('C*').pack('U*') if !val.valid_encoding?
.\xB0
dos en symboles de degrés. Même levalid_encoding?
revient vrai , mais je vérifie toujours si elle ne fonctionne pas et les caractères dépouilleront offensants à l' aide de la réponse de Amir ci - dessus:string.encode!('UTF-8', 'binary', invalid: :replace, undef: :replace, replace: '')
. J'avais également essayé l'force_encoding
itinéraire mais cela a échoué.Essaye ça:
la source
Je vous recommande d'utiliser un analyseur HTML. Trouvez simplement le plus rapide.
L'analyse HTML n'est pas aussi simple que cela puisse paraître.
Les navigateurs analysent les séquences UTF-8 non valides, dans les documents HTML UTF-8, en mettant simplement le symbole « ». Ainsi, une fois que la séquence UTF-8 invalide dans le HTML est analysée, le texte résultant est une chaîne valide.
Même à l'intérieur des valeurs d'attribut, vous devez décoder des entités HTML comme amp
Voici une excellente question qui résume pourquoi vous ne pouvez pas analyser de manière fiable le HTML avec une expression régulière: RegEx correspond aux balises ouvertes sauf les balises autonomes XHTML
la source
Cela semble fonctionner:
la source
la source
J'ai rencontré des chaînes, qui avaient des mélanges d'anglais, de russe et d'autres alphabets, ce qui a causé une exception. Je n'ai besoin que du russe et de l'anglais, et cela fonctionne actuellement pour moi:
la source
Alors que la solution de Nakilon fonctionne, au moins en ce qui concerne l'erreur, dans mon cas, j'ai converti en CSV ce personnage étrange f-ed up provenant de Microsoft Excel en CSV qui s'enregistrait en ruby en tant que (obtenez ceci) cyrillique K qui dans ruby était un K. en gras. Pour résoudre ce problème, j'ai utilisé «iso-8859-1» à savoir.
CSV.parse(f, :encoding => "iso-8859-1")
, qui a transformé mes freaky cyrillic K's en un beaucoup plus gérable/\xCA/
, que je pourrais ensuite supprimer avecstring.gsub!(/\xCA/, '')
la source
Avant de l'utiliser
scan
, assurez-vous que l'en-Content-Type
tête de la page demandée esttext/html
, car il peut y avoir des liens vers des éléments comme des images qui ne sont pas encodées en UTF-8. La page peut également être non html si vous avez choisi unhref
élément comme un<link>
élément. La façon de vérifier cela varie en fonction de la bibliothèque HTTP que vous utilisez. Ensuite, assurez-vous que le résultat est uniquement ascii avecString#ascii_only?
(pas UTF-8 car HTML est censé utiliser uniquement ascii, les entités peuvent être utilisées autrement). Si ces deux tests réussissent, leur utilisation est sûrescan
.la source
Si vous ne vous «souciez» pas des données, vous pouvez simplement faire quelque chose comme:
search_params = params[:search].valid_encoding? ? params[:search].gsub(/\W+/, '') : "nothing"
J'avais l'habitude
valid_encoding?
de le faire passer. Le mien est un champ de recherche, et donc je trouvais la même bizarrerie encore et encore, alors j'ai utilisé quelque chose comme: juste pour que le système ne se brise pas. Étant donné que je ne contrôle pas l'expérience utilisateur pour procéder à une validation automatique avant d'envoyer ces informations (comme un retour automatique pour dire "factice!"), Je peux simplement les intégrer, les supprimer et renvoyer des résultats vides.la source