Kaunis keitto- "Näytönkaapijan ystävä" -http://www.crummy.com/software/BeautifulSoup/
Beautiful Soup jäsentää (mahdollisesti virheellisen) XML- tai HTML-asiakirjan apuun esitys. Se tarjoaa menetelmiä ja pytonisia idioomeja, jotka tekevätpuussa on helppo navigoida, etsiä ja muokata.
Hyvin muotoiltu XML/HTML-dokumentti tuottaa hyvin muotoiltua dataarakenne. Väärin muotoiltu XML/HTML-dokumentti tuottaa vastaavanhuonosti muotoiltu tietorakenne. Jos asiakirjasi on vain paikallisestihyvin muotoiltu, voit käyttää tätä kirjastoa löytääksesi ja käsitelläksesihyvin muotoiltu osa sitä.
Beautiful Soup toimii Python 2.2:n ja sitä uudempien kanssa. Sillä ei ole ulkopuolistariippuvuudet, mutta onnistut paremmin muuntamaan tiedot UTF-8-muotoonjos asennat myös nämä kolme pakettia:
* Chardet merkkikoodausten automaattiseen tunnistamiseen
* cjkcodecs ja iconv_codec, jotka lisäävät koodauksia tuettuihin
- varastolla Python.
Beautiful Soup määrittelee luokat kahdelle tärkeimmälle jäsennysstrategialle:
Kaunis StoneSoup, XML-, SGML- tai verkkotunnuskohtaisen jäsentämiseen
- kieli, joka näyttää XML:ltä.
Kaunis keitto, tavanomaisen HTML-koodin jäsentämiseen, oli se sitten voimassa
- tai virheellinen. Tällä luokalla on verkkoselaimen kaltainen heuristiikkajärkevän jäsennyspuun hankkiminen yleisten HTML-virheiden varalta.
Kaunis keitto määrittelee myös luokan (UnicodeDammit) automaattista tunnistamista vartenHTML- tai XML-dokumentin koodaus ja sen muuntaminenUnicode. Suuri osa tästä koodista on otettu Mark Pilgrimin Universal Feed Parserista.
Katso lisätietoja kauniista keitosta kuin koskaan halusi tietäädokumentointi:http://www.crummy.com/software/BeautifulSoup/documentation.html
Tässä vähän lakia:
Tekijänoikeus (c) 2004-2008, Leonard Richardson
Kaikki oikeudet pidätetään.
Uudelleenjakelu ja käyttö lähde- ja binäärimuodoissa, joko kanssa tai ilmanmuutokset ovat sallittuja, jos seuraavat ehdot täyttyvättavannut:
- Lähdekoodin uudelleenjakelun tulee säilyttää yllä mainitut tekijänoikeudet
- huomautus, tämä luettelo ja seuraava vastuuvapauslauseke.
- Binäärimuodossa olevien uudelleenjakelujen on toistettava yllä oleva
- tekijänoikeusilmoitus, tämä luettelo ja seuraavat asiatvastuuvapauslauseke asiakirjoissa ja/tai muussa toimitetussa materiaalissajakelun kanssa.
- Ei myöskään Beautiful Soup Consortiumin nimi ja kaikki
- Night Kosher Bakery tai sen avustajien nimet voivat ollakäytetään tästä ohjelmistosta johdettujen tuotteiden tukemiseen tai mainostamiseenilman erityistä kirjallista lupaa.
TÄMÄN OHJELMISTON TOIMITTAVAT TEKIJÄNOIKEUDEN HALLITTAJAT JA TUOTTAJAT"SELLAISENAAN" JA KAIKKI NIMENOMAISET TAI OLUETUT TAKUUT, MUKAAN LUKIEN, MUTTA EIRAJOITETTU OLOSUHTEISIIN TAKUIHIN MYYNTIKELPOISUUDESTA JA SOVELTUVUUDESTATIETTYÄ TARKOITUSTA KIELTYY. MITÄÄN TAPAUKSESSA TEKIJÄNOIKEUDEN OMISTAJA TAITEKIJÄT OVAT VASTUUSSA SUORISTA, EPÄSUORISTA, SATUNNAISISTA, ERIKOISISTA,ESIMERKKEJÄ TAI VÄLILLISET VAHINGOT (mukaan lukien, EI RAJOITETTU,KORVAUSTAVAROIDEN TAI PALVELUJEN HANKINTA; KÄYTÖN, TIETOJEN MENETYKSET TAITULOT; TAI LIIKETOIMINNAN KESKEYTYS) MIKSI AIHEUTTAA JA MITÄ tahansa TEORIAAVASTUU, JOKA SOPIMUS, TILA VASTUU TAI vahingonkorvausvastuu (mukaan lukienHUOMIOITTAMINEN TAI MUUTOIN), JOKA JOKA TAPAHTUU MITEN TÄMÄN KÄYTÖSTÄOHJELMISTO, VAIKKA ON ILMOITETTU TÄLLAISEEN VAHINGON MAHDOLLISUUDESTA.
"""__tulevaisuuden__ tuontigeneraattoreista__author__ = "Leonard Richardson (leonardr@segfault.org)"__version__ = "3.0.7a"__copyright__ = "Tekijänoikeus (c) 2004-2008 Leonard Richardson"__license__ = "Uuden tyylinen BSD"sgmllib-tuonnista SGMLParser, SGMLParseErrortuoda koodekkejatuo merkintäpohjaatuontityypittuonti retuo sgmllibyrittää:htmlentitydefs-tuonnista nimi2koodipistepaitsi ImportError:nimi2koodipiste = {}yrittää:asetapaitsi NameError:joukosta tuonti Aseta asetukseksi#Nämä hakkerit tekevät Beautiful Soupista jäsentämässä XML-tiedostoa nimiavaruuksillasgmllib.tagfind = re.compile('[a-zA-Z][-_.:a-zA-Z0-9]*')markupbase._declname_match = re.compile(r'[a-zA-Z][-_.:a-zA-Z0-9]*\s*').matchDEFAULT_OUTPUT_ENCODING = "utf-8"# Ensinnäkin luokat, jotka edustavat merkintäelementtejä.luokan sivuelementti:"""Sisältää jonkin sivun osan navigointitiedot(joko tunniste tai tekstinpätkä)"""def setup(self, parent=Ei mitään, edellinen=ei mitään):"""Asettaa alkusuhteet tämän elementin ja välillämuut elementit."""itse.vanhempi = vanhempiitse.edellinen = edellinenself.next = Ei mitäänself.previousSibling = Ei mitäänself.nextSibling = Ei mitäänjos self.parent ja self.parent.contents:self.previousSibling = self.parent.contents[-1]self.previousSibling.nextSibling = itsedef korvaaWith(itse, korvaaWith):oldParent = self.parentmyIndex = self.parent.contents.index(self)if hasattr(replaceWith, 'parent') ja korvaaWith.parent == self.parent:# Korvaamme tämän elementin yhdellä sen sisaruksista.index = self.parent.contents.index(replaceWith)jos indeksi ja indeksi < myIndex:# Lisäksi se tulee ennen tätä elementtiä. Että# tarkoittaa, että kun puramme sen, tämän indeksi# elementti muuttuu.myIndex = myIndex - 1self.extract()oldParent.insert(omahakemisto, korvaaWith)def-ote (itse):"""Repii tämän elementin tuhottomasti puusta."""jos itse.vanhempi:yrittää:self.parent.contents.remove(self)paitsi ValueError:kulkea#Etsi kaksi elementtiä, jotka olisivat vierekkäin, jos#tätä elementtiä (ja kaikkia lapsia) ei ollut jäsennetty. Kytkeä#kaksi.lastChild = self._lastRecursiveChild()nextElement = viimeinenLapsi.seuraavajos itse.edellinen:self.previous.next = nextElementjos seuraavaElementti:nextElement.previous = self.previousself.previous = Ei mitäänlastChild.next = Ei mitäänself.parent = Ei mitäänjos itse.previousSisarus:self.previousSibling.nextSibling = self.nextSiblingjos itse.seuraava sisarus:self.nextSibling.previousSibling = self.previousSiblingself.previousSibling = self.nextSibling = Ei mitäänpalauta itsesidef _lastRecursiveChild(self):"Löytää tämän objektin alta viimeisen elementin jäsennettäväksi."lastChild = itsewhile hasattr(lastCild, 'contents') and lastCild.contents:lastChild = lastChild.contents[-1]palauta viimeinen lapsidef insert (itse, sijainti, uusi lapsi):if (instance(newChild, kantamerkkijono)tai isinstance(newChild, unicode)) \eikä isinstance(newChild, NavigableString):uusiLapsi = NavigableString(uusi lapsi)sijainti = min(sijainti, linssi(itse.sisältö))if hasattr(uusiLapsi, 'parent') and newChild.parent != Ei mitään:# "Lisäämme" elementin, joka on jo sellainen# tämän objektin lapsista.jos uusiLapsi.vanhempi == itse:indeksi = itse.löytää(uusiLapsi)jos indeksi ja indeksi < sijainti:# Lisäksi siirrämme sitä alemmas# luettelo tämän objektin lapsista. Se tarkoittaa sitä# kun poimimme tämän elementin, kohdeindeksimme# hyppää alas yhden.sijainti = sijainti - 1uusiLapsi.ote()uusiLapsi.vanhempi = itsepreviousChild = Ei mitäänjos paikka == 0:newChild.previousSibling = Ei mitäänuusiLapsi.edellinen = itsemuu:edellinenLapsi = itse.sisältö[positio-1]newChild.previousSibling = edellinenLapsinewChild.previousSibling.nextSibling = uusiLapsinewChild.previous = edellinenLapsi._lastRecursiveChild()jos uusiLapsi.edellinen:uusiLapsi.edellinen.seuraava = uusiLapsinewChildsLastElement = uusiLapsi._lastRecursiveChild()jos sijainti >= linssi(itse.sisältö):newChild.nextSibling = Ei mitäänvanhempi = itsevanhempienNextSibling = Ei mitäänmutta eivät vanhemmatSeuraava sisarus:vanhempienNextSibling = vanhempi.seuraava sisarusvanhempi = vanhempi.vanhempijos ei ole vanhempi: # Tämä on asiakirjan viimeinen elementti.taukojos vanhemmatSeuraava sisarus:newChildsLastElement.next = vanhemmatSeuraava sisarusmuu:newChildsLastElement.next = Ei mitäänmuu:nextChild = self.contents[position]uusiLapsi.seuraavaSisarus = seuraavaLapsijos uusiLapsi.seuraava sisarus:newChild.nextSibling.previousSibling = uusiLapsinewChildsLastElement.next = nextChildif newChildsLastElement.next:newChildsLastElement.next.previous = newChildsLastElementself.contents.insert(position, new Child)def append(itse, tag):"""Liittää annetun tunnisteen tämän tunnisteen sisältöön."""self.insert(len(self.contents), tag)def findNext(self, name=Ei mitään, attrs={}, text=Ei mitään, **kwargs):"""Palauttaa ensimmäisen kohteen, joka vastaa annettuja ehtoja janäkyy tämän tunnisteen jälkeen dokumentissa."""return self._findOne(self.findAllNext, nimi, attrs, teksti, **kwargs)def findAllNext(self, name=Ei mitään, attrs={}, text=Ei mitään, limit=Ei mitään,**korut):"""Palauttaa kaikki kohteet, jotka vastaavat annettuja ehtoja ja näkyvättämän tunnisteen jälkeen dokumentissa."""return self._findAll(nimi, attrs, text, limit, self.nextGenerator,**korut)def findNextSibling(self, name=Ei mitään, attrs={}, text=Ei mitään, **kwargs):"""Palauttaa tämän tunnisteen lähimmän sisaruksen, joka vastaaannetut kriteerit ja näkyy asiakirjassa tämän tunnisteen jälkeen."""return self._findOne(self.findNextSisarukset, nimi, attrs, teksti,**korut)def findNextSiblings(self, name=Ei mitään, attrs={}, text=Ei mitään, limit=Ei mitään,**korut):"""Palauttaa tämän tunnisteen sisarukset, jotka vastaavat annettuakriteerit ja näkyvät asiakirjassa tämän tunnisteen jälkeen."""return self._findAll(nimi, attrs, teksti, raja,self.nextSiblingGenerator, **kwargs)fetchNextSiblings = findNextSiblings # Yhteensopivuus pre-3.x:n kanssadef findPrevious(self, name=Ei mitään, attrs={}, text=Ei mitään, **kwargs):"""Palauttaa ensimmäisen kohteen, joka vastaa annettuja ehtoja janäkyy ennen tätä tunnistetta dokumentissa."""return self._findOne(self.findAllPrevious, nimi, attrs, text, **kwargs)def findAllPrevious(self, name=Ei mitään, attrs={}, text=Ei mitään, limit=Ei mitään,**korut):"""Palauttaa kaikki kohteet, jotka vastaavat annettuja ehtoja ja näkyvätennen tätä tunnistetta asiakirjassa."""return self._findAll(nimi, attrs, text, limit, self.previousGenerator,**korut)fetchPrevious = findAllPrevious # Yhteensopivuus vanhempien 3.x kanssadef findPreviousSibling(self, name=Ei mitään, attrs={}, text=Ei mitään, **kwargs):"""Palauttaa tämän tunnisteen lähimmän sisaruksen, joka vastaaannetut kriteerit ja näkyy ennen tätä tunnistetta dokumentissa."""return self._findOne(self.findPreviousSisarukset, nimi, attrs, text,**korut)def findPreviousSiblings(self, name=Ei mitään, attrs={}, text=Ei mitään,limit=Ei mitään, **kwargs):"""Palauttaa tämän tunnisteen sisarukset, jotka vastaavat annettuaehdot ja näkyvät asiakirjassa ennen tätä tunnistetta."""return self._findAll(nimi, attrs, teksti, raja,self.previousSiblingGenerator, **kwargs)fetchPreviousSiblings = findPreviousSiblings # Yhteensopivuus vanhemman 3.x:n kanssadef findParent(itse, nimi=ei mitään, attrs={}, **kwargs):"""Palauttaa tämän tunnisteen lähimmän ylätason, joka vastaa annettuakriteeri."""# HUOMAA: Emme voi käyttää _findOnea, koska findParents on erilainen# joukko argumentteja.r = Ei mitäänl = self.findParents(nimi, attrs, 1)jos minä:r = l[0]paluu rdef findParents(self, name=Ei mitään, attrs={}, limit=Ei mitään, **kwargs):"""Palauttaa tämän tunnisteen vanhemmat, jotka vastaavat annettuakriteeri."""return self._findAll(nimi, attrs, ei mitään, raja, self.parentGenerator,**korut)fetchParents = findParents # Yhteensopivuus vanhempien 3.x kanssa#Nämä menetelmät tekevät todellisen raskaan noston.def _findOne(itse, menetelmä, nimi, attrs, teksti, **kwargs):r = Ei mitäänl = menetelmä (nimi, attrs, teksti, 1, **kwargs)jos minä:r = l[0]paluu rdef _findAll(itse, nimi, attrs, teksti, raja, generaattori, **kwargs):"Iteroi generaattorin yli ja etsii sopivia asioita."jos isinstance(nimi, SoupStrainer):siivilä = nimimuu:# Rakenna Soup Strainersiivilä = SoupStrainer(nimi, attrs, teksti, **kwargs)tulokset = ResultSet(siivilä)g = generaattori()kun taas Totta:yrittää:i = g.seuraava()paitsi StopIteration:taukojos minä:löytyi = siivilä.search(i)jos löytyy:tulokset.append(found)if limit ja len(tulokset) >= raja:taukopalauttaa tulokset#Näillä generaattoreilla voidaan navigoida molemmista alkaen#NavigableStrings and Tags.def nextGenerator(itse):i = itsesillä aikaa kun minä:i = i.seuraavatuotto idef nextSiblingGenerator(itse):i = itsesillä aikaa kun minä:i = i.seuraava sisarustuotto idef previousGenerator(itse):i = itsesillä aikaa kun minä:i = i.edellinentuotto idef previousSiblingGenerator(itse):i = itsesillä aikaa kun minä:i = i.edellinen sisarustuotto idef parentGenerator(itse):i = itsesillä aikaa kun minä:i = i.vanhempituotto i# Hyödyllisyysmenetelmätdef substituteEncoding(self, str, encoding=Ei mitään):koodaus = koodaus tai "utf-8"return str.replace("%SOUP-ENCODING%", koodaus)def toEncoding(self, s, encoding=Ei mitään):"""Koodaa objektin jollakin koodauksella olevaksi merkkijonoksi tai Unicodeksi."""jos isinstance(t, unicode):jos koodaus:s = s.encode(koodaus)elif isinstance(s, str):jos koodaus:s = s.encode(koodaus)muu:s = unicode(t)muu:jos koodaus:s = self.toEncoding(str(s), koodaus)muu:s = unicode(t)paluu sluokka NavigableString(unicode, sivuelementti):def __new__(cls, arvo):"""Luo uusi NavigableString.Kun NavigableString-merkkijonoa poistetaan, tätä menetelmää kutsutaan kanssamerkkijono muodossa DEFAULT_OUTPUT_ENCODING. Tuon koodauksen pitää ollasiirtyi superluokan __uuteen__ tai superluokka ei tiedäkuinka käsitellä ei-ASCII-merkkejä."""if isinstance(arvo, unicode):palauttaa unicode.__new__(cls, arvo)palauttaa unicode.__new__(cls, arvo, DEFAULT_OUTPUT_ENCODING)def __getnewargs__(itse):return (NavigableString.__str__(itse),)def __getattr__(itse, attr):"""text.string antaa sinulle tekstiä. Tämä on taaksepäinyhteensopivuus Navigable*Stringille, mutta CData*:lle se mahdollistaahanki merkkijono ilman CData-käärettä."""if attr == 'merkkijono':palauta itsesimuu:raise AttributeError, objektilla "%s" ei ole attribuuttia "%s" % (self.__class__.__name__, attr)def __unicode__(itse):return str(self).decode(DEFAULT_OUTPUT_ENCODING)def __str__(itse, koodaus=DEFAULT_OUTPUT_ENCODING):jos koodaus:return self.encode(koodaus)muu:palauta itsesiluokan CData(NavigableString):def __str__(itse, koodaus=DEFAULT_OUTPUT_ENCODING):return "<![CDATA[%s]]>" % NavigableString.__str__(itse, koodaus)luokan ProcessingInstruction(NavigableString):def __str__(itse, koodaus=DEFAULT_OUTPUT_ENCODING):lähtö = itsejos "%SOUP-ENCODING%" tulosteessa:lähtö = self.substituteEncoding(tulostus, koodaus)return "%s?>" % self.toEncoding(tulostus, koodaus)luokan kommentti (NavigableString):def __str__(itse, koodaus=DEFAULT_OUTPUT_ENCODING):return "" % NavigableString.__str__(itse, koodaus)luokan ilmoitus (NavigableString):def __str__(itse, koodaus=DEFAULT_OUTPUT_ENCODING):return "<!%s>" % NavigableString.__str__(itse, koodaus)luokan tunniste (sivuelementti):"""Esittää löydettyä HTML-tunnistetta attribuuteineen ja sisällöineen."""def _invert(h):"Halpa toiminto hashin kääntämiseen."i = {}k,v:lle h.items():i[v] = kpalauta iXML_ENTITIES_TO_SPECIAL_CHARS = { "apos" : "'","quot" : '''',"amp" : "&","lt" : "<","gt" : ">" }XML_SPECIAL_CHARS_TO_ENTITIES = _invert(XML_ENTITIES_TO_SPECIAL_CHARS)def _convertEntities(self, match):"""Käytetään kutsussa re.sub korvaamaan HTML, XML ja numeerisetentiteetit sopivilla Unicode-merkeillä. Jos HTMLkokonaisuuksia muunnetaan, tunnistamattomat kokonaisuudet ovatpakeni."""x = match.group(1)if self.convertHTMLEntities ja x nimi2koodipisteessä:palauttaa unichr(nimi2koodipiste[x])elif x itsestään.XML_ENTITIES_TO_SPECIAL_CHARS:if self.convertXMLEntities:palauta itse.XML_ENTITIES_TO_SPECIAL_CHARS[x]muu:palauta u'&%s;' % xelif len(x) > 0 ja x[0] == '#':# Käsittele numeerisia kokonaisuuksiajos len(x) > 1 ja x[1] == 'x':return unichr(int(x[2:], 16))muu:return unichr(int(x[1:]))elif self.escapeUnrecognizedEntities:palauta u'&%s;' % xmuu:palauta u'&%s;' % xdef __init__(self, parser, name, attrs=Ei mitään, parent=Ei mitään,edellinen = ei mitään):"Perusrakentaja."# Emme varsinaisesti tallenna jäsennysobjektia: sen avulla voidaan purkaa# palaset kerätään roskatself.parserClass = jäsentäjä.__class__self.isSelfClosing = jäsentäjä.isSelfClosingTag(nimi)itse.nimi = nimiif attrs == Ei mitään:attrs = []self.attrs = attrsself.contents = []self.setup(vanhempi, edellinen)self.hidden = Falseself.containsSubstitutions = Falseself.convertHTMLEntities = parser.convertHTMLEntitiesself.convertXMLEntities = parser.convertXMLEntitiesself.escapeUnrecognizedEntities = parser.escapeUnrecognizedEntities# Muunna mitkä tahansa HTML-, XML- tai numeeriset entiteetit attribuuttiarvoissa.muuntaa = lambda(k, val): (k,re.sub("&(#\d+|#x[0-9a-fA-F]+|\w+);",self._convertEntities,val))self.attrs = kartta(muunnos, self.attrs)def get(itse, avain, oletus=ei mitään):"""Palauttaa tagin "avain"-attribuutin arvon taioletusarvolle annettu arvo, jos sitä ei oleattribuutti."""return self._getAttrMap().get(avain, oletus)def has_key(self, key):return self._getAttrMap().has_key(avain)def __gettime__(itse, avain):"""tunniste[avain] palauttaa tagin "avain"-attribuutin arvon,ja tekee poikkeuksen, jos sitä ei ole."""return self._getAttrMap()[avain]def __iter__(itse):"Iterointi tunnisteen yli toistaa sen sisällön."palauta iter (self.contents)def __len__(itse):"Tagin pituus on sen sisältöluettelon pituus."palauta linssi (self.contents)def __contains__(itse, x):palauttaa x itse.sisällössädef __nonzero__(itse):"Tagi on ei-ei mitään, vaikka sillä ei olisi sisältöä."palauta Tottadef __setitem__(itse, avain, arvo):"""Asetus tag[avain] asettaa 'avain'-attribuutin arvontag."""self._getAttrMap()self.attrMap[avain] = arvolöydetty = Väärinfor i in range(0, len(self.attrs)):if self.attrs[i][0] == avain:self.attrs[i] = (avain, arvo)löydetty = tottajos ei löydy:self.attrs.append((avain, arvo))self._getAttrMap()[avain] = arvodef __delitem__(itse, avain):"Tagin[avain] poistaminen poistaa kaikki tunnisteen "avain"-attribuutit."nimikkeelle self.attrs:if item[0] == avain:self.attrs.remove(tuote)#Emme riko, koska huono HTML voi määrittää saman#attribuutti useita kertoja.self._getAttrMap()if self.attrMap.has_key(avain):del self.attrMap[avain]def __call__(itse, *args, **kwargs):"""Tagin kutsuminen funktiona on sama kuin sen kutsuminenFindAll() -menetelmä. Esim. tag('a') palauttaa luettelon kaikista A-tunnisteistalöytyi tästä tunnisteesta."""palautushakemus (self.findAll, args, kwargs)def __getattr__(itse, tunniste):#print "Getattr %s.%s" % (self.__class__, tag)if len(tag) > 3 ja tag.rfind('Tag') == len(tunniste)-3:palauta self.find(tunniste[:-3])elif tag.find('__') != 0:palauta self.find(tag)raise AttributeError, objektilla "%s" ei ole attribuuttia "%s" % (self.__class__, tag)def __eq__(itse, muu):"""Palauttaa tosi, jos tällä tunnisteella on sama nimi, samat attribuutit,ja sama sisältö (rekursiivisesti) kuin annettu tunniste.HUOMAA: tällä hetkellä tämä palauttaa false, jos kahdella tunnisteella onsamat attribuutit eri järjestyksessä. Pitäisikö tämä korjata?"""jos ei hasattr(muu, 'nimi') tai ei hasattr(muu, 'attrs') tai ei hasattr(muu, 'sisältö') tai itse.nimi != muu.nimi tai itse.attrs != muu.attrs tai len (itse) != len(muu):palauttaa Falsefor i in range(0, len(self.contents)):if self.contents[i] != other.contents[i]:palauttaa Falsepalauta Tottadef __ne__(itse, muu):"""Palauttaa tosi, jos tämä tunniste ei ole identtinen toisen tagin kanssa,määriteltynä __eq__."""palauta ei itse == muudef __repr__(itse, koodaus=DEFAULT_OUTPUT_ENCODING):"""Tee tämän tunnisteen merkkijonona."""palauttaa itsensä.__str__(koodaus)def __unicode__(itse):palaa itse.__str__(Ei mitään)BARE_AMPERSAND_OR_BRACKET = re.compile("([<>]|"+ "&(?!#\d+;|#x[0-9a-fA-F]+;|\w+;)"+ ")")def _sub_entity(self, x):"""Käytetään säännöllisen lausekkeen kanssa korvaamaansopiva XML-entiteetti XML-erikoismerkille."""palauttaa "&" + self.XML_SPECIAL_CHARS_TO_ENTITIES[x.group(0)[0]] + ";"def __str__(self, koodaus=DEFAULT_OUTPUT_ENCODING,prettyPrint=False, indentLevel=0):"""Palauttaa tämän tagin merkkijonon tai Unicode-esityksen jasen sisältöä. Saadaksesi Unicoden, jätä Ei mitään koodaukselle.HUOMAA: koska Pythonin HTML-jäsentäjä kuluttaa välilyöntejä, tämämenetelmä ei välttämättä toista siinä olevaa tyhjää tilaaalkuperäinen merkkijono."""encodedName = self.toEncoding(self.name, koodaus)attrs = []jos self.attrs:avaimelle val in self.attrs:fmt = '%s="%s"'jos onString(arvo):if self.containsSubstitutions and '%SOUP-ENCODING%' arvossa:val = self.substituteEncoding(arvo, koodaus)# Attribuutin arvo joko:## * Ei sisällä upotettuja kaksoislainausmerkkejä tai yksittäisiä lainausmerkkejä.# Ei hätää: kirjoitamme sen lainausmerkkeihin.# * Sisältää upotetut yksittäiset lainausmerkit. Ei ongelmaa:# lainausmerkit toimivat myös täällä.# * Sisältää upotetut lainausmerkit. Ei ongelmaa:# laitamme sen lainausmerkkeihin.# * Upottaa sekä yksittäiset _ja_ lainausmerkit. Tämä# ei voi tapahtua luonnollisesti, mutta se voi tapahtua, jos# muokkaat määritteen arvoa jäsentämisen jälkeen# asiakirja. Nyt meillä on vähän a#ongelma. Ratkaisemme sen liittämällä#-attribuutti yksittäisissä lainausmerkeissä ja kaikki pakolliset# upotettuja yksittäisiä lainausmerkkejä XML-kokonaisuuksiin.jos '"' arvossa:fmt = "%s='%s'"jos "'" arvossa:# TODO: korvaa apos kun# sopiva.val = val.replace("'", "&squot;")# Nyt olemme kunnossa ilman lainausmerkkejä. Mutta ominaisuus#-arvo voi sisältää myös kulmasulkeja tai# et-merkkiä, jotka eivät ole osa entiteettiä. Me tarvitsemme# paeta ne myös XML-kokonaisuuksiin.val = self.BARE_AMPERSAND_OR_BRACKET.sub(self._sub_entity, val)attrs.append(fmt % (self.toEncoding(avain, koodaus),self.toEncoding(val, encoding)))kiinni = ''closeTag = ''jos self.isSelfClosing:sulje = ' /'muu:closeTag = '%s>' % encodedNameindentTag, indentContents = 0, 0jos kaunisTulosta:indentTag = indentLevelvälilyönti = (' ' * (indentTag-1))indentContents = indentTag + 1contents = self.renderContents(koodaus, prettyPrint, indentContents)jos self.hidden:s = sisältömuu:s = []attribuuttimerkkijono = ''jos attrs:attribuuttiString = ' ' + ' '.join(attrs)jos kaunisTulosta:s.append(välilyönti)s.append('<%s%s%s>' % (encodedName, attribuuttimerkkijono, sulje))jos kaunisTulosta:s.append("\n")s.append(sisältö)if prettyPrint ja sisältö ja sisältö[-1] != "\n":s.append("\n")if prettyPrint and closeTag:s.append(välilyönti)s.append(closeTag)if prettyPrint and closeTag and self.nextSibling:s.append("\n")s = ''.liitty(t)paluu sdef hajoa (itse):"""Tuhoaa rekursiivisesti tämän puun sisällön."""contents = [i for i in self.contents]minulle sisällössä:if isinstance(i, Tag):i.decompose()muu:i.extract()self.extract()def prettify(self, koodaus=DEFAULT_OUTPUT_ENCODING):return self.__str__(koodaus, True)def renderContents(self, koodaus=DEFAULT_OUTPUT_ENCODING,prettyPrint=False, indentLevel=0):"""Tee tämän tunnisteen sisällön merkkijonona annetussa muodossakoodaus. Jos koodaus on Ei mitään, palauttaa Unicode-merkkijonon.."""s=[]c:lle itsenäinen:teksti = Ei mitäänif isinstance(c, NavigableString):teksti = c.__str__(koodaus)elif isinstance(c, Tag):s.append(c.__str__(koodaus, prettyPrint, indentLevel))jos teksti ja kaunisTulosta:teksti = text.strip()jos tekstiä:jos kaunisTulosta:s.append(" " * (indentTaso-1))s.append(teksti)jos kaunisTulosta:s.append("\n")palauta ''.join(s)#keittomenetelmätdef find(self, name=Ei mitään, attrs={}, recursive=True, text=Ei mitään,**korut):"""Palauta vain tämän tunnisteen ensimmäinen alaosa, joka vastaa annettuakriteeri."""r = Ei mitäänl = self.findAll(nimi, attrs, rekursiivinen, teksti, 1, **kwargs)jos minä:r = l[0]paluu rlöytääLapsi = löytäädef findAll(self, name=Ei mitään, attrs={}, recursive=True, text=Ei mitään,limit=Ei mitään, **kwargs):"""Poimii luettelon tunnisteobjekteista, jotka vastaavat annettuakriteeri. Voit määrittää tunnisteen nimen ja minkä tahansaattribuutit, jotka haluat tagilla olevan.Avain-arvo-parin arvo "attrs"-kartassa voi olla amerkkijono, merkkijonoluettelo, säännöllinen lausekeobjekti tai akutsuttava, joka ottaa merkkijonon ja palauttaa riippumatta siitä, onkomerkkijonoosumat joillekin mukautetuille osumamääritteille. Thesama pätee tagin nimeen."""generaattori = self.recursiveChildGeneratorjos ei rekursiivinen:generaattori = self.childGeneratorreturn self._findAll(nimi, attrs, teksti, raja, generaattori, **kwargs)findChildren = löydä kaikki# Pre-3.x-yhteensopivuusmenetelmätensimmäinen = löytäähae = löydä kaikkidef fetchText(self, text=Ei mitään, recursive=True, limit=Ei mitään):return self.findAll(teksti=teksti, rekursiivinen=rekursiivinen, raja=raja)def firstText(itse, teksti=ei mitään, rekursiivinen=tosi):return self.find(teksti=teksti, rekursiivinen=rekursiivinen)#Yksityiset menetelmätdef _getAttrMap(self):"""Alustaa tämän tunnisteen attribuuttien karttaesityksen,jos ei ole jo alustettu."""jos ei getattr(self, 'attrMap'):self.attrMap = {}for (avain, arvo) in self.attrs:self.attrMap[avain] = arvoreturn self.attrMap#Generaattorimenetelmätdef childGenerator(itse):for i in range(0, len(self.contents)):tuottaa itse.contents[i]nosta StopIterationdef recursiveChildGenerator(itse):pino = [(itse, 0)]pinon aikana:tag, start = pino.pop()if isinstance(tunniste, tunniste):i:lle alueella(alku, len(tunniste.sisältö)):a = tag.contents[i]tuotto aif isinstance(a, Tag) ja tag.contents:if i < len(tag.contents) - 1:pino.append((tunniste, i+1))pino.append((a, 0))taukonosta StopIteration# Seuraavaksi pari luokkaa edustamaan kyselyitä ja niiden tuloksia.luokan Soup Strainer:"""Kapseloi useita tapoja kohdistaa merkintäelementti (tunniste taiteksti)."""def __init__(self, name=Ei mitään, attrs={}, text=Ei mitään, **kwargs):itse.nimi = nimiif isString(attrs):kwargs['luokka'] = attrsattrs = Ei mitäänjos kwargs:jos attrs:attrs = attrs.copy()attrs.update(kwargs)muu:attrs = kwargsself.attrs = attrsitse.teksti = tekstidef __str__(itse):jos itse.teksti:palauta itse.tekstimuu:palauttaa "%s|%s" % (self.name, self.attrs)def searchTag(self, markupName=Ei mitään, markupAttrs={}):löytyi = ei yhtäänmarkup = Ei mitäänif isinstance(markupName, Tag):merkintä = markupNamemarkupAttrs = merkintäcallFunctionWithTagData = kutsuttava(itse.nimi) \eikä isinstance(markupName, Tag)jos (ei itse.nimi) \tai callFunctionWithTagData \tai (merkintä ja self._matches(markup, self.name)) \tai (ei merkintää ja self._matches(markupName, self.name)):jos callFunctionWithTagData:match = self.name(markupName, markupAttrs)muu:ottelu = tottamarkupAttrMap = Ei mitäänfor attr, matchAgainst in self.attrs.items():jos ei markupAttrMap:if hasattr(markupAttrs, 'get'):markupAttrMap = markupAttrsmuu:markupAttrMap = {}k,v:lle markupAttrs:markupAttrMap[k] = vattrValue = markupAttrMap.get(attr)jos ei self._matches(attrValue, matchAgainst):ottelu = falsetaukojos vastaa:jos merkintä:löytyi = merkintämuu:löytyi = markupNamepalautus löytynytdef-haku (itse, merkintä):#print 'etsii %s:sta %s' % (itse, merkintä)löytyi = ei yhtään# Jos saat luettelon kohteista, etsi siitä tekstielementti, joka# Ottelut.if isList(markup) eikä isinstance(markup, Tag):merkinnöissä olevalle elementille:if isinstance(element, NavigableString) \ja self.search(element):löytyi = elementtitauko# Jos se on tunniste, varmista, että sen nimi tai määritteet täsmäävät.# Älä välitä tunnisteiden kanssa, jos etsimme tekstiä.elif isinstance (merkintä, tunniste):jos ei itse.text:löytyi = self.searchTag(markup)# Jos se on tekstiä, varmista, että teksti vastaa.elif isinstance(markup, NavigableString) tai \isString(merkintä):jos self._matches(markup, self.text):löytyi = merkintämuu:nosta poikkeus, "en tiedä kuinka pelata %s:a vastaan" \% lisäys.__luokka__palautus löytynytdef _matches(self, markup, matchAgainst):#print "Yhteys %s vastaan %s" % (merkintä, matchAgainst)tulos = falseif matchAgainst == True ja type(matchAgainst) == tyypit. BooleanType:tulos = merkintä ! = Ei mitäänelif callable (matchAgainst):tulos = matchAgainst(markup)muu:#Mukautetut hakumenetelmät pitävät tagia argumenttina, mutta kaikki#muut tavat sovittaa yhteen tunnisteen nimen merkkijonona.if isinstance (merkintä, tunniste):merkintä = merkintä.nimijos merkintä eikä isString(markup):merkintä = unicode(merkintä)#Nyt tiedämme, että pala on joko merkkijono tai ei mitään.if hasattr(matchAgainst, 'match'):# Se on regexp-objekti.tulos = merkintä ja matchAgainst.search(markup)elif isList(matchAgainst):tulos = merkintä matchAgainstissaelif hasattr(matchAgainst, 'kohteet'):tulos = markup.has_key(matchAgainst)elif matchAgainst and isString(merkintä):if isinstance (merkintä, unicode):matchAgainst = unicode(matchAgainst)muu:matchAgainst = str(matchAgainst)jos ei tulos:tulos = matchAgainst == merkintäpalauttaa tuloksenluokan tulosjoukko(lista):"""ResultSet on vain luettelo, joka pitää kirjaa SoupStraineristajoka loi sen."""def __init__(itse, lähde):lista.__init__([])self.source = lähde# Nyt joitain aputoimintoja.def isList(l):"""Mukava menetelmä, joka toimii kaikkien Pythonin 2.x-versioiden kanssamäärittääksesi onko jokin luettelomainen vai ei."""return hasattr(l, '__iter__') \tai (type(l) in (types.ListType, types.TupleType))def isString(s):"""Mukava menetelmä, joka toimii kaikkien Pythonin 2.x-versioiden kanssamäärittääkseen onko jokin merkkijonomainen vai ei."""yrittää:palauttaa isinstance(t, unicode) tai isinstance(t, kantamerkkijono)paitsi NameError:palautusinstanssi(t, str)def buildTagMap(oletus, *args):"""Muuntaa luettelon kartoista, luetteloista tai skalaareista yhdeksi kartaksi.Käytetään SELF_CLOSING_TAGS-, NESTABLE_TAGS- jaNESTING_RESET_TAGS karttaa luetteloista ja osittaisista kartoista."""rakennettu = {}annokselle argissa:if hasattr(osio, 'kohteet'):#Se on kartta. Yhdistä se.k,v:lle portion.items():rakennettu[k] = velif isList(osa):#Se on lista. Yhdistä jokainen kohde oletusarvoon.k osissa:rakennettu[k] = oletusmuu:#Se on skalaari. Yhdistä se oletusarvoon.rakennettu[osa] = oletuspaluu rakennettu# Nyt jäsennysluokat.luokan BeautifulStoneSoup (tunniste, SGMLParser):"""Tämä luokka sisältää perusjäsentimen ja hakukoodin. Se määrittääjäsentäjä, joka ei tiedä mitään tunnisteen käyttäytymisestä paitsiseurata:Et voi sulkea tunnistetta sulkematta kaikkia sen sisältämiä tunnisteita.Eli "" tarkoittaa itse asiassa" ".[Toinen mahdollinen selitys on " ", mutta koskatämä luokka ei määrittele SELF_CLOSING_TAGS:ia, se ei koskaan käytä niitäselitys.]Tämä luokka on hyödyllinen XML- tai keksittyjen merkintäkielten jäsentämiseen,tai kun BeautifulSoup tekee oletuksen, joka on ristiriidassa sen kanssa, mitä olitodottaa."""SELF_CLOSING_TAGS = {}NESTABLE_TAGS = {}RESET_NESTING_TAGS = {}QUOTE_TAGS = {}PRESERVE_WHITESPACE_TAGS = []MARKUP_MASSAGE = [(re.compile('(<[^<>]*)/>'),lambda x: x.group(1) + ' />'),(re.compile('<!\s+([^<>]*)>'),lambda x: '<!' + x.ryhmä(1) + '>')]ROOT_TAG_NAME = u'[asiakirja]'HTML_ENTITIES = "html"XML_ENTITIES = "xml"XHTML_ENTITIES = "xhtml"# TODO: Tämä on olemassa vain taaksepäin yhteensopivuuden kannaltaALL_ENTITIES = XHTML_ENTITIES# Käytetään määritettäessä, onko tekstisolmu vain välilyönti ja# voidaan korvata yhdellä välilyönnillä. Tekstisolmu, joka sisältää# hienoja Unicode-välilyöntejä (yleensä rikkoutumattomia) tulee jättää#yksin.STRIP_ASCII_SPACES = { 9: ei mitään, 10: ei mitään, 12: ei mitään, 13: ei mitään, 32: ei mitään, }def __init__(self, markup="", parseOnlyThese=Ei mitään, fromEncoding=Ei mitään,markupMassage=Tosi, smartQuotesTo=XML_ENTITIES,convertEntities=Ei mitään, selfClosingTags=Ei mitään, isHTML=False):"""Soup-objekti alustetaan 'juuritunnisteeksi' jaannettu merkintä (joka voi olla merkkijono tai tiedostomainen objekti)syötetään alla olevaan jäsentimeen.sgmllib käsittelee useimmat huonot HTML-koodit ja BeautifulSoupinluokassa on joitain temppuja tappavan HTML:n käsittelemiseensgmllib, mutta Beautiful Soup voi silti tukehtua tai menettää tietojajos tiedoissasi käytetään itsestään sulkeutuvia tunnisteita tai ilmoituksiaväärin.Oletuksena Beautiful Soup käyttää regexejä syötteen puhdistamiseen,välttää suurin osa näistä ongelmista. Jos ongelmiaeivät koske sinua, jätä arvoksi False markupMassage jasaat paremman suorituskyvyn.Oletusparser-hierontatekniikat korjaavat kaksi yleisintävirheellisen HTML-koodin esiintymät, jotka tukahduttavat sgmllib:n:
(Ei välilyöntiä sulkevan tagin nimen ja tagin sulkemisen välillä)<! --kommentti--> (ylimääräinen välilyönti ilmoituksessa)Voit välittää mukautetun luettelon (RE-objekti, korvausmenetelmä)tuples saada Beautiful Soup puhdistaa syötteesi haluamallasi tavallahaluta."""self.parseOnlyThese = parseOnlyTheseself.fromEncoding = fromEncodingself.smartQuotesTo = smartQuotesToself.convertEntities = convertEntities# Aseta säännöt sille, kuinka käsittelemme tahoja, joita me käsittelemme# kohdatajos self.convertEntities:# Ei ole järkevää muuntaa koodattuja merkkejä# entiteettiä, vaikka muunnat entiteettejä Unicode-muotoon.# Muunna se vain Unicodeksi.self.smartQuotesTo = Ei mitäänif convertEntities == self.HTML_ENTITIES:self.convertXMLEntities = Väärinself.convertHTMLEntities = Tottaself.escapeUnrecognizedEntities = Tottaelif convertEntities == self.XHTML_ENTITIES:self.convertXMLEntities = Tosiself.convertHTMLEntities = Tottaself.escapeUnrecognizedEntities = Väärinelif convertEntities == self.XML_ENTITIES:self.convertXMLEntities = Tosiself.convertHTMLEntities = Väärinself.escapeUnrecognizedEntities = Väärinmuu:self.convertXMLEntities = Väärinself.convertHTMLEntities = Väärinself.escapeUnrecognizedEntities = Väärinself.instanceSelfClosingTags = buildTagMap(Ei mitään, selfClosingTags)SGMLParser.__init__(itse)if hasattr(markup, 'read'): # Se on tiedostotyyppinen objekti.markup = markup.read()self.markup = merkintäself.markupMassage = markupMassageyrittää:self._feed(isHTML=isHTML)paitsi StopParsing:kulkeaself.markup = Ei mitään # Merkintä voidaan nyt GCeddef convert_charref(itse, nimi):"""Tämä menetelmä korjaa virheen Pythonin SGMLParserissa."""yrittää:n = int(nimi)paitsi ValueError:palatajos ei 0 <= n <= 127 : # ASCII päättyy numeroon 127, ei 255palatareturn self.convert_codepoint(n)def _feed(self, inDocumentEncoding=Ei mitään, isHTML=False):# Muunna asiakirja Unicode-muotoon.merkintä = self.markupif isinstance (merkintä, unicode):jos ei hasattr(self, 'originalEncoding'):self.originalEncoding = Ei mitäänmuu:dammit = UnicodeDammit\(markup, [self.fromEncoding, inDocumentEncoding],smartQuotesTo=self.smartQuotesTo, isHTML=isHTML)markup = dammit.unicodeself.originalEncoding = dammit.originalEncodingself.declaredHTMLEncoding = dammit.declaredHTMLEncodingjos merkintä:jos self.markupMassage:jos ei, onList(self.markupMassage):self.markupMassage = self.MARKUP_MASSAGEfix, m in self.markupMassage:merkintä = fix.sub(m, merkintä)# TODO: Pääsemme eroon markupMassage niin, että# keittokohde voidaan syväkopioida myöhemmin. Jonkin verran# Python-asennukset eivät voi kopioida regexejä. Jos joku# luotti olemassaoloon markupMassage, tämä# saattaa aiheuttaa ongelmia.del(self.markupMassage)self.reset()SGMLParser.feed (itse, merkintä)# Sulje kaikki keskeneräiset merkkijonot ja sulje kaikki avoimet tagit.self.endData()while self.currentTag.name != self.ROOT_TAG_NAME:self.popTag()def __getattr__(self, methodName):"""Tämä menetelmä reitittää menetelmäkutsupyynnöt joko SGMLParserillesuperclass tai Tag superclass menetelmän nimestä riippuen."""#print "__getattr__ kutsutaan %s.%s" % (self.__class__, methodName)if methodName.find('aloitus_') == 0 tai metodinnimi.find('end_') == 0 \tai methodName.find('do_') == 0:return SGMLParser.__getattr__(self, methodName)elif methodName.find('__') != 0:return Tag.__getattr__(self, methodName)muu:nosta AttributeErrordef isSelfClosingTag(itse, nimi):"""Palauttaa tosi, jos annettu merkkijono on a:n nimiitsestään sulkeutuva tagi tämän jäsentimen mukaan."""return self.SELF_CLOSING_TAGS.has_key(name) \tai self.instanceSelfClosingTags.has_key(name)def reset (itse):Tag.__init__(self, self, self.ROOT_TAG_NAME)itse.piilotettu = 1SGMLParser.reset(itse)self.currentData = []self.currentTag = Ei mitäänself.tagStack = []self.quoteStack = []self.pushTag(self);def popTag(itse):tag = self.tagStack.pop()# Tunnisteet, joissa on vain yksi merkkijono omistava lapsi, saavat lapsen a# 'merkkijono'-ominaisuus, joten soup.tag.string on lyhenne sanalle# soup.tag.contents[0]if len(self.currentTag.contents) == 1 ja \isinstance(self.currentTag.contents[0], NavigableString):self.currentTag.string = self.currentTag.contents[0]#print "Pop", tag.namejos self.tagStack:self.currentTag = self.tagStack[-1]return self.currentTagdef pushTag(itse, tag):#print "Push", tag.namejos self.currentTag:self.currentTag.contents.append(tunniste)self.tagStack.append(tunniste)self.currentTag = self.tagStack[-1]def endData(self, containerClass=NavigableString):jos self.currentData:nykyiset tiedot = u''.join(itse.nykyiset tiedot)if (currentData.translate(self.STRIP_ASCII_SPACES) == '' janot set([tag.nimi tagille self.tagStackissa]).intersection(itse.PRESERVE_WHITESPACE_TAGS)):jos '\n' nykyisissä tiedoissa:currentData = '\n'muu:currentData = ' 'self.currentData = []if self.parseOnlyThese ja len(self.tagStack) <= 1 ja \(ei self.parseOnlyThese.text tai \not self.parseOnlyThese.search(currentData)):palatao = konttiluokka (nykyiset tiedot)o.setup(self.currentTag, self.previous)jos itse.edellinen:itse.edellinen.seuraava = oitse.edellinen = oself.currentTag.contents.append(o)def _popToTag(itse, nimi, inclusivePop=True):"""Nostaa tunnistepinon viimeisimpään mukaan lukienannetun tagin esiintymä. Jos inclusivePop on epätosi, ponnahtaa tunnistepinoa, mutta *ei*, mukaan lukien viimeisin esiintymäannettu tunniste."""#print "Popping kohteeseen %s" % namejos nimi == itse.ROOT_TAG_NAME:palatanumPops = 0mostRecentTag = Ei mitäänfor i in range(len(self.tagStack)-1, 0, -1):jos nimi == itse.tagPino[i].nimi:numPops = len(self.tagStack)-itaukojos ei sisälläPop:numPops = numPops - 1i in range (0, numPops):mostRecentTag = self.popTag()palauttaa viimeisimmän tunnisteendef _smartPop(itse, nimi):"""Meidän on avattava tämän tyyppinen aikaisempi tunniste, elleiyksi tämän tagin sisäkkäisasetusten palautustriggereistä tulee tämän väliin-tunniste ja edellinen tämän tyyppinen tagi, TAI ellei tämä tunniste ole ayleinen sisäkkäiskäynnistin ja toinen yleinen sisäkkäisliipaisintulee tämän ja edellisen tämän tyyppisen tagin väliin.Esimerkkejä:Foopalkin *
* tulee ponnahtaa kohtaan "p", ei "b".
Foo
* | * tulee ponnahtaa kohtaan tr, ei ensimmäiseen td:hen"""nestingResetTriggers = self.NESTABLE_TAGS.get(nimi)isNestable = nestingResetTriggers != Ei mitäänisResetNesting = self.RESET_NESTING_TAGS.has_key(name)popTo = Ei mitäänmukaan lukien = Tottafor i in range(len(self.tagStack)-1, 0, -1):p = self.tagStack[i]if (ei p tai p.nimi == nimi) ja not isNestable:#Non-stable tags ponnahtaa yläreunaan tai niiden päälle#viimeinen esiintyminen.popTo = nimitaukoif (nestingResetTriggers != Ei mitäänja p.name nestingResetTriggersissä) \tai (nestingResetTriggers == Ei mitään ja isResetNestingja self.RESET_NESTING_TAGS.has_key(p.name)):#Jos kohtaamme yhden sisäkkäisten nollauslaukaisujen#ominaisuutena tälle tunnisteelle, tai kohtaamme toisen tunnisteen#joka aiheuttaa sisäkkäisyyden nollaamisen, ponnahtaa esiin, mutta ei#mukaan lukien tuo tagi.popTo = p.nimimukaan lukien = Väärintaukop = p.vanhempijos popTo:self._popToTag(popTo, mukaan lukien)def unknown_starttag(self, nimi, attrs, selfClosing=0):#print "Aloita tagi %s: %s" % (nimi, attrs)jos itse.quoteStack:#Tämä ei ole oikea tunniste.#print "<%s> ei ole totta!" % nimiattrs = ''. join(kartta(lambda(x, y): ' %s="%s"' % (x, y), attrs))self.handle_data('<%s%s>' % (nimi, attrs))palataself.endData()jos ei itse.isSelfClosingTag(name) and not selfClosing:self._smartPop(nimi)if self.parseOnlyThese ja len(self.tagStack) <= 1 \ja (self.parseOnlyThese.text or not self.parseOnlyThese.searchTag(nimi, attrs)):palatatag = Tunniste(itse, nimi, attrs, self.currentTag, self.previous)jos itse.edellinen:self.previous.next = tunnisteself.previous = tagself.pushTag(tunniste)jos selfClosing tai self.isSelfClosingTag(name):self.popTag()jos nimi itsessään.QUOTE_TAGS:#print "Alkulainaus (%s)" % nimiself.quoteStack.append(nimi)itse.kirjaimellinen = 1palautusmerkkidef unknown_endtag(itse, nimi):#print "Lopputunniste %s" % nimiif self.quoteStack ja self.quoteStack[-1] != nimi:#Tämä ei ole todellinen lopputunniste.#print "%s> ei ole totta!" % nimiself.handle_data('%s>' % name)palataself.endData()self._popToTag(nimi)if self.quoteStack ja self.quoteStack[-1] == nimi:self.quoteStack.pop()self.literal = (len(self.quoteStack) > 0)def handle_data(self, data):self.currentData.append(data)def _toStringSubclass(itse, teksti, alaluokka):"""Lisää puuhun tietyn tekstin Navigable String -merkkijononaalaluokka."""self.endData()self.handle_data(text)self.endData(alaluokka)def handle_pi(itse, teksti):"""Käsittelyohjeita käsittelyohjeenaobjekti, mahdollisesti sellainen, jossa on %SOUP-ENCODING% -paikka, johon ankoodaus liitetään myöhemmin."""if text[:3] == "xml":text = u"xml version='1.0' encoding='%SOUP-ENCODING%'"self._toStringSubclass(teksti, käsittelyohje)def handle_comment(itse, teksti):"Käsittele kommentteja kommenttiobjekteina."self._toStringSubclass(teksti, kommentti)def handle_charref(self, ref):"Käsittele merkkiviittauksia datana."jos self.convertEntities:data = unichr(int(ref))muu:data = '%s;' % refself.handle_data(data)def handle_entityref(self, ref):"""Käsittele entiteettiviittauksia datana, mahdollisesti muuttamalla tunnettujaHTML- ja/tai XML-entiteetti viittaa vastaavaan Unicode-koodiinhahmoja."""data = Ei mitäänif self.convertHTMLEntities:yrittää:data = unichr(nimi2koodipiste[viite])paitsi KeyError:kulkeajos ei dataa ja self.convertXMLEntities:data = self.XML_ENTITIES_TO_SPECIAL_CHARS.get(ref)jos ei data ja self.convertHTMLEntities and \ei itse.XML_ENTITIES_TO_SPECIAL_CHARS.get(ref):# TODO: Meillä on ongelma tässä. Meille kerrotaan näin# entiteettiviittaus, mutta se ei ole XML-entiteetti# viittaus tai HTML-entiteettiviittaus. Kuitenkin,# Looginen asia on välittää se läpi# tuntematon kokonaisuusviittaus.## Paitsi: kun syöte on "&carol;" tämä toiminto# kutsutaan syötteellä "carol". Kun syöttö on# "AT&T", tätä toimintoa kutsutaan syötteellä# "T". Emme voi tietää, onko puolipiste# oli alun perin läsnä, joten emme tiedä onko# tämä on tuntematon kokonaisuus tai vain väärässä paikassa# et-merkki.## Yleisin tapaus on väärin sijoitettu et-merkki, joten minä# ohita et-merkki ja jätä pois puolipiste.data = "&%s" % refjos ei dataa:# Tämä tapaus eroaa yllä olevasta, koska me# ei ole jo käynyt läpi oletettavasti kattavaa# entiteettien yhdistäminen Unicode-merkkeihin. Emme ehkä# ovat käyneet läpi mitään kartoituksia. Joten mahdollisuudet ovat# erittäin korkea, että tämä on todellinen kokonaisuus, eikä a# väärin sijoitettu et-merkki.data = "&%s;" % refself.handle_data(data)def handle_decl(self, data):"Käsittele DOCTYPEjä ja vastaavia ilmoitusobjekteina."self._toStringSubclass(data, ilmoitus)def parse_declaration(self, i):"""Käsittele väärää SGML-ilmoitusta raakatietona. Käsittele CDATA:tailmoitus CData-objektiksi."""j = Ei mitäänif self.rawdata[i:i+9] == '<![CDATA[':k = self.rawdata.find(']]>', i)jos k == -1:k = len(self.rawdata)data = self.rawdata[i+9:k]j = k+3self._toStringSubclass(data, CData)muu:yrittää:j = SGMLParser.parse_declaration(self, i)paitsi SGMLParseError:toHandle = self.rawdata[i:]self.handle_data(toHandle)j = i + len(toHandle)paluu jluokan BeautifulSoup (BeautifulStoneSoup):"""Tämä jäsentäjä tietää seuraavat tiedot HTML:stä:* Joillakin tunnisteilla ei ole lopputunnistetta, ja ne tulisi tulkita sellaisiksisuljetaan heti kun ne kohtaavat.* Joidenkin tunnisteiden sisällä oleva teksti (esim. 'script') voi sisältää tunnisteita, jotkaeivät varsinaisesti ole osa asiakirjaa ja jotka pitäisi jäsentäätekstinä, ei tunnisteina. Jos haluat jäsentää tekstin tunnisteiksi, voit tehdä senaina hakea ja jäsentää se erikseen.* Tunnisteiden sisäkkäissäännöt:Useimpia tageja ei voi laittaa sisäkkäin ollenkaan. Esimerkiksi esiintyminen -tunnisteen tulee implisiittisesti sulkea edellinen -tunniste. Para1 Para2pitäisi muuttaa muotoon: Para1 Para2Jotkut tunnisteet voidaan upottaa mielivaltaisesti. Esimerkiksi tapahtuma -tunnisteen _ei_ saa sulkea implisiittisesti edellistä-tunniste.Alice sanoi:Bob sanoi:BlahEI pidä muuttaa muotoon:Alice sanoi:Bob sanoi:BlahJotkut tunnisteet voidaan sisäkkäin, mutta sisäkkäisyyden nollaamuiden tunnisteiden väliin. Esimerkiksi |