2011-12-25 13 views
5

Próbuję parsować dowolne dokumenty pobierane z dzikiej sieci i tak, nie mam kontroli nad ich zawartością.Piękna zupa podnosi UnicodeEncodeError "porządkowy nie w zasięgu (128)"

Od Beautiful Soup won't choke if you give it bad markup... Zastanawiam się, dlaczego to daje mi te Hick-upy, kiedy czasami część z doc jest uszkodzony i czy istnieje sposób, aby powrócić do następnego czytelnej części dokumentu, niezależnie od tego błąd.

Linia którym wystąpił błąd jest 3rd jednego:

from BeautifulSoup import BeautifulSoup as doc_parser 
reader = open(options.input_file, "rb") 
doc = doc_parser(reader) 

CLI pełne wyjście jest:

Traceback (most recent call last): 
    File "./grablinks", line 101, in <module> 
    sys.exit(main()) 
    File "./grablinks", line 88, in main 
    links = grab_links(options) 
    File "./grablinks", line 36, in grab_links 
    doc = doc_parser(reader) 
    File "/usr/local/lib/python2.7/dist-packages/BeautifulSoup.py", line 1519, in __init__ 
    BeautifulStoneSoup.__init__(self, *args, **kwargs) 
    File "/usr/local/lib/python2.7/dist-packages/BeautifulSoup.py", line 1144, in __init__ 
    self._feed(isHTML=isHTML) 
    File "/usr/local/lib/python2.7/dist-packages/BeautifulSoup.py", line 1186, in _feed 
    SGMLParser.feed(self, markup) 
    File "/usr/lib/python2.7/sgmllib.py", line 104, in feed 
    self.goahead(0) 
    File "/usr/lib/python2.7/sgmllib.py", line 143, in goahead 
     k = self.parse_endtag(i) 
    File "/usr/lib/python2.7/sgmllib.py", line 320, in parse_endtag 
    self.finish_endtag(tag) 
    File "/usr/lib/python2.7/sgmllib.py", line 358, in finish_endtag 
    method = getattr(self, 'end_' + tag) 
UnicodeEncodeError: 'ascii' codec can't encode characters in position 15-16: ordinal not in range(128) 
+0

jaki rodzaj danych wprowadzasz do BeautifulSoup? Zgodnie z komunikatem o błędzie, być może analizujesz niektóre dane nie-ascii (na przykład zawierające znaki inne niż łacińskie)? –

+0

Parsuję dane pochodzą z dzikiej sieci, a jej części są zdecydowanie nie-ascii. –

Odpowiedz

2

Tak, będzie się dusić, jeśli masz elementy o nazwach innych niż ASCII (<café>). I to nie jest nawet "zły markup", dla XML ...

Jest to błąd w sgmllib, którego używa BeautifulSoup: próbuje znaleźć niestandardowe metody o takich samych nazwach jak znaczniki, ale w Pythonie 2 nazwy metod są ciągami bajtów więc nawet szukając dla metody ze znakiem spoza ASCII, który nigdy nie będzie obecny, nie powiedzie się.

Możesz zhackować poprawkę do sgmllib, zmieniając wiersze 259 i 371 z except AttributeError: na except AttributeError, UnicodeError:, ale to nie jest dobra poprawka. Nie trywialne, aby zastąpić resztę metody.

Co próbujesz przeanalizować? BeautifulStoneSoup zawsze był wątpliwą użytecznością - XML ​​nie ma bogactwa upiornych haseł parsera, które robi HTML, więc ogólnie zepsuty XML nie jest XMLem. W związku z tym powinieneś generalnie używać zwykłego starego parsera XML (np. Użyj standardowego DOM lub etree). W przypadku parsowania ogólnego HTML, obecnie lepszym rozwiązaniem jest opcja html5lib.

+0

Sugerowana przez ciebie poprawka nie zadziała w ogóle, ponieważ błąd zaczyna się wcześniej, gdy parser próbuje dopasować znacznik _start_ za pomocą wyrażenia regularnego, które obsługuje tylko znaki nie będące znakami ASCII. Oznacza to, że poprawny tag startowy zostanie pominięty, nawet przed wystąpieniem "UnicodeEncodeError". – ekhumoro

+0

@bobince, poszedłem za twoją sugestią i dodałem 'UnicodeError',' UnicodeEncodeError' i 'UnicodeDecodeError' (zobacz na https://gist.github.com/1520499#L331) dla * _endtag i * _startag metod - i teraz mam oczekiwane wyniki, po prostu pomijają części binarne i wyodrębniają tylko odpowiednie fragmenty. Dzięki! –

0

Dzieje się tak, jeśli istnieją non-ASCII znaków w wejściu w wersjach Pythona przed Python 3.0

Jeśli próbujesz użyć str(...) na łańcuchu zawierającym znaki o wartości znaku> 128 (ANSII & Unicode), tym wyjątkiem jest r aised.

Tutaj może wystąpić błąd, ponieważ getattr próbuje użyć str na łańcuchu Unicode - "myśli", że może to bezpiecznie zrobić, ponieważ w wersjach Pythona wcześniejsze niż 3.0 identyfikatory nie mogą zawierać kodu Unicode.

Sprawdź kod HTML pod kątem znaków Unicode. Spróbuj wymienić/zakodować te, a jeśli nadal nie działa, powiedz nam.

Powiązane problemy