diff options
Diffstat (limited to 'doc/source')
-rw-r--r-- | doc/source/README | 23 | ||||
-rw-r--r-- | doc/source/index.ptbr.rst | 3261 | ||||
-rw-r--r-- | doc/source/index.rst | 21 |
3 files changed, 44 insertions, 3261 deletions
diff --git a/doc/source/README b/doc/source/README new file mode 100644 index 0000000..6fbab84 --- /dev/null +++ b/doc/source/README @@ -0,0 +1,23 @@ +Translation credits +################### + +I keep a copy of all translations in this repository so that it's easy +to host translations on the Beautiful Soup website. These are +generally not the canonical versions of the translations, though. + +doc.html/index.jp.html is a copy of the 2013 Japanese translation hosted at +http://kondou.com/BS4/. I don't know who to credit for the +translation. + +doc.html/index.kr.html is a copy of the 2012 Korean translation formerly hosted +at http://coreapython.hosting.paran.com/etc/beautifulsoup4.html. I +retrieved this copy from the Wayback Machine. I'm not sure who wrote +the translation but I believe the credit goes to "Johnsonj". + +doc.ptbr/source/index.rst is a 2019 Brazilian Portuguese translation by Cezar +Peixeiro. The version in this repository has been modified from +https://github.com/czrpxr/BeautifulSoup4-ptbr-translation. + +doc.zh/source/index.rst is a 2018 Chinese translation by Deron +Wang. The version in this repository has been copied from +https://github.com/DeronW/beautifulsoup. diff --git a/doc/source/index.ptbr.rst b/doc/source/index.ptbr.rst deleted file mode 100644 index f596d44..0000000 --- a/doc/source/index.ptbr.rst +++ /dev/null @@ -1,3261 +0,0 @@ -Documentação Beautiful Soup -============================ - -.. image:: 6.1.jpg - :align: right - :alt: "O Lacaio-Peixe começou tirando debaixo do braço uma grande carta, quase tão grande quanto ele mesmo." - - -`Beautiful Soup <http://www.crummy.com/software/BeautifulSoup/>`_ é uma biblioteca -Python de extração de dados de arquivos HTML e XML. Ela funciona com o seu interpretador (parser) favorito -a fim de prover maneiras mais intuitivas de navegar, buscar e modificar uma árvore de análise (parse tree). -Ela geralmente economiza horas ou dias de trabalho de programadores ao redor do mundo. - -Estas instruções ilustram as principais funcionalidades do Beautiful Soup 4 -com exemplos. Mostro para o que a biblioteca é indicada, como funciona, -como se usa e como fazer aquilo que você quer e o que fazer quando ela frustra suas -expectativas. - -Os exemplos nesta documentação devem funcionar da mesma maneira em Python 2.7 e Python 3.2. - -`Você pode estar procurando pela documentação do Beautiful Soup 3 -<http://www.crummy.com/software/BeautifulSoup/bs3/documentation.html>`_. -Se está, informo que o Beautiful Soup 3 não está mais sendo desenvolvido, -e que o Beautiful Soup 4 é o recomendado para todos os novos projetos. -Se você quiser saber as diferenças entre as versões 3 e 4, veja `Portabilidade de código para BS4`_. - -Esta documentação foi traduzida para outros idiomas pelos usuários do Beautiful Soup: - -* `这篇文档当然还有中文版. <https://www.crummy.com/software/BeautifulSoup/bs4/doc/index.zh.html>`_ -* このページは日本語で利用できます(`外部リンク <http://kondou.com/BS4/>`_) -* 이 문서는 한국어 번역도 가능합니다. (`외부 링크 <https://web.archive.org/web/20150319200824/http://coreapython.hosting.paran.com/etc/beautifulsoup4.html>`_) -* Este documento também está disponível em Português do Brasil - -Como conseguir ajuda: ---------------------- - -Se você tem perguntas sobre o Beautiful Soup ou está com dificuldades, -`envie uma mensagem para nosso grupo de discussão -<https://groups.google.com/forum/?fromgroups#!forum/beautifulsoup>`_. Se o seu -problema envolve a interpretação de um documento HTML, não esqueça de mencionar -:ref:`o que a função diagnose() diz <diagnose>` sobre seu documento. - -Início Rápido -============= - -Este é o HTML que usarei como exemplo ao longo deste documento -É um trecho de "Alice no País das Maravilhas":: - - html_doc = """ - <html><head><title>The Dormouse's story</title></head> - <body> - <p class="title"><b>The Dormouse's story</b></p> - - <p class="story">Once upon a time there were three little sisters; and their names were - <a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>, - <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and - <a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>; - and they lived at the bottom of a well.</p> - - <p class="story">...</p> - """ - -Executando o arquivo "three sisters" através do Beautiful Soup, ele nos -retorna um objeto ``BeautifulSoup``, que apresenta o documento como uma estrutura -de dados aninhada:: - - from bs4 import BeautifulSoup - soup = BeautifulSoup(html_doc, 'html.parser') - - print(soup.prettify()) - # <html> - # <head> - # <title> - # The Dormouse's story - # </title> - # </head> - # <body> - # <p class="title"> - # <b> - # The Dormouse's story - # </b> - # </p> - # <p class="story"> - # Once upon a time there were three little sisters; and their names were - # <a class="sister" href="http://example.com/elsie" id="link1"> - # Elsie - # </a> - # , - # <a class="sister" href="http://example.com/lacie" id="link2"> - # Lacie - # </a> - # and - # <a class="sister" href="http://example.com/tillie" id="link2"> - # Tillie - # </a> - # ; and they lived at the bottom of a well. - # </p> - # <p class="story"> - # ... - # </p> - # </body> - # </html> - -Abaixo verificamos algumas maneiras simples de navegar na estrutura:: - - soup.title - # <title>The Dormouse's story</title> - - soup.title.name - # u'title' - - soup.title.string - # u'The Dormouse's story' - - soup.title.parent.name - # u'head' - - soup.p - # <p class="title"><b>The Dormouse's story</b></p> - - soup.p['class'] - # u'title' - - soup.a - # <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a> - - soup.find_all('a') - # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>, - # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>, - # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>] - - soup.find(id="link3") - # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a> - -Uma tarefa comum é extratir todas as URLs encontradas nas tags <a> de uma página:: - - for link in soup.find_all('a'): - print(link.get('href')) - # http://example.com/elsie - # http://example.com/lacie - # http://example.com/tillie - -Outra tarefa comum é extrair todo o texto de uma página:: - - print(soup.get_text()) - # The Dormouse's story - # - # The Dormouse's story - # - # Once upon a time there were three little sisters; and their names were - # Elsie, - # Lacie and - # Tillie; - # and they lived at the bottom of a well. - # - # ... - -Isso se parece com o que você precisa? Então vá em frente! - -Instalando o Beautiful Soup -=========================== - -Se você está usando uma versão recente das distribuições Linux Debian ou Ubuntu, -você pode instalar o Beautiful Soup facilmente utilizando o gerenciador de pacotes - -:kbd:`$ apt-get install python-bs4` (for Python 2) - -:kbd:`$ apt-get install python3-bs4` (for Python 3) - -O Beautiful Soup 4 também está publicado no PyPi. Portanto, se -você não conseguir instalá-lo através de seu gerenciador de pacotes, você -pode fazer isso com ``easy_install`` ou ``pip``. O nome do pacote é ``beautifulsoup4``, -e o mesmo pacote é válido tanto para Python 2 quanto Python 3. Tenha certeza de utilizar -a versão correta de ``pip`` ou ``easy_install`` para sua versão do Python (estarão -nomeados como ``pip3`` ou ``easy_install3`` ,respectivamente, se você estiver usando Python 3). - - -:kbd:`$ easy_install beautifulsoup4` - -:kbd:`$ pip install beautifulsoup4` - -(O pacote ``BeautifulSoup`` provavelmente `não` é o que você quer. Esta -é a versão anterior, `Beautiful Soup 3`_. Muitos softwares utilizam -BS3, por isso ele ainda está disponível, mas se você está criando algo novo, -você deve instalar o ``beautifulsoup4``.) - -Se você não possui o ``easy_install`` ou ``pip`` instalados, você pode fazer -o download através do tarball do arquivo fonte do Beautiful Soup 4 -<http://www.crummy.com/software/BeautifulSoup/download/4.x/>`_ e -instalar através do ``setup.py``. - -:kbd:`$ python setup.py install` - -Se tudo isso falhar, a licença do Beautiful Soup lhe permite empacotar -toda a biblioteca em sua aplicação. Você pode fazer o download do arquivo -tarball, copiar o diretório ``bs4`` do código-fonte para sua aplicação e -utilizar o Beautiful Soup sem nenhum processo de instalação. - -Eu utilizo Python 2.7 e Python 3.2 para desenvolver o Beautiful Soup, -mas ele também funcionará com outras versões recentes. - -Problemas após a instalação ---------------------------- - -O Beautiful Soup é empacotado em Python 2. Quando você o instala utilizando -Python 3 ele é automaticamente convertido para esta versão. Se você não instalar o pacote, o -código não será convertido. Também foi relatado versões erradas sendo instaladas em -máquinas Windows. - -Se você receber um ``ImportError`` "No module named HTMLParser", seu problema -é que você está utilizando o formato de código Python 2 sob Python 3. - -Se você receber um ``ImportError`` "No module named html.parser", seu problema -é que você está utilizando o formato de código Python 3 sob Python 2. - -Em ambos os casos, sua melhor opção é remover completamente a -instalação do Beautiful Soup do seu sistema (incluindo qualquer diretório -criado quando o tarball foi descompactado) e realizar a instalação novamente. - -Se você receber um ``SyntaxError`` "Invalid syntax" na linha -``ROOT_TAG_NAME = u'[document]'``, você terá que converter o Python 2 -em Python 3. Você pode fazer isso instalando o pacote: - -:kbd:`$ python3 setup.py install` - -ou manualmente executando o script de conversão ``2to3`` no -diretório ``bs4``: - -:kbd:`$ 2to3-3.2 -w bs4` - -.. _parser-installation: - - -Instalando um interpretador (parser) ------------------------------------- - - -O Beautiful Soup não só suporta o parser HTML incluído na biblioteca -padrão do Python como também inúmeros parsers de terceiros. -Um deles é o `parser lxml <http://lxml.de/>`_. Dependendo de sua configuração, -você podera instalar o lxml com algum dos seguintes comandos: - -:kbd:`$ apt-get install python-lxml` - -:kbd:`$ easy_install lxml` - -:kbd:`$ pip install lxml` - -Outra alternativa é o parser `html5lib -<http://code.google.com/p/html5lib/>`_ do Python puro, o qual analisa o HTML -da mesma maneira que o navegador o faz. Dependendo de sua configuração, -você podera instalar o html5lib com algum dos seguintes comandos: - -:kbd:`$ apt-get install python-html5lib` - -:kbd:`$ easy_install html5lib` - -:kbd:`$ pip install html5lib` - -Esta tabela resume as vantagens e desvantagens de cada parser:- - -+----------------------+--------------------------------------------+--------------------------------+--------------------------+ -| Parser | Uso Padrão | Vantagens | Desvantagens | -+----------------------+--------------------------------------------+--------------------------------+--------------------------+ -| html.parser (puro) | ``BeautifulSoup(markup, "html.parser")`` | * Baterias inclusas | * Não tão rápido quanto | -| | | * Velocidade Decente | lxml, menos leniente | -| | | * Leniente (Python 2.7.3 | que html5lib. | -| | | e 3.2.) | | -+----------------------+--------------------------------------------+--------------------------------+--------------------------+ -| HTML (lxml) | ``BeautifulSoup(markup, "lxml")`` | * Muito rápido | * Dependencia externa de | -| | | * Leniente | C | -+----------------------+--------------------------------------------+--------------------------------+--------------------------+ -| XML (lxml) | ``BeautifulSoup(markup, "lxml-xml")`` | * Muito rápido | * Dependência externa de | -| | ``BeautifulSoup(markup, "xml")`` | * O único parser XML atualmente| C | -| | | suportado | | -+----------------------+--------------------------------------------+--------------------------------+--------------------------+ -| html5lib | ``BeautifulSoup(markup, "html5lib")`` | * Extremamente leniente | * Muito lento | -| | | * Analisa as páginas da mesma | * Dependência externa de | -| | | maneira que o navegador o faz| Python | -| | | * Cria HTML5 válidos | | -+----------------------+--------------------------------------------+--------------------------------+--------------------------+ - -Se for possível recomendo que você instale e utilize o lxml pelo desempenho. -Se você está utilizando o Python 2 anterior a 2.7.3 ou uma versão do Python 3 -anterior a 3.2.2, é `essencial` que você instale o lxml ou o html5lib. O parser -HTML nativo do Python não é muito bom para versões mais antigas. - -Note que se um documento é inválido, diferentes parsers irão gerar -diferentes árvores BeautifulSoup para isso. Veja :ref:`Diferenças entre os interpretadores (parsers)` -para detalhes. - - -Criando a "Sopa" -================ - -Para analisar um documento, passe-o como argumento dentro de um construtor ``BeautifulSoup``. -Você pode passar este argumento como uma string ou manipulador da função open():: - - from bs4 import BeautifulSoup - - with open("index.html") as fp: - soup = BeautifulSoup(fp) - - soup = BeautifulSoup("<html>data</html>") - -Primeiro, o documento é convertido para Unicode e as entidades HTML -são convertidas para caracteres Unicode:: - - BeautifulSoup("Sacré bleu!") - <html><head></head><body>Sacré bleu!</body></html> - -O Beautiful Soup então interpreta o documento usando o melhor parser disponível. -Ele irá utilizar um parser HTML ao menos que você indique a ele que utilize um -parser XML.(Veja `Interpretando XML`_.) - -Tipos de objetos -================ - -O Beautiful Soup transforma um documento HTML complexo em uma complexa árvore de objetos Python. -Mas você terá apenas que lidar com quatro `tipos` de objetos: ``Tag``, ``NavigableString``, ``BeautifulSoup``, -e ``Comment``. - -.. _Tag: - -``Tag`` -------- - -Um objeto ``Tag`` corresponde a uma tag XML ou HTML do documento original:: - - soup = BeautifulSoup('<b class="boldest">Extremely bold</b>') - tag = soup.b - type(tag) - # <class 'bs4.element.Tag'> - -As tags possuem muitos atributos e métodos que eu falarei mais sobre em -`Navegando pela árvore`_ e `Buscando na árvore`_. Por agora, as características -mais importantes da tag são seu nome e atributos. - -Nome -^^^^ - -Toda tag possui um nome, acessível através de ``.name``:: - - tag.name - # u'b' - -Se você mudar o nome de uma tag, a alteração será refletida em qualquer HTML gerado pelo -Beautiful Soup:: - - tag.name = "blockquote" - tag - # <blockquote class="boldest">Extremely bold</blockquote> - -Atributos -^^^^^^^^^^ -Uma tag pode ter inúmeros atributos. A tag ``<b id="boldest">`` -possui um atributo "id" que possui o valor "boldest". Você pode -acessar um atributo de uma tag tratando-a como um dicionário:: - - tag['id'] - # u'boldest' - -Você pode acessar este dicionário diretamente através de ``.attrs``:: - - tag.attrs - # {u'id': 'boldest'} - -Você pode adicionar, remover ou modificar os atributos de uma tag. Novamente, isso pode -ser feito tratando a tag como um dicionário:: - - tag['id'] = 'verybold' - tag['another-attribute'] = 1 - tag - # <b another-attribute="1" id="verybold"></b> - - del tag['id'] - del tag['another-attribute'] - tag - # <b></b> - - tag['id'] - # KeyError: 'id' - print(tag.get('id')) - # None - -.. _multivalue: - -Atributos com múltiplos valores -&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& - -O HTML 4 define alguns atributos que podem ter múltiplos valores. O HTML 5 -removeu alguns deles, mas definiu alguns novos. O atributo mais comum -que pode receber múltiplos valores é o ``class`` (ou seja, a tag pode ter mais de uma classe CSS). -Outros são ``rel``, ``rev``, ``accept-charset``, ``headers``, e ``accesskey``. -O Beautiful Soup apresenta o(s) valor(es) de um atributo deste tipo como uma lista:: - - css_soup = BeautifulSoup('<p class="body"></p>') - css_soup.p['class'] - # ["body"] - - css_soup = BeautifulSoup('<p class="body strikeout"></p>') - css_soup.p['class'] - # ["body", "strikeout"] - -Se um atributo possui mais de um valor, mas não é um atributo -que aceita múltiplos valores conforme definido por qualquer versão do -padrão HTML, o Beautiful Soup retornará como um valor único:: - - id_soup = BeautifulSoup('<p id="my id"></p>') - id_soup.p['id'] - # 'my id' - -Quando a tag é transformada novamente em string, os valores do atributo múltiplo -são consolidados:: - - rel_soup = BeautifulSoup('<p>Back to the <a rel="index">homepage</a></p>') - rel_soup.a['rel'] - # ['index'] - rel_soup.a['rel'] = ['index', 'contents'] - print(rel_soup.p) - # <p>Back to the <a rel="index contents">homepage</a></p> - -Você pode desabilitar esta opção passando ``multi_valued_attributes=None`` como argumento -dentro do construtor ``BeautifulSoup`` :: - - no_list_soup = BeautifulSoup('<p class="body strikeout"></p>', 'html', multi_valued_attributes=None) - no_list_soup.p['class'] - # u'body strikeout' - -Você pode utilizar ```get_attribute_list`` para retornar um valor no formato de lista, seja um atributo de -múltiplos valores ou não:: - - id_soup.p.get_attribute_list('id') - # ["my id"] - -Se você analisar um documento como XML, nenhum atributo será tratado como de múltiplos valores:: - - xml_soup = BeautifulSoup('<p class="body strikeout"></p>', 'xml') - xml_soup.p['class'] - # u'body strikeout' - -Novamente, você pode configurar isto usando o argumento ``multi_valued_attributes``:: - - class_is_multi= { '*' : 'class'} - xml_soup = BeautifulSoup('<p class="body strikeout"></p>', 'xml', multi_valued_attributes=class_is_multi) - xml_soup.p['class'] - # [u'body', u'strikeout'] - -Você provavelmente não precisará fazer isso, mas se fizer, use os padrões como guia. -Eles implementam as regras descritas na especificação do HTML:: - - from bs4.builder import builder_registry - builder_registry.lookup('html').DEFAULT_CDATA_LIST_ATTRIBUTES - - -``NavigableString`` -------------------- - -Uma string corresponde a um texto dentro de uma tag. -O Beautiful Soup usa a classe ``NavigableString`` para armazenar este texto:: - - tag.string - # u'Extremely bold' - type(tag.string) - # <class 'bs4.element.NavigableString'> - -Uma ``NavigableString`` é como uma string Unicode do Python, exceto -que ela também suporta algumas características descritas em `Navegando pela árvore`_ -e `Buscando na árvore`_. Você pode converter um -``NavigableString`` em uma string Unicode utilizando ``unicode()``:: - - unicode_string = unicode(tag.string) - unicode_string - # u'Extremely bold' - type(unicode_string) - # <type 'unicode'> - -Você não pode editar uma string "in place", mas você pode substituir -uma string por outra usando :ref:`replace_with()`:: - - tag.string.replace_with("No longer bold") - tag - # <blockquote>No longer bold</blockquote> - -``NavigableString`` suporta a maior parte das características descritas em -`Navegando pela árvore`_ e `Buscando na árvore`_, mas não todas elas. -Em particular, desde que uma string não pode conter de tudo (da maneira que -uma tag pode conter uma string ou outra tag), as strings não suportam os -atributos ``.contents`` ou ``.string`` ou o método ``find()``. - -Se você quer utilizar uma ``NavigableString`` fora do Beautiful Soup, -você deve chamar o ``unicode()`` para transformá-la em uma string Unicode Python -padrão. Se você não fizer isso, sua string irá carregar uma referência de toda sua -árvore Beautiful Soup, mesmo que você já não esteja mais usando ela, o que é um grande -desperdício de memória. - -``BeautifulSoup`` ------------------ - -O objeto ``BeautifulSoup`` em si representa o documento como um todo. -Para maioria dos propósitos, você pode tratá-lo como um objeto :ref:`Tag`. -Isso significa que irá suportar a maioria dos métodos descritos em -`Navegando pela árvore`_ e `Buscando na árvore`_. - -Sabendo que o objeto ``BeautifulSoup`` não corresponde a uma tag -HTML ou XML propriamente dita, ele não tem nome e nem atributos. Mas em alguns -casos é útil observar seu ``.name``; então, foi dado o especial -``.name`` "[document]":: - - soup.name - # u'[document]' - -Comentários e outras strings especiais --------------------------------------- - -``Tag``, ``NavigableString``, e ``BeautifulSoup`` abrangem quase -tudo o que você encontrará em um arquivo HTML ou XML, mas há alguns -pontos faltando. O único deles que você provavelmente precisará se preocupar -é o comentário:: - - markup = "<b><!--Hey, buddy. Want to buy a used parser?--></b>" - soup = BeautifulSoup(markup) - comment = soup.b.string - type(comment) - # <class 'bs4.element.Comment'> - -O objeto ``Comment`` é apenas um tipo especial de ``NavigableString``:: - - comment - # u'Hey, buddy. Want to buy a used parser' - -Mas quando aparece como parte de um documento HTML, um ``Comment`` é -exibido com uma formatação especial:: - - print(soup.b.prettify()) - # <b> - # <!--Hey, buddy. Want to buy a used parser?--> - # </b> - -O Beautiful Soup define classes para qualquer outra coisa que possa -aparecer em um documento XML: ``CData``, ``ProcessingInstruction``, -``Declaration`` e ``Doctype``. Assim como ``Comment``, estas classes -são subclasses de ``NavigableString`` que adicionam algo a string. -Aqui está um exemplo que substitui o comentário por um bloco CDATA:: - - from bs4 import CData - cdata = CData("A CDATA block") - comment.replace_with(cdata) - - print(soup.b.prettify()) - # <b> - # <![CDATA[A CDATA block]]> - # </b> - - -Navegando pela árvore -===================== - -Aqui está o documento HTML "Three sisters" novamente:: - - html_doc = """ - <html><head><title>The Dormouse's story</title></head> - <body> - <p class="title"><b>The Dormouse's story</b></p> - - <p class="story">Once upon a time there were three little sisters; and their names were - <a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>, - <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and - <a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>; - and they lived at the bottom of a well.</p> - - <p class="story">...</p> - """ - - from bs4 import BeautifulSoup - soup = BeautifulSoup(html_doc, 'html.parser') - -Eu usarei este documento como exemplo para mostrar como navegar -de uma parte para outra do documento. - -Descendo na Árvore ------------------- -As tags podem conter strings e outras tags. Estes elementos são as tags -`filhas` (children). O Beautiful Soup oferece diferentes atributos para -navegar e iterar sobre as tags filhas. - -Note que as strings Beautiful Soup não suportam qualquer destes atributos, -porque uma string não pode ter filhos. - -Navegar usando os nomes das tags -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -A maneira mais simples de navegar pela árvore é utilizar -o nome da tag que você quer. Se você quer a tag <head>, -simplesmente use ``soup.head``:: - - soup.head - # <head><title>The Dormouse's story</title></head> - - soup.title - # <title>The Dormouse's story</title> - -Você pode usar este truque de novo, e de novo, para focar em certa parte da -árvore de análise. Este código retorna a primeira tag <b> abaixo da tag <body>:: - - soup.body.b - # <b>The Dormouse's story</b> - -Utilizando o nome da tag como atributo irá lhe retornar apenas a `primeira` -tag com aquele nome:: - - soup.a - # <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a> - -Se você precisar retornar `todas` as tags <a>, ou algo mais complicado -que a primeira tag com um certo nome, você precisará utilizar um dos -métodos descritos em `Buscando na árvore`_, como `find_all()`:: - - soup.find_all('a') - # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>, - # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>, - # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>] - -``.contents`` e ``.children`` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -As tags filhas de uma outra tag estão disponíveis em uma lista chamada por ``.contents``:: - - head_tag = soup.head - head_tag - # <head><title>The Dormouse's story</title></head> - - head_tag.contents - [<title>The Dormouse's story</title>] - - title_tag = head_tag.contents[0] - title_tag - # <title>The Dormouse's story</title> - title_tag.contents - # [u'The Dormouse's story'] - -O objeto ``BeautifulSoup`` em si possui filhos. Neste caso, a tag -<html> é a filha do objeto ``BeautifulSoup``.:: - - len(soup.contents) - # 1 - soup.contents[0].name - # u'html' - -Uma string não possui o atributo ``.contents``, porque ela não pode conter -nada:: - - text = title_tag.contents[0] - text.contents - # AttributeError: 'NavigableString' object has no attribute 'contents' - -Ao invés de retorná-las como uma lista, você pode iterar sobre as -tag's filhas usando o gerador ``.children``:: - - for child in title_tag.children: - print(child) - # The Dormouse's story - -``.descendants`` -^^^^^^^^^^^^^^^^ - -Os atributos ``.contents`` e ``.children`` somente consideram tags que -são `filhas diretas`. Por instância, a tag <head> tem apenas uma tag filha direta, -a tag <title>:: - - head_tag.contents - # [<title>The Dormouse's story</title>] - -Mas a tag <title> em si possui uma filha: a string "The Dormouse's story". -Existe uma percepção de que esta string também é filha da tag <head>. -O atributo ``.descendants`` permite que você itere sobre `todas` -as tags filhas, recursivamente: suas filhas diretas, as filhas de suas filhas, e assim por diante:: - - for child in head_tag.descendants: - print(child) - # <title>The Dormouse's story</title> - # The Dormouse's story - -A tag <head> possui apenas uma filha, mas também possui dois `descentendes`: -a tag <title> e a filha da tag <title>. O objeto ``BeautifulSoup`` possui apenas -uma filha direta (a tag <html>), mas ele possui vários descendentes:: - - len(list(soup.children)) - # 1 - len(list(soup.descendants)) - # 25 - -.. _.string: - -``.string`` -^^^^^^^^^^^ - -Se uma tag possui apenas uma filha, e esta filha é uma ``NavigableString``, -esta filha pode ser disponibilizada através de ``.string``:: - - title_tag.string - # u'The Dormouse's story' - -Se a filha única de uma tag é outra tag e esta tag possui uma -``.string``, então considera-se que a tag mãe tenha a mesma -``.string`` como sua filha:: - - head_tag.contents - # [<title>The Dormouse's story</title>] - - head_tag.string - # u'The Dormouse's story' - -Se uma tag contém mais de uma coisa, então não fica claro a que -``.string`` deve se referir, portanto ``.string`` será definida como -``None``:: - - print(soup.html.string) - # None - -.. _string-generators: - -``.strings`` e ``stripped_strings`` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Se existe mais de alguma coisa dentro da tag, você pode continuar -olhando apenas as strings. Use o gerador ``.strings``:: - - for string in soup.strings: - print(repr(string)) - # u"The Dormouse's story" - # u'\n\n' - # u"The Dormouse's story" - # u'\n\n' - # u'Once upon a time there were three little sisters; and their names were\n' - # u'Elsie' - # u',\n' - # u'Lacie' - # u' and\n' - # u'Tillie' - # u';\nand they lived at the bottom of a well.' - # u'\n\n' - # u'...' - # u'\n' - -Estas strings tendem a ter muitos espaços em branco, os quais você -pode remover utilizando o gerador ``.stripped_strings`` como alternativa:: - - for string in soup.stripped_strings: - print(repr(string)) - # u"The Dormouse's story" - # u"The Dormouse's story" - # u'Once upon a time there were three little sisters; and their names were' - # u'Elsie' - # u',' - # u'Lacie' - # u'and' - # u'Tillie' - # u';\nand they lived at the bottom of a well.' - # u'...' - -Aqui, strings formadas inteiramente por espaços em branco serão ignoradas, -e espaços em branco no início e no fim das strings serão removidos. - -Subindo na Árvore ------------------ - -Continuando a analogia da árvore como "família", toda tag e toda string possuem -`tags mães (parents)`: a tag que as contém. - -.. _.parent: - -``.parent`` -^^^^^^^^^^^ - -Você pode acessar o elemento mãe com o atributo ``.parent``. No -exemplo "three sisters", a tag <head> é mãe da tag <title>:: - - title_tag = soup.title - title_tag - # <title>The Dormouse's story</title> - title_tag.parent - # <head><title>The Dormouse's story</title></head> - -A string de title tem uma mãe: a tag <title> que a contém:: - - title_tag.string.parent - # <title>The Dormouse's story</title> - -A tag mãe de todo documento (<html>) é um objeto ``BeautifulSoup`` em si:: - - html_tag = soup.html - type(html_tag.parent) - # <class 'bs4.BeautifulSoup'> - -E o ``.parent`` de um objeto ``BeautifulSoup`` é definido como None:: - - print(soup.parent) - # None - -.. _.parents: - -``.parents`` -^^^^^^^^^^^^ -Você pode iterar sobre todos os elementos pais com -``.parents``. Este exemplo usa ``.parents`` para viajar de uma tag <a> -profunda no documento, para o elemento mais ao topo da árvore do documento:: - - link = soup.a - link - # <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a> - for parent in link.parents: - if parent is None: - print(parent) - else: - print(parent.name) - # p - # body - # html - # [document] - # None - -Navegando para os lados: ------------------------- - -Considere um simples documento como este:: - - sibling_soup = BeautifulSoup("<a><b>text1</b><c>text2</c></b></a>") - print(sibling_soup.prettify()) - # <html> - # <body> - # <a> - # <b> - # text1 - # </b> - # <c> - # text2 - # </c> - # </a> - # </body> - # </html> - -A tag <b> e a tag <c> estão no mesmo nível: ambas são filhas diretas -da mesma tag. Nós podemos chamá-las irmãs (`siblings`). -Quando um documento é pretty-printed, irmãs aparecem no mesmo nível de identação. -Você pode utilizar esta relação nos códigos que você escrever. - -``.next_sibling`` e ``.previous_sibling`` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Você pode usar ``.next_sibling`` e ``.previous_sibling`` para navegar -entre os elementos da página que estão no mesmo nível da árvore:: - - sibling_soup.b.next_sibling - # <c>text2</c> - - sibling_soup.c.previous_sibling - # <b>text1</b> - -A tag <b> possui ``.next_sibling``, mas não ``.previous_sibling``, -porque não há nada antes da tag <b> `no mesmo nível na árvore`. -Pela mesma razão, a tag <c> possui ``.previous_sibling`` -mas não ``.next_sibling``:: - - print(sibling_soup.b.previous_sibling) - # None - print(sibling_soup.c.next_sibling) - # None - -As strings "text1" e "text2" `não` são irmãs, porque elas não tem a mesma tag mãe:: - - sibling_soup.b.string - # u'text1' - - print(sibling_soup.b.string.next_sibling) - # None - -No mundo real, ``.next_sibling`` ou ``.previous_sibling`` de uma tag -geralmente são strings contendo espaços em branco. Voltando ao documento -"three sisters":: - - <a href="http://example.com/elsie" class="sister" id="link1">Elsie</a> - <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> - <a href="http://example.com/tillie" class="sister" id="link3">Tillie</a> - -Você pode pensar que o ``.next_sibling`` da primeira tag <a> será a segunda tag <a>. -Mas na verdade é uma string: a vírgula e um caracter de nova linha (\n) que separam -a primeira da segunda tag <a>:: - - link = soup.a - link - # <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a> - - link.next_sibling - # u',\n' - -A segunda tag <a> é, na verdade, a ``.next_sibling`` da vírgula:: - - link.next_sibling.next_sibling - # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a> - -.. _sibling-generators: - -``.next_siblings`` e ``.previous_siblings`` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Você pode iterar sobre as tag's filhas com ``.next_siblings`` -ou ``.previous_siblings``:: - - for sibling in soup.a.next_siblings: - print(repr(sibling)) - # u',\n' - # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a> - # u' and\n' - # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a> - # u'; and they lived at the bottom of a well.' - # None - - for sibling in soup.find(id="link3").previous_siblings: - print(repr(sibling)) - # ' and\n' - # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a> - # u',\n' - # <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a> - # u'Once upon a time there were three little sisters; and their names were\n' - # None - -Indo e voltando ----------------- - -Dê uma olhada no início do documento "three sisters":: - - <html><head><title>The Dormouse's story</title></head> - <p class="title"><b>The Dormouse's story</b></p> - -Um parser HTML transforma estas strings em uma série de eventos: "abrir -uma tag <html>", "abrir uma tag <head>", "abrir uma tag <title>", -"adicionar uma string", "fechar uma tag <title>, -"abrir uma tag <p>", e daí por diante. O Beautiful Soup oferece ferramentas -para reconstruir a análise inicial do documento. - -.. _element-generators: - -``.next_element`` e ``.previous_element`` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -O atributo ``.next_element`` de uma string ou tag aponta para -qualquer coisa que tenha sido interpretado posteriormente. -Isso deveria ser o mesmo que ``.next_sibling``, mas é -drasticamente diferente. - -Aqui está a tag <a> final no "three sisters". Sua -``.next_sibling`` é uma string: a conclusão da sentença -que foi interrompida pelo início da tag <a>.:: - - last_a_tag = soup.find("a", id="link3") - last_a_tag - # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a> - - last_a_tag.next_sibling - # '; and they lived at the bottom of a well.' - -Mas no ``.next_element`` da tag <a>, o que é analisado imediatamente -depois da tag <a> `não` é o resto da sentença: é a palavra "Tillie". - - last_a_tag.next_element - # u'Tillie' - -Isso porque na marcação original, a palavra "Tillie" apareceu -antes do ponto e virgula. O parser encontrou uma tag <a>, então -a palavra "Tillie", então fechando a tag </a>, então o ponto e vírgula e o -resto da sentença. O ponto e vírgula estão no mesmo nível que a tag <a>, -mas a palavra "Tillie" foi encontrada primeiro. - -O atributo ``.previous_element`` é exatamente o oposto de -``.next_element``. Ele aponta para qualquer elemento que -seja analisado antes do respectivo:: - - last_a_tag.previous_element - # u' and\n' - last_a_tag.previous_element.next_element - # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a> - -``.next_elements`` e ``.previous_elements`` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Você deve ter entendido a idéia agora. Você pode usar estes iteradores -para andar para frente e para atrás no documento quando ele for analisado:: - - for element in last_a_tag.next_elements: - print(repr(element)) - # u'Tillie' - # u';\nand they lived at the bottom of a well.' - # u'\n\n' - # <p class="story">...</p> - # u'...' - # u'\n' - # None - -Buscando na árvore -================== - -O Beautiful Soup define vários métodos para buscar na árvore que está sendo analisada, -mas eles são todos muito similares. Vou usar a maior parte do tempo para explicar os dois mais -populares métodos: ``find()`` e ``find_all()``. Os outros métodos recebem exatamente -os mesmos argumentos, portanto, vou cobrí-los apenas brevemente. - - -Mais uma vez, utilizarei o documento "three sisters" como exemplo:: - - html_doc = """ - <html><head><title>The Dormouse's story</title></head> - <body> - <p class="title"><b>The Dormouse's story</b></p> - - <p class="story">Once upon a time there were three little sisters; and their names were - <a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>, - <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and - <a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>; - and they lived at the bottom of a well.</p> - - <p class="story">...</p> - """ - - from bs4 import BeautifulSoup - soup = BeautifulSoup(html_doc, 'html.parser') - -Utilizando em um filtro um argumento como ``find_all()``, você pode -"dar um zoom" nas partes do documento que você está interessado. - -Tipos de filtros ----------------- - -Antes de entrar em detalhes sobre o ``find_all()`` e métodos similares, -quero mostrar exemplos de diferentes filtros que você pode passar dentro -destes métodos. Estes filtros aparecerão de novo e de novo por toda API -de pesquisa. Você pode usá-los para realizar filtros baseados nos nomes das tags, -nos seus atributos, no texto de uma strings ou em alguma combinação entre eles. - -.. _uma string: - -Uma string -^^^^^^^^^^ - -O filtro mais simples é uma string. Passando uma string para um método de pesquisa, -o Beautiful Soup irá buscar uma correspondência a esta exata string. O seguinte código -encontrará todas as tags <b> no documento:: - - soup.find_all('b') - # [<b>The Dormouse's story</b>] - -Se você passar uma byte string, o Beautiful Soup assumirá que a string -esta codificada como UTF-8. Você pode evitar isso passando ao invés disso -uma string Unicode. - -.. _uma expressão regular: - -Uma expressão regular (regex) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Se você passar um objeto `regex`, o Beautiful Soup irá -realizar um filtro com ela utilizando seu método ``search()``. -O código seguinte buscará todas as tags as quais os nomes comecem com -a letra "b"; neste caso, a tag <body> e a tag <b>:: - - import re - for tag in soup.find_all(re.compile("^b")): - print(tag.name) - # body - # b - -Este código buscará todas as tags cujo nome contenha a letra "t":: - - for tag in soup.find_all(re.compile("t")): - print(tag.name) - # html - # title - -.. _uma lista: - -Uma lista -^^^^^^^^^ - -Se você passar uma lista, o Beautiful Soup irá buscar -uma correspondência com qualquer item dessuma lista. -O código seguinte buscará todas as tags <a> e todas -as tags <b>:: - - soup.find_all(["a", "b"]) - # [<b>The Dormouse's story</b>, - # <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>, - # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>, - # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>] - -.. _the value True: - -``True`` -^^^^^^^^ - -O valor ``True`` irá corresponder com tudo. -O código abaixo encontrará ``todas`` as tags do documento, -mas nenhuma das strings:: - - for tag in soup.find_all(True): - print(tag.name) - # html - # head - # title - # body - # p - # b - # p - # a - # a - # a - # p - -.. _a function: - -Uma function -^^^^^^^^^^^^ - -Se nenhuma das opções anteriores funcionar para você, defina uma -função que pegará um elemento como seu único argumento. A função -deverá retornar ``True`` se o argumento corresponder e ``False`` -caso contrário. - -Aqui você tem uma função que irá retornar ``True`` se uma tag definir -o atributo `class`, mas não definir o atributo `id`:: - - def has_class_but_no_id(tag): - return tag.has_attr('class') and not tag.has_attr('id') - -Passe esta função dentro de ``find_all()`` e você irá retornar todas -as tags <p>:: - - soup.find_all(has_class_but_no_id) - # [<p class="title"><b>The Dormouse's story</b></p>, - # <p class="story">Once upon a time there were...</p>, - # <p class="story">...</p>] - -Esta função irá encontrar apenas as tags <p>. Não irá encontrar as tags <a>, -porque elas definem "class e "id" ao mesmo tempo. Ela não encontrará -as tags <html> e <title>, porque estas tags não definem um atributo -"class". - -Se você passar uma função para filtrar um atributo específico como -``href``, o argumento passado na função será o nome do atributo e -não toda a tag. Aqui vemos uma função que encontra todas as tags <a> -em que o atributo ``href`` não corresponde a expressão regular passada:: - - def not_lacie(href): - return href and not re.compile("lacie").search(href) - soup.find_all(href=not_lacie) - # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>, - # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>] - -A função pode ser tão complexa quanto você precise que seja. -Aqui temos uma função que retorna ``True`` se uma tag esta -cercada por objetos string:: - - from bs4 import NavigableString - def surrounded_by_strings(tag): - return (isinstance(tag.next_element, NavigableString) - and isinstance(tag.previous_element, NavigableString)) - - for tag in soup.find_all(surrounded_by_strings): - print tag.name - # p - # a - # a - # a - # p - -Agora nós estamos prontos para olhar os métodos de busca em detalhes. - -``find_all()`` --------------- - -Definição: find_all(:ref:`name <name>`, :ref:`attrs <attrs>`, :ref:`recursive -<recursive>`, :ref:`string <string>`, :ref:`limit <limit>`, :ref:`**kwargs <kwargs>`) - -O método ``find_all()`` busca entre os decendentes de uma tag e retorna todos os decendentes -que correspondem a seus filtros. Dei diversos exemplos em `Tipos de filtros`_, -mas aqui estão mais alguns:: - - soup.find_all("title") - # [<title>The Dormouse's story</title>] - - soup.find_all("p", "title") - # [<p class="title"><b>The Dormouse's story</b></p>] - - soup.find_all("a") - # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>, - # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>, - # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>] - - soup.find_all(id="link2") - # [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>] - - import re - soup.find(string=re.compile("sisters")) - # u'Once upon a time there were three little sisters; and their names were\n' - -Alguns podem parecer familiares, mas outros são novos. -O que significa passar um valor ``string`` ou ``id``? Por que -``find_all("p", "title")`` encontra uma tag <p> com a classe CSS "title"? -Vamos dar uma olhada nos argumentos de ``find_all()``. - -.. _name: - -O argumento ``name`` -^^^^^^^^^^^^^^^^^^^^ - -Passe um valor para ``name`` e você dirá para o Beautiful Soup -considerar apenas as tags com certos nomes. Strings de texto seão ignoradas, -assim como os nomes que não corresponderem ao argumento ``name`` - -Este é o uso mais simples:: - - soup.find_all("title") - # [<title>The Dormouse's story</title>] - -Lembre-se de `Tipos de filtros`_ que o valor para ``name`` pode ser `uma -string`_, `uma expressão regular`_, `uma lista`_, `uma função`_, ou `o valor -True`_. - -.. _kwargs: - -Os argumentos "palavras-chave" -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Qualquer argumento que não for reconhecido se tornará um filtro -de atributos da tag. Se você passar um valor para um argumento -chamado ``id``, o Beautiful Soup irá buscar correspondentes entre -todas tags ``id``:: - - soup.find_all(id='link2') - # [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>] - -Se você passar um valor para ``href``, o Beautiful Soup buscar correspondentes -em cada tag que possua o atributo ``href``:: - - soup.find_all(href=re.compile("elsie")) - # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>] - -Você pode filtrar um atributo baseado em `uma string`_, `uma regular -expression`_, `uma lista`_, `uma função`_, ou `no valor True`_. - -Este código encontra todas as tags em que o atributo ``id`` -possuem um valor, independente de qual valor seja:: - - soup.find_all(id=True) - # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>, - # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>, - # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>] - -Você pode filtrar múltiplos atributos de uma vez passando mais de um argumento -palavra-chave:: - - soup.find_all(href=re.compile("elsie"), id='link1') - # [<a class="sister" href="http://example.com/elsie" id="link1">three</a>] - -Alguns atributos, como o atributo data-* do HTML5, possuem nomes que não -podem ser usados como argumentos palavra-chave::: - - data_soup = BeautifulSoup('<div data-foo="value">foo!</div>') - data_soup.find_all(data-foo="value") - # SyntaxError: keyword can't be an expression - -Você pode usar estes atributos para realizar buscas, colocando-os -em um dicionário e passando o dicionário em ``find_all()``, como o argumento -``attrs``:: - - data_soup.find_all(attrs={"data-foo": "value"}) - # [<div data-foo="value">foo!</div>] - -Você não pode utilizar um argumento palavra-chave para buscar pelo elemento -HTML "name", porque o Beautiful Soup utiliza o argumento ``name`` para -conter o nome da própria tag. Ao invés disso, você pode passar o valor para -"name" no argumento ``attrs``:: - - name_soup = BeautifulSoup('<input name="email"/>') - name_soup.find_all(name="email") - # [] - name_soup.find_all(attrs={"name": "email"}) - # [<input name="email"/>] - -.. _attrs: - -Buscando por uma classe CSS -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -É muito útil buscar por uma tag que tem uma certa classe CSS, mas -o nome do atributo CSS, "class", é uma palavra reservada no Python. -Utilizar ``class`` como um argumento palavra-chave lhe trará um erro -de sintaxe. A partir do Beautiful Soup 4.1.2, você pode buscar por uma -classe CSS utilizando o argumento palavra-chave ``class_``:: - - soup.find_all("a", class_="sister") - # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>, - # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>, - # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>] - -Assim como qualquer argumento palavra-chave, você pode passar para ``class_`` -uma string, uma expressão regular (regex), uma função ou ``True``:: - - soup.find_all(class_=re.compile("itl")) - # [<p class="title"><b>The Dormouse's story</b></p>] - - def has_six_characters(css_class): - return css_class is not None and len(css_class) == 6 - - soup.find_all(class_=has_six_characters) - # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>, - # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>, - # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>] - -:ref:`Lembre-se <multivalue>` que uma tag pode ter valores múltiplos -para seu atributo classe. Quando você buscar por uma tag que tenha -uma certa classe CSS, você esta buscando correspodência em `qualquer` -de suas classes CSS:: - - css_soup = BeautifulSoup('<p class="body strikeout"></p>') - css_soup.find_all("p", class_="strikeout") - # [<p class="body strikeout"></p>] - - css_soup.find_all("p", class_="body") - # [<p class="body strikeout"></p>] - -Você pode também buscar por uma string exata como valor de ``class``:: - - css_soup.find_all("p", class_="body strikeout") - # [<p class="body strikeout"></p>] - -Mas ao procurar por variações de uma string, isso não irá funcionar:: - - css_soup.find_all("p", class_="strikeout body") - # [] - -Se voce quiser buscar por tags que correspondem a duas ou mais classes CSS, -você deverá utilizar um seletor CSS:: - - css_soup.select("p.strikeout.body") - # [<p class="body strikeout"></p>] - -Em versões mais antigas do Beautiful Soup, as quais não possuem o atalho ``class_`` -você pode utilizar o truque ``attrs`` conforme mencionado acima. Será criado um dicionário -do qual o valor para "class" seja uma string ( ou uma expressão regular, ou qualquer -outra coisa) que você queira procurar:: - - soup.find_all("a", attrs={"class": "sister"}) - # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>, - # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>, - # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>] - -.. _string: - -O argumento ``string`` -^^^^^^^^^^^^^^^^^^^^^^^ - -Com ``string`` você pode buscar por strings ao invés de tags. Assim como -``name`` e os argumentos palavras-chave, você pode passar `uma string`_, `uma -expressão regular`_, `uma lista`_, `uma função`_, ou `o valor True`_. -Aqui estão alguns exemplos:: - - soup.find_all(string="Elsie") - # [u'Elsie'] - - soup.find_all(string=["Tillie", "Elsie", "Lacie"]) - # [u'Elsie', u'Lacie', u'Tillie'] - - soup.find_all(string=re.compile("Dormouse")) - [u"The Dormouse's story", u"The Dormouse's story"] - - def is_the_only_string_within_a_tag(s): - """Return True if this string is the only child of its parent tag.""" - return (s == s.parent.string) - - soup.find_all(string=is_the_only_string_within_a_tag) - # [u"The Dormouse's story", u"The Dormouse's story", u'Elsie', u'Lacie', u'Tillie', u'...'] - -Mesmo que ``string`` seja para encontrar strings, você pode combiná-lo com argumentos -para encontrar tags: o Beautiful Soup encontrará todas as tags as quais -``.string`` corresponder seu valor em ``string``. O código seguinte encontra -a tag <a>, a qual a ``.string`` é "Elsie":: - - soup.find_all("a", string="Elsie") - # [<a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>] - -O argumento ``string`` é novo no Beautiful Soup 4.4.0. Em versões anteriores -ele era chamado de ``text``:: - - soup.find_all("a", text="Elsie") - # [<a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>] - -.. _limit: - -O argumento ``limit`` -^^^^^^^^^^^^^^^^^^^^^^ - -``find_all()`` retorna todas as tags e strings que correspondem aos seus -filtros. Isso pode levar algum tmepo se o documento for extenso. Se você -não precisar de `todos` os resultados, você pode passar um número limite -(``limit``). Ele funciona assim como o parâmetro LIMIT utilizado em SQL. -Ele diz ao Beautiful Soup para parar de adquirir resultados assim que atingir -um certo número. - -Existem três links no documento "three sisters", mas este código encontra somente -os dois primeiros:: - - soup.find_all("a", limit=2) - # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>, - # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>] - -.. _recursive: - -O argumento ``recursive`` -^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Se você chamar ``mytag.find_all()``, o Beautiful Soup irá examinar todos os descendentes -de ``mytag``: suas filhas, as filhas de suas filhas e daí em diante. Se você quer apenas que -o Beautiful Soup considere filhas diretas, você pode passar o parâmetro ``recursive=False``. -Veja a diferença aqui:: - - soup.html.find_all("title") - # [<title>The Dormouse's story</title>] - - soup.html.find_all("title", recursive=False) - # [] - -Aqui está o trecho do documento:: - - <html> - <head> - <title> - The Dormouse's story - </title> - </head> - ... - -O tag <title> esta abaixo da tag <html>, mas não está `diretamente` -abaixo de <html>: a tag <head> está no caminho entre elas. O Beautiful Soup encontra a tag -<title> quando é autorizado a olhar todos os descendentes de <html>, mas -quando ``recursive=False`` é restringido o acesso as filhas imediatas de <html>. - -O Beautiful Soup oferece diversos métodos de busca na árvore (como vimos acima), e a maioria -deles recebe os mesmos argumentos que ``find_all()``: ``name``, -``attrs``, ``string``, ``limit``, e os argumentos palavras-chave. Mas o -argumento ``recursive`` é diferente: ``find_all()`` e ``find()`` são -os únicos métodos que o suportam. Passar ``recursive=False`` em um método -como ``find_parents()`` não seria muito útil. - -Chamar uma tag é como chamar ``find_all()`` --------------------------------------------- - -Por ``find_all()`` ser o método mais popular na API de busca do -Beautiful Soup, você pode usar um atalho para ele. Se você tratar -o objeto ``BeautifulSoup`` ou um objeto ``Tag`` como se fosse uma -função, então é o mesmo que chamar ``find_all()`` para aquele objeto. -Estas duas linhas de código são equivalentes:: - - soup.find_all("a") - soup("a") - -Estas duas linhas também são equivalentes:: - - soup.title.find_all(string=True) - soup.title(string=True) - -``find()`` ----------- - -Signature: find(:ref:`name <name>`, :ref:`attrs <attrs>`, :ref:`recursive -<recursive>`, :ref:`string <string>`, :ref:`**kwargs <kwargs>`) - -O método ``find_all()`` varre todo o documento em busca de resultados, -mas algumas vezes você irá querer apenas um resultado. Se você sabe que -o documento possui apenas uma tag <body>, é perda de tempo varrer todo o -o documento procurando por outras. Ao invés de passar ``limit=1`` -toda vez em que chamar ``find_all``, você pode usar o método ``find()``. -Estas duas linhas de código são `quase` equivalentes:: - - soup.find_all('title', limit=1) - # [<title>The Dormouse's story</title>] - - soup.find('title') - # <title>The Dormouse's story</title> - -A única diferença é que ``find_all()`` retorna uma lista contendo apenas -um resuldado, enquanto ``find()`` retorna o resultado. - -Se ``find_all()`` não encontrar nada, ele retornará uma lista vazia. Se -``find()`` não encontrar nada, ele retornará ``None``:: - - print(soup.find("nosuchtag")) - # None - -Lembre-se do truque ``soup.head.title`` de `Navegar usando os nomes das tags`_? -Aquele truque funciona chamando repetidamente ``find()``:: - - soup.head.title - # <title>The Dormouse's story</title> - - soup.find("head").find("title") - # <title>The Dormouse's story</title> - -``find_parents()`` e ``find_parent()`` ----------------------------------------- - -Signature: find_parents(:ref:`name <name>`, :ref:`attrs <attrs>`, :ref:`string <string>`, :ref:`limit <limit>`, :ref:`**kwargs <kwargs>`) - -Signature: find_parent(:ref:`name <name>`, :ref:`attrs <attrs>`, :ref:`string <string>`, :ref:`**kwargs <kwargs>`) - -Levei muito tempo cobrindo ``find_all()`` e ``find()`` acima. -O API do Beautiful Soup define dez outros métodos -para buscas na árvore, mas não tenha medo! Cinco destes métodos são -basicamente o mesmo que ``find_all()``, e os outros cinco são basicamente -o mesmo que ``find()``. A única diferença está em qual parte da árvore -eles procuram. - -Primeiro vamos considerar ``find_parents()`` e -``find_parent()``. Lembre-se que ``find_all()`` e ``find()`` trabalham -de sua própria maneira descendo através da árvore, procurando pelos -descendentes de uma tag. Estes métodos fazem o contrário: eles trabalham -`subindo` a árvore, procurando pelas `mães` de uma tag (ou string). -Vamos experimentá-los: começando por uma string "enterrada" no documento -"three daughters":: - - a_string = soup.find(string="Lacie") - a_string - # u'Lacie' - - a_string.find_parents("a") - # [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>] - - a_string.find_parent("p") - # <p class="story">Once upon a time there were three little sisters; and their names were - # <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>, - # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a> and - # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>; - # and they lived at the bottom of a well.</p> - - a_string.find_parents("p", class="title") - # [] - -Uma das três tags <a> é diretamente um nível superior da string em -questão, então nossa busca a encontra. Uma das três tags <p> é uma mãe -indireta da string e nossa busca também a encontra. Há uma tag <p> com -a classe CSS "title" em algum lugar no documento, mas não é nenhuma das tags mães -da string, portanto, não podemos encontrá-la com ``find_parents()``. - -Você já deve ter feito a conexão entre ``find_parent()`` e -``find_parents()``, e os atributos `.parent`_ e `.parents`_ mencionados -anteriormente. A conexão é muito forte. Estes métodos de busca utilizam ``.parents`` -para iterar sobre todos as mãesS e compara cada um com o filtro passado -para verificar se preenche o requisito. - -``find_next_siblings()`` e ``find_next_sibling()`` ----------------------------------------------------- - -Signature: find_next_siblings(:ref:`name <name>`, :ref:`attrs <attrs>`, :ref:`string <string>`, :ref:`limit <limit>`, :ref:`**kwargs <kwargs>`) - -Signature: find_next_sibling(:ref:`name <name>`, :ref:`attrs <attrs>`, :ref:`string <string>`, :ref:`**kwargs <kwargs>`) - -Estes métodos utilizam :ref:`.next_siblings <sibling-generators>` para -iterar sobre o resto dos filhos de um elemento da árvore. O método -``find_next_siblings()`` retornará todos os filhos que atendem o -requisito ``find_next_sibling()`` retorna apenas o primeiro:: - - first_link = soup.a - first_link - # <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a> - - first_link.find_next_siblings("a") - # [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>, - # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>] - - first_story_paragraph = soup.find("p", "story") - first_story_paragraph.find_next_sibling("p") - # <p class="story">...</p> - -``find_previous_siblings()`` e ``find_previous_sibling()`` ------------------------------------------------------------- - -Signature: find_previous_siblings(:ref:`name <name>`, :ref:`attrs <attrs>`, :ref:`string <string>`, :ref:`limit <limit>`, :ref:`**kwargs <kwargs>`) - -Signature: find_previous_sibling(:ref:`name <name>`, :ref:`attrs <attrs>`, :ref:`string <string>`, :ref:`**kwargs <kwargs>`) - -Estes métodos utilizam :ref:`.previous_siblings <sibling-generators>` para iterar sobre os filhos de um elemento que -o precede na árvore. O método ``find_previous_siblings()`` -retorna todos os filhos que atendem o requisito e ``find_previous_sibling()``retorna apenas o primeiro:: - - last_link = soup.find("a", id="link3") - last_link - # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a> - - last_link.find_previous_siblings("a") - # [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>, - # <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>] - - first_story_paragraph = soup.find("p", "story") - first_story_paragraph.find_previous_sibling("p") - # <p class="title"><b>The Dormouse's story</b></p> - - -``find_all_next()`` e ``find_next()`` ---------------------------------------- - -Signature: find_all_next(:ref:`name <name>`, :ref:`attrs <attrs>`, :ref:`string <string>`, :ref:`limit <limit>`, :ref:`**kwargs <kwargs>`) - -Signature: find_next(:ref:`name <name>`, :ref:`attrs <attrs>`, :ref:`string <string>`, :ref:`**kwargs <kwargs>`) - -Estes métodos utilizam :ref:`.next_elements <element-generators>` para -iterar sobre qualquer tag e string que aparecer depois da atual no documento. -O método ``find_all_next()`` retorna todos os casos que atendem, e -``find_next()`` retorna somente o primeiro caso:: - - first_link = soup.a - first_link - # <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a> - - first_link.find_all_next(string=True) - # [u'Elsie', u',\n', u'Lacie', u' and\n', u'Tillie', - # u';\nand they lived at the bottom of a well.', u'\n\n', u'...', u'\n'] - - first_link.find_next("p") - # <p class="story">...</p> - -No primeiro exemplo, a string "Elsie" foi encontrada, mesmo estando -dentro da tag <a>. No segundo exemplo, a última tag <p> do documento foi -encontrada, mesmo que não esteja na mesma parte da árvore que <a> onde começamos. -Para estes métodos, o que importa é que um elemento corresponda ao filtro e esteja -depois do elemento de início no documento. - -``find_all_previous()`` e ``find_previous()`` ------------------------------------------------ - -Signature: find_all_previous(:ref:`name <name>`, :ref:`attrs <attrs>`, :ref:`string <string>`, :ref:`limit <limit>`, :ref:`**kwargs <kwargs>`) - -Signature: find_previous(:ref:`name <name>`, :ref:`attrs <attrs>`, :ref:`string <string>`, :ref:`**kwargs <kwargs>`) - -Estes métodos utilizam :ref:`.previous_elements <element-generators>` para -iterar sobre as tags e strings que aparecem antes do elemento indicado no argumento. -O método ``find_all_previous()`` retorna todos que correspondem a busca e o método -``find_previous()`` apenas a primeira correspondência:: - - first_link = soup.a - first_link - # <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a> - - first_link.find_all_previous("p") - # [<p class="story">Once upon a time there were three little sisters; ...</p>, - # <p class="title"><b>The Dormouse's story</b></p>] - - first_link.find_previous("title") - # <title>The Dormouse's story</title> - -Quando se chama ``find_all_previous("p")`` é encontrado não só o -primeiro parágrafo do documento (o que possui class="title"), mas também o -segundo parágrafo, a tag <p> que contém a tag <a> por onde começamos. -Isso não deveria ser tão surpreendente: nós estamos olhando para todas as tags -que apareceram anteriormente no documento incluindo aquela onde começamos. Uma -tag <p> que contenha uma tag <a> deve aparecer antes da tag <a> que ela contém. - -Seletores CSS -------------- - -A partir da versão 4.7.0, o Beautiful Soup suporta a maior parte dos seletores CSS4 -através do projeto `SoupSieve <https://facelessuser.github.io/soupsieve/>`_. Se você -instalou o Beautiful Soup através do ``pip``,o SoupSieve foi instalado ao mesmo tempo, -portanto você não precisará realizar nenhuma etapa adicional. - -``BeautifulSoup`` possui um método ``.select()`` o qual utiliza o SoupSieve para -executar um seletor CSS selector sobre um documento a ser analisado e retorna todos os -elementos correspondentes. ``Tag`` possui um método similar que executa um seletor CSS -sobre o conteúdo de uma única tag. - -(Versões anteriores do Beautiful Soup também possuem o método ``.select()``, - mas somente os seletores CSS mais populares são suportados. - -A `documentação <https://facelessuser.github.io/soupsieve/>`_ SoupSieve -lista todos os seletores suportados atualmente, mas aqui estão alguns dos -básicos:: - -Você pode encontrar tags:: - - soup.select("title") - # [<title>The Dormouse's story</title>] - - soup.select("p:nth-of-type(3)") - # [<p class="story">...</p>] - -Encontrar tags aninhadas com outras:: - soup.select("body a") - # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>, - # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>, - # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>] - - soup.select("html head title") - # [<title>The Dormouse's story</title>] - -Encontrar tags `diretamente` abaixo de outras tags no aninhamento:: - - soup.select("head > title") - # [<title>The Dormouse's story</title>] - - soup.select("p > a") - # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>, - # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>, - # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>] - - soup.select("p > a:nth-of-type(2)") - # [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>] - - soup.select("p > #link1") - # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>] - - soup.select("body > a") - # [] - -Encontrar as irmãs de alguma tag:: - - soup.select("#link1 ~ .sister") - # [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>, - # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>] - - soup.select("#link1 + .sister") - # [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>] - -Encontrar tags pela classe CSS:: - - soup.select(".sister") - # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>, - # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>, - # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>] - - soup.select("[class~=sister]") - # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>, - # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>, - # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>] - -Encontrar tags pelo ID:: - - soup.select("#link1") - # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>] - - soup.select("a#link2") - # [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>] - -Encontrar tags que se relacionam com qualquer seletor em uma lista de seletores:: - - soup.select("#link1,#link2") - # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>, - # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>] - -Testar a existência de um atributo:: - - soup.select('a[href]') - # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>, - # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>, - # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>] - -Encontrar tags pelo valor do atributo:: - - soup.select('a[href="http://example.com/elsie"]') - # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>] - - soup.select('a[href^="http://example.com/"]') - # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>, - # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>, - # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>] - - soup.select('a[href$="tillie"]') - # [<a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>] - - soup.select('a[href*=".com/el"]') - # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>] - -Há outro método chamado ``select_one()``, o qual encontra somente -a primeira tag que combina com um seletor:: - - soup.select_one(".sister") - # <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a> - -Se você analisou um XML que define namespaces, você pode -utilizar nos seletores CSS:: - - from bs4 import BeautifulSoup - xml = """<tag xmlns:ns1="http://namespace1/" xmlns:ns2="http://namespace2/"> - <ns1:child>I'm in namespace 1</ns1:child> - <ns2:child>I'm in namespace 2</ns2:child> - </tag> """ - soup = BeautifulSoup(xml, "xml") - - soup.select("child") - # [<ns1:child>I'm in namespace 1</ns1:child>, <ns2:child>I'm in namespace 2</ns2:child>] - - soup.select("ns1|child", namespaces=namespaces) - # [<ns1:child>I'm in namespace 1</ns1:child>] - -Quando manipulando um seletor CSS que utiliza -namespaces,o Beautiful Soup utiliza a abreviação do namespace -que encontrou quando estava analisando o documento. Você pode evitar isso -passando um dicionário com suas próprias abreviações:: - - namespaces = dict(first="http://namespace1/", second="http://namespace2/") - soup.select("second|child", namespaces=namespaces) - # [<ns1:child>I'm in namespace 2</ns1:child>] - -Todo este negócio de seletor CSS é conveniente -para pessoas que já sabem a sintaxe do seletor CSS. -Você pode fazer tudo isso com a API do BeautifulSoup. -E se os seletores CSS são tudo o que você precisa, -você deveria analisar o documento com lxml: é mais rápido. Mas isso deixa você `combinar` -seletores CSS com a API do Beautiful Soup. - -Modificando a árvore -==================== - -O principal poder do Beautiful Soup está na busca pela árvore, mas você -pode também modificar a árvore e escrever suas modificações como um novo -documento HTML ou XML. - -Alterando nomes de tags e atributos ---------------------------------- - -Cobri este assunto anteriormente em `Atributos`_, mas vale a pena repetir. Você -pode renomear uma tag, alterar o valor de algum de seus atributos, adicionar novos -atributos e deletar qualquer um deles:: - - soup = BeautifulSoup('<b class="boldest">Extremely bold</b>') - tag = soup.b - - tag.name = "blockquote" - tag['class'] = 'verybold' - tag['id'] = 1 - tag - # <blockquote class="verybold" id="1">Extremely bold</blockquote> - - del tag['class'] - del tag['id'] - tag - # <blockquote>Extremely bold</blockquote> - -Modificando ``.string`` ------------------------ - -Se você definir o um atributo ``.string`` de uma tag, o conteúdo da -tag será substituido pela string que foi passada:: - - markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>' - soup = BeautifulSoup(markup) - - tag = soup.a - tag.string = "New link text." - tag - # <a href="http://example.com/">New link text.</a> - -Cuidado: se a tag conter outra(s) tag(s), ela(s) e todo seu conteúdo -serão destruídos. - -``append()`` ------------- - -Você pode adicionar algo no conteúdo de uma tag com ``Tag.append()``. Funciona -da mesma maneira que ``.append()`` de uma lista:: - - soup = BeautifulSoup("<a>Foo</a>") - soup.a.append("Bar") - - soup - # <html><head></head><body><a>FooBar</a></body></html> - soup.a.contents - # [u'Foo', u'Bar'] - -``extend()`` ------------- - -Com início no Beautiful Soup 4.7.0, ``Tag`` também suporta um método chamado -``.extend()``, o qual funciona da mesma maneira que chamando ``.extend()`` em -uma lista:: - - soup = BeautifulSoup("<a>Soup</a>") - soup.a.extend(["'s", " ", "on"]) - - soup - # <html><head></head><body><a>Soup's on</a></body></html> - soup.a.contents - # [u'Soup', u''s', u' ', u'on'] - -``NavigableString()`` e ``.new_tag()`` -------------------------------------------------- - -Se você precisar adicionar uma string a um documento, sem problema -- você -pode passar uma string Python através de ``append()``, ou você pode chamar -o construtor ``NavigableString``:: - - soup = BeautifulSoup("<b></b>") - tag = soup.b - tag.append("Hello") - new_string = NavigableString(" there") - tag.append(new_string) - tag - # <b>Hello there.</b> - tag.contents - # [u'Hello', u' there'] - -Se você quiser criar um comentário ou alguma outra subclasse de -``NavigableString``, apenas chame o construtor:: - - from bs4 import Comment - new_comment = Comment("Nice to see you.") - tag.append(new_comment) - tag - # <b>Hello there<!--Nice to see you.--></b> - tag.contents - # [u'Hello', u' there', u'Nice to see you.'] - -(Esta é uma funcionalidade nova no Beautiful Soup 4.4.0.) - -E se você precisar criar uma nova tag? A melhor solução -é chamar o método ``BeautifulSoup.new_tag()``:: - - soup = BeautifulSoup("<b></b>") - original_tag = soup.b - - new_tag = soup.new_tag("a", href="http://www.example.com") - original_tag.append(new_tag) - original_tag - # <b><a href="http://www.example.com"></a></b> - - new_tag.string = "Link text." - original_tag - # <b><a href="http://www.example.com">Link text.</a></b> - -Somente o primeiro argumento (o nome da tag) é obrigatório. - -``insert()`` ------------- - -``Tag.insert()`` funciona assim como ``Tag.append()``, exceto que o novo elemento -não será inserido ao final do ``.contents`` de sua tag mãe. Ele será inserido em qualquer posição -numérica que você informar. Funciona assim como ``.insert()`` em uma lista:: - - markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>' - soup = BeautifulSoup(markup) - tag = soup.a - - tag.insert(1, "but did not endorse ") - tag - # <a href="http://example.com/">I linked to but did not endorse <i>example.com</i></a> - tag.contents - # [u'I linked to ', u'but did not endorse', <i>example.com</i>] - -``insert_before()`` e ``insert_after()`` ------------------------------------------- - -O método ``insert_before()`` insere tags ou strings imediatamente antes de algo -na árvore:: - - soup = BeautifulSoup("<b>stop</b>") - tag = soup.new_tag("i") - tag.string = "Don't" - soup.b.string.insert_before(tag) - soup.b - # <b><i>Don't</i>stop</b> - -O método ``insert_after()`` insere tags ou strings imediatamente após algo -na árvore:: - - div = soup.new_tag('div') - div.string = 'ever' - soup.b.i.insert_after(" you ", div) - soup.b - # <b><i>Don't</i> you <div>ever</div> stop</b> - soup.b.contents - # [<i>Don't</i>, u' you', <div>ever</div>, u'stop'] - -``clear()`` ------------ - -O ``Tag.clear()`` remove o conteúdo de uma tag:: - - markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>' - soup = BeautifulSoup(markup) - tag = soup.a - - tag.clear() - tag - # <a href="http://example.com/"></a> - -``extract()`` -------------- - -O ``PageElement.extract()`` remove uma tag ou string da árvore. Ele retorna -a tag ou string que foi extraída:: - - markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>' - soup = BeautifulSoup(markup) - a_tag = soup.a - - i_tag = soup.i.extract() - - a_tag - # <a href="http://example.com/">I linked to</a> - - i_tag - # <i>example.com</i> - - print(i_tag.parent) - None - -Neste ponto você efetivamente tem duas árvores de análise: uma baseada no objeto -``BeautifulSoup`` que você usou para analisar o documento, e outra baseada na tag que foi -extraída. Você pode também chamar ``extract`` em um filho do elemento que você extraiu:: - - my_string = i_tag.string.extract() - my_string - # u'example.com' - - print(my_string.parent) - # None - i_tag - # <i></i> - - -``decompose()`` ---------------- - -O ``Tag.decompose()`` remove uma tag da árvore, então destrói `completamente` ela -e seu conteúdo:: - - markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>' - soup = BeautifulSoup(markup) - a_tag = soup.a - - soup.i.decompose() - - a_tag - # <a href="http://example.com/">I linked to</a> - - -.. _replace_with(): - -``replace_with()`` ------------------- - -Um ``PageElement.replace_with()`` remove uma tag ou string da árvore e -substitui pela tag ou string que você escolher:: - - markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>' - soup = BeautifulSoup(markup) - a_tag = soup.a - - new_tag = soup.new_tag("b") - new_tag.string = "example.net" - a_tag.i.replace_with(new_tag) - - a_tag - # <a href="http://example.com/">I linked to <b>example.net</b></a> - -``replace_with()`` retorna a tag ou string que foi substituída, então você pode -examiná-la ou adicioná-la novamente em outra parte da árvore. - -``wrap()`` ----------- - -O ``PageElement.wrap()`` envelopa um elemento na tag que você especificar. Ele -retornará o novo empacotador:: - - soup = BeautifulSoup("<p>I wish I was bold.</p>") - soup.p.string.wrap(soup.new_tag("b")) - # <b>I wish I was bold.</b> - - soup.p.wrap(soup.new_tag("div") - # <div><p><b>I wish I was bold.</b></p></div> - -Este método é novo no Beautiful Soup 4.0.5. - -``unwrap()`` ---------------------------- - -O ``Tag.unwrap()`` é o oposto de ``wrap()``. Ele substitui uma tag pelo -que estiver dentro dela. É uma boa maneira de remover marcações:: - - markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>' - soup = BeautifulSoup(markup) - a_tag = soup.a - - a_tag.i.unwrap() - a_tag - # <a href="http://example.com/">I linked to example.com</a> - -Assim como ``replace_with()``, ``unwrap()`` retorna a tag que foi -substituída. - -``smooth()`` ---------------------------- - -Após chamar vários métodos que modificam a árvore, você pode acabar com um ou dois objetos ``NavigableString`` próximos um ao outro. O Beautiful Soup não tem nenhum problema com isso, mas como isso não pode acontecer em um documento que acabou de ser analisado, você não deve esperar um comportamento como o seguinte:: - - soup = BeautifulSoup("<p>A one</p>") - soup.p.append(", a two") - - soup.p.contents - # [u'A one', u', a two'] - - print(soup.p.encode()) - # <p>A one, a two</p> - - print(soup.p.prettify()) - # <p> - # A one - # , a two - # </p> - -Você pode chamar ``Tag.smooth()`` para limpar a árvore analisada, consolidando strings adjacentes:: - - soup.smooth() - - soup.p.contents - # [u'A one, a two'] - - print(soup.p.prettify()) - # <p> - # A one, a two - # </p> - -O método ``smooth()`` é novo no Beautiful Soup 4.8.0. - -Saída -====== - -.. _.prettyprinting: - -Pretty-printing ---------------- - -O método ``prettify()`` irá transformar uma árvore do Beautiful Soup em -uma string Unicode devidamente formatada, com uma linha para cada tag e cada string:: - - markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>' - soup = BeautifulSoup(markup) - soup.prettify() - # '<html>\n <head>\n </head>\n <body>\n <a href="http://example.com/">\n...' - - print(soup.prettify()) - # <html> - # <head> - # </head> - # <body> - # <a href="http://example.com/"> - # I linked to - # <i> - # example.com - # </i> - # </a> - # </body> - # </html> - -Você pode chamar ``prettify()`` no top-level do objeto ``BeautifulSoup``, -ou em qualquer de seus objetos ``Tag``:: - - print(soup.a.prettify()) - # <a href="http://example.com/"> - # I linked to - # <i> - # example.com - # </i> - # </a> - -Non-pretty printing -------------------- - -Se você quer apenas uma string, sem nenhuma formatação, você pode chamar -``unicode()`` ou ``str()`` para o objeto ``BeautifulSoup`` ou uma ``Tag`` -dentro dele:: - - str(soup) - # '<html><head></head><body><a href="http://example.com/">I linked to <i>example.com</i></a></body></html>' - - unicode(soup.a) - # u'<a href="http://example.com/">I linked to <i>example.com</i></a>' - -A função ``str()`` retorna uma string codificada em UTF-8. Veja -`Encodings`_ para outras opções. - -Você também pode chamar ``encode()`` para ter uma bytestring, e ``decode()`` -para ter Unicode. - -.. _output_formatters: - -Output formatters ------------------ - -Se você der para o Beautiful Soup um documento que contém entidades HTML como -"&lquot;", elas serão convertidades em caracteres Unicode:: - - soup = BeautifulSoup("“Dammit!” he said.") - unicode(soup) - # u'<html><head></head><body>\u201cDammit!\u201d he said.</body></html>' - -Se você converter o documento em uma string, os caracteres Unicode -serão codificados como UTF-8. Você não irá ter suas entidades HTML de volta:: - - str(soup) - # '<html><head></head><body>\xe2\x80\x9cDammit!\xe2\x80\x9d he said.</body></html>' - -Por padrão, os únicos caracteres que escapam desta saída são o & e os sinais de <>. -Eles são convertidos em "&", "<", -e ">", com isso o Beautiful Soup não gera HTML e XML inválidos de maneira inadvertida. - - soup = BeautifulSoup("<p>The law firm of Dewey, Cheatem, & Howe</p>") - soup.p - # <p>The law firm of Dewey, Cheatem, & Howe</p> - - soup = BeautifulSoup('<a href="http://example.com/?foo=val1&bar=val2">A link</a>') - soup.a - # <a href="http://example.com/?foo=val1&bar=val2">A link</a> - -Você pode alterar este comportamento informando um valor para o argumento de -``formatter`` para ``prettify()``, ``encode()``, ou -``decode()``. Beautiful Soup reconhece cinco possiveis valores para ``formatter``. - -O padrão é ``formatter="minimal"``. Strings sempre serão processadas de maneira a garantir que o Beautiful Soup gere HTML/XML válidos:: - - french = "<p>Il a dit <<Sacré bleu!>></p>" - soup = BeautifulSoup(french) - print(soup.prettify(formatter="minimal")) - # <html> - # <body> - # <p> - # Il a dit <<Sacré bleu!>> - # </p> - # </body> - # </html> - -Se você passar ``formatter="html"``, Beautiful Soup irá converter caracteres -Unicode para entidades HTML sempre que possível:: - - print(soup.prettify(formatter="html")) - # <html> - # <body> - # <p> - # Il a dit <<Sacré bleu!>> - # </p> - # </body> - # </html> - -Se você passar um ``formatter="html5"``, é o mesmo que ``formatter="html"``, -mas o Beautiful Soup irá omitir a barra de fechamento HTML:: - - soup = BeautifulSoup("<br>") - - print(soup.encode(formatter="html")) - # <html><body><br/></body></html> - - print(soup.encode(formatter="html5")) - # <html><body><br></body></html> - -Se você passar ``formatter=None``, Beautiful Soup não irá modificar -as strings na saída. Esta é a opção mais rápida, mas permitirá que o -Beautiful Soup gere HTML/XML inválidos, como nestes exemplos:: - - print(soup.prettify(formatter=None)) - # <html> - # <body> - # <p> - # Il a dit <<Sacré bleu!>> - # </p> - # </body> - # </html> - - link_soup = BeautifulSoup('<a href="http://example.com/?foo=val1&bar=val2">A link</a>') - print(link_soup.a.encode(formatter=None)) - # <a href="http://example.com/?foo=val1&bar=val2">A link</a> - -Se você precisar de controles mais sofisticados sobre sua saída, -você pode usar a classe ``Formatter`` do Beautiful Soup. Aqui você pode ver um -formatter que converte strings para uppercase, quando elas ocorrem em um nó de texto -ou em um valor de algum atributo:: - - from bs4.formatter import HTMLFormatter - def uppercase(str): - return str.upper() - formatter = HTMLFormatter(uppercase) - - print(soup.prettify(formatter=formatter)) - # <html> - # <body> - # <p> - # IL A DIT <<SACRÉ BLEU!>> - # </p> - # </body> - # </html> - - print(link_soup.a.prettify(formatter=formatter)) - # <a href="HTTP://EXAMPLE.COM/?FOO=VAL1&BAR=VAL2"> - # A LINK - # </a> - -Dividindo em subclasses ``HTMLFormatter`` ou ``XMLFormatter`` darão a você ainda -mais controle sobre a saída. Por exemplo, o Beautiful Soup ordena os atributos em toda -tag por padrão:: - - attr_soup = BeautifulSoup(b'<p z="1" m="2" a="3"></p>') - print(attr_soup.p.encode()) - # <p a="3" m="2" z="1"></p> - -Para desabilitar esta opção, você pode criar uma subclasse do método ``Formatter.attributes()``, -o qual controla qual atributo será usado na saída e em que ordem. Esta -implementação também filtra o atributido chamado "m" quando ele aparece:: - - class UnsortedAttributes(HTMLFormatter): - def attributes(self, tag): - for k, v in tag.attrs.items(): - if k == 'm': - continue - yield k, v - print(attr_soup.p.encode(formatter=UnsortedAttributes())) - # <p z="1" a="3"></p> - -Um último conselho: se você criar um objeto ``CDATA'', o texto dentro deste objeto -sempre estará presente `exatamente como aparenta, com nenhuma formatação`. -O Beautiful Soup irá chamar sua função de substituição da entidade, apenas -no caso de você ter escrito uma função personalizada que conta todas as strings -que existem no documento ou algo do tipo, mas ele irá ignorar o valor de retorno:: - - from bs4.element import CData - soup = BeautifulSoup("<a></a>") - soup.a.string = CData("one < three") - print(soup.a.prettify(formatter="xml")) - # <a> - # <![CDATA[one < three]]> - # </a> - - -``get_text()`` --------------- - -Se você quer apenas o texto contido no documento ou em um par de tags, você -pode utilizar o método ``get_text()``. Ele retornará todo texto em um documento -ou dentro das tags como uma string Unicode:: - - markup = '<a href="http://example.com/">\nI linked to <i>example.com</i>\n</a>' - soup = BeautifulSoup(markup) - - soup.get_text() - u'\nI linked to example.com\n' - soup.i.get_text() - u'example.com' - -Você pode especificar uma string a ser usada para unir as partes do texto:: - - # soup.get_text("|") - u'\nI linked to |example.com|\n' - -Você pode dizer ao Beautiful Soup para excluir espaços em branco do início -e fim de cada parte de texto:: - - # soup.get_text("|", strip=True) - u'I linked to|example.com' - -Contudo para isso, você pode querer utilizar o gerador :ref:`.stripped_strings <string-generators>` -e processar o texto você mesmo:: - - [text for text in soup.stripped_strings] - # [u'I linked to', u'example.com'] - -Especificando um interpretador (parser) para uso -================================================ - -Se você precisa analisar um pequeno HTML, você pode passá-lo no construtor do -``BeautifulSoup`` e será o suficiente. O Beautiful Soup irá escolher um parser -para você e irá interpretar o dado. Mas existem alguns argumentos adicionais que você -pode passar no construtor para alterar qual parser será usado. - -O primeiro argumento do construtor ``BeautifulSoup`` é uma string ou uma variável contendo o -conteúdo do que você quer analisar. O segundo argumento é `como` você quer interpretar aquele -conteúdo. - -Se você não especificar nada, você irá utilizar o melhor analisador HTML instalado. -O Beautiful Soup classifica o lxml's como sendo o melhor, logo em seguida o html5lib, -e então o parser nativo do Python. Você pode substituí-lo, especificando de acordo -com as seguintes características: - -* O tipo de marcação que você quer analisar. Atualmente são suportados - "html", "xml", and "html5". -* O nome do parser que você quer utilizar. Atualmente são suportadas -as opções "lxml", "html5lib", e "html.parser" (parser nativo do Python). - -A seção `Instalando um interpretador (parser)`_ compara os parsers suportados. - -Se você não tem um parser apropriado instalado, o Beautiful Soup irá -ignorar sua solicitação e escolher um diferente. Atualmente, o único parser -XML suportado é o lxml. Se você não possui o lxml instalado, pedir um parser -XML não trará um e pedir por "lxml" não funcionará também. - -Diferenças entre os interpretadores (parsers) ------------------------------------------- - -O Beautiful Soup apresenta a mesma interface para diferentes parsers, -mas cada um é diferente. Diferentes parsers irão criar diferentes análises da árvore -do mesmo documento. As maiores diferenças estão entre os parsers HTML e XML. -Aqui está um pequeno documento analisado como HTML:: - - BeautifulSoup("<a><b /></a>") - # <html><head></head><body><a><b></b></a></body></html> - -Como uma tag <b /> vazia não é um HTML válido, o analisador a transforma -em um par <b></b>. - -Aqui está o mesmo documento analisado como XML (partindo do princípio -que você tenha o lxml instalado). Note que o a tag vazia <b /> é deixada sozinha, -e que é dada ao documento uma declaração XML ao invés de ser colocada dentro de uma tag <html>.:: - - BeautifulSoup("<a><b /></a>", "xml") - # <?xml version="1.0" encoding="utf-8"?> - # <a><b/></a> - -Há também diferenças entre analisadores HTML. Se você der ao Beautiful -Soup um documento HTML perfeitamente formatado, estas diferenças não irão -importar. Um analisador será mais rápido que outro, mas todos irão lhe -retornar uma estrutura de dados que se parece exatamente como o HTML original. - -Mas se o documento não estiver perfeitamente formatado, diferentes analisadores -irão retornar diferentes resultados. Aqui está um pequeno e inválido documento -analisado utilizando o analisador lxml HTML. Note que a tag pendente </p> é -simplesmente ignorada:: - - BeautifulSoup("<a></p>", "lxml") - # <html><body><a></a></body></html> - -Aqui está o mesmo documento analisado utilizando html5lib:: - - BeautifulSoup("<a></p>", "html5lib") - # <html><head></head><body><a><p></p></a></body></html> - -Ao invés de ignorar a tag </p> pendente, o html5lib a equipara a uma tag -<p> aberta. Este parser também adiciona uma tag <head> vazia ao documento. - -Aqui está o mesmo documento analisado com o parser HTML nativo do Python:: - - BeautifulSoup("<a></p>", "html.parser") - # <a></a> - -Assim como html5lib, este parser ignora a tag de fechamento </p>. -Este parser também não realiza nenhuma tentatida de criar um HTML bem -formatado adicionando uma tag <body>. Como lxml, ele nem se importa em -adicionar uma tag <html>. - -Sendo o documento "<a></p>" inválido, nenhuma dessas técnicas é a maneira -"correta" de lidar com isso. O html5lib utiliza técnicas que são parte -do padrão HTML5, portanto vendo sendo definido como a maneira "mais correta", -mas todas as três técnicas são legítimas. - -Diferenças entre analisadores podem afetar o seu script. Se você está -planejando distribuir seu script para outras pessoas, ou rodá-lo em -múltiplas máquinas, você deve especificar o analisador no construtor -``BeautifulSoup``. Isso irá reduzir as chances de que seus usuários -analisem um documento de forma diferente da maneira como você analisou. - - -Codificação (Encoding) -====================== - -Todo documento HTML ou XML é escrito em uma codificação (encoding) específica como ASCII -ou UTF-8. Mas quando você carrega um documento no BeautifulSoup, você irá descobrir -que ele foi convertido para Unicode:: - - markup = "<h1>Sacr\xc3\xa9 bleu!</h1>" - soup = BeautifulSoup(markup) - soup.h1 - # <h1>Sacré bleu!</h1> - soup.h1.string - # u'Sacr\xe9 bleu!' - -Não é mágica (Seria bem legal que fosse). O BeautifulSoup utiliza uma -sub-biblioteca chamada `Unicode, Dammit`_ para detectar a codificação de -um documento e convertê-lo para Unicode. A codificação detectada automaticamente está -disponível como objeto ``.original_encoding`` atributo do objeto ``BeautifulSoup`` :: - - soup.original_encoding - 'utf-8' - -`Unicode, Dammit` acerta na maioria das vezes, mas pode errar em algumas. -Outras vezes acerta, porém somente após uma busca byte a byte no documento, -o leva muito tempo. Se você souber com antecedência a codificação, você poderá -evitar erros ou demora passando-o para o contrutor do ``BeautifulSoup`` -através de ``from_encoding``. - -Abaixo você tem um documento escrito em ISO-8859-8. O documento é tão -pequeno que o `Unicode, Dammit` não consegue verificar sua codificação -e acaba fazendo a identificação como ISO-8859-7:: - - markup = b"<h1>\xed\xe5\xec\xf9</h1>" - soup = BeautifulSoup(markup) - soup.h1 - <h1>νεμω</h1> - soup.original_encoding - 'ISO-8859-7' - -Podemos consertar isso passando a codificação correta com ``from_encoding``:: - - soup = BeautifulSoup(markup, from_encoding="iso-8859-8") - soup.h1 - <h1>םולש</h1> - soup.original_encoding - 'iso8859-8' - -Se você não sabe qual a codificação correta, mas você sabe que o -`Unicode, Dammit` está errado, você pode passar as opções excluentes -como ``exclude_encodings``:: - - soup = BeautifulSoup(markup, exclude_encodings=["ISO-8859-7"]) - soup.h1 - <h1>םולש</h1> - soup.original_encoding - 'WINDOWS-1255' - -Windows-1255 não é 100% correto, mas é um superconjunto compatível com -ISO-8859-8, portanto é mais próximo do ideal. (``exclude_encodings`` -é uma opção nova no Beautiful Soup 4.4.0.) - -Em casos raros (geralmente quando um documento UTF-8 contém texto escrito -em uma codificação completamente diferente), a única maneira de ser convertido para -Unicode é convertendo alguns caracteres com o caractere especial Unicode -"REPLACEMENT CHARACTER" (U+FFFD, �). Se o `Unicode, Dammit` precisar utilizá-lo, -ele será armazenado no atributo ``.contains_replacement_characters`` como -``True`` no ``UnicodeDammit`` ou objeto ``BeautifulSoup``. Isso deixa você ciente -que a representação Unicode não é uma representação exata do original - algum dado -foi perdido. Se um documento possui �, mas ``.contains_replacement_characters`` é ``False``, -você poderá concluir então que o � já estava ali originalmente e não representa dados -perdidos. - -Codificação de Saída --------------------- - -Quando um documento é gerado pelo Beautiful Soup, ele é gerado como UTF-8, -mesmo que o documento não for um UTF-8 de início. Aqui está um documento gerado -com codificação Latin-1:: - - markup = b''' - <html> - <head> - <meta content="text/html; charset=ISO-Latin-1" http-equiv="Content-type" /> - </head> - <body> - <p>Sacr\xe9 bleu!</p> - </body> - </html> - ''' - - soup = BeautifulSoup(markup) - print(soup.prettify()) - # <html> - # <head> - # <meta content="text/html; charset=utf-8" http-equiv="Content-type" /> - # </head> - # <body> - # <p> - # Sacré bleu! - # </p> - # </body> - # </html> - -Note que a tag <meta> foi reescrita para refletir o fato que o documento -é agora um UTF-8. - -Se você não quiser um UTF-8, você pode passar a codificação desejada como parâmetro de -``prettify()``:: - - print(soup.prettify("latin-1")) - # <html> - # <head> - # <meta content="text/html; charset=latin-1" http-equiv="Content-type" /> - # ... - -Você também pode chamar encode() no objeto ``BeautifulSoup`` ou em qualquer elemento -do objeto, assim como se faz em uma string Python:: - - soup.p.encode("latin-1") - # '<p>Sacr\xe9 bleu!</p>' - - soup.p.encode("utf-8") - # '<p>Sacr\xc3\xa9 bleu!</p>' - -Qualquer caractere que não pode ser representado na codificação escolhida -irá ser convertida para uma entidade de referência numérica XML. Abaixo você -tem um documento que inclui o caractere Unicode SNOWMAN:: - - markup = u"<b>\N{SNOWMAN}</b>" - snowman_soup = BeautifulSoup(markup) - tag = snowman_soup.b - -O caractere SNOWMAN faz parte da documentação UTF-8 (algo como -☃), mas não possui representação para este caractere em ISO-latin-1 ou -ASCII, portanto ele é convertido para "☃" para as essas codificações:: - - print(tag.encode("utf-8")) - # <b>☃</b> - - print tag.encode("latin-1") - # <b>☃</b> - - print tag.encode("ascii") - # <b>☃</b> - -Unicode, Dammit ---------------- - -Você pode usar o `Unicode, Dammit` fora do Beautiful Soup. É útil -quando você possui dados em uma codificação desconhecida e quer -simplesmente convertê-la para Unicode:: - - from bs4 import UnicodeDammit - dammit = UnicodeDammit("Sacr\xc3\xa9 bleu!") - print(dammit.unicode_markup) - # Sacré bleu! - dammit.original_encoding - # 'utf-8' - - -As respostas do `Unicode, Dammit` serão um pouco mais precisas se você -instalar as bibliotecas ``chardet`` ou ``cchardet``. Quanto maior a quantidade -de dados no arquivo que você passar para o `Unicode, Dammit`, mais precisas serão -as conversões. Se você possui suas suspeitas sobre qual a codificação original, -você pode passar as opções em uma lista:: - - dammit = UnicodeDammit("Sacr\xe9 bleu!", ["latin-1", "iso-8859-1"]) - print(dammit.unicode_markup) - # Sacré bleu! - dammit.original_encoding - # 'latin-1' - -`Unicode, Dammit` possui duas características que o Beautiful Soup não utiliza. - -Smart quotes -^^^^^^^^^^^^ - -Você pode utilizar `Unicode, Dammit` para converter Microsoft smart quotes para -entidades HTML ou XML:: - - markup = b"<p>I just \x93love\x94 Microsoft Word\x92s smart quotes</p>" - - UnicodeDammit(markup, ["windows-1252"], smart_quotes_to="html").unicode_markup - # u'<p>I just “love” Microsoft Word’s smart quotes</p>' - - UnicodeDammit(markup, ["windows-1252"], smart_quotes_to="xml").unicode_markup - # u'<p>I just “love” Microsoft Word’s smart quotes</p>' - -Você também pode converter Microsoft smart quotes para ASCII:: - - UnicodeDammit(markup, ["windows-1252"], smart_quotes_to="ascii").unicode_markup - # u'<p>I just "love" Microsoft Word\'s smart quotes</p>' - -Espero que você ache estas características úteis, mas o Beautiful Soup não -as usa.O Beautiful Soup dá preferência ao comportamento padrão, que é -converter para caracteres Unicode:: - - UnicodeDammit(markup, ["windows-1252"]).unicode_markup - # u'<p>I just \u201clove\u201d Microsoft Word\u2019s smart quotes</p>' - -Codificação Inconsistente -^^^^^^^^^^^^^^^^^^^^^^^^^ - -Algumas vezes um documento é em sua maioria UTF-8, mas contém caracteres -Windows-1252 assim como (de novo) Microsoft smart quotes. Isso pode acontecer -quando um website compostos de dados de muitas fontes diferentes. Você pode -utilizar ``UnicodeDammit.detwingle()`` para transformar este documento em um -UTF-8 puro. Aqui está um exemplo:: - - snowmen = (u"\N{SNOWMAN}" * 3) - quote = (u"\N{LEFT DOUBLE QUOTATION MARK}I like snowmen!\N{RIGHT DOUBLE QUOTATION MARK}") - doc = snowmen.encode("utf8") + quote.encode("windows_1252") - -Este documento é uma bagunça. O snowmen é um UTF-8 e as aspas são Windows-1252. -Você pode exibir o snowmen ou as aspas, mas não os dois ao mesmo tempo:: - - print(doc) - # ☃☃☃�I like snowmen!� - - print(doc.decode("windows-1252")) - # ☃☃☃“I like snowmen!” - -Decodificar um documento como UTF-8 gera um ``UnicodeDecodeError``, e -como um Windows-1252 lhe tras algo sem sentido. Felizmente, -``UnicodeDammit.detwingle()`` irá converter a string para UTF-8 puro, -permitindo a você decodificá-la para Unicode e exibir o snowmen e as -aspas simultaneamente:: - - new_doc = UnicodeDammit.detwingle(doc) - print(new_doc.decode("utf8")) - # ☃☃☃“I like snowmen!” - -``UnicodeDammit.detwingle()`` sabe apenas como trabalhar com Windows-1252 -contido em UTF-8 (ou vice versa, eu suponho), mas este é o caso mais comum. - -Note que você deve chamar ``UnicodeDammit.detwingle()`` em seu dado -antes de passá-lo para ``BeautifulSoup`` ou para o construtor ``UnicodeDammit``. -O Beautiful Soup assume que um documento possui apenas uma codificação, -independente de qual ela seja. Se você passar um documento que -contém ambos UTF-8 e Windows-1252, é provável que ele pense que todo -o documento seja Windows-1252, e o documento parecerá ``☃☃☃“I like snowmen!”``. - -``UnicodeDammit.detwingle()`` é novo no Beautiful Soup 4.1.0. - -Linhas numeradas -================ - -Os interpretadores ``html.parser` e ``html5lib`` podem rastrear onde, no -documento original, cada tag foi encontrada. Você pode acessar esta -informação através de ``Tag.sourceline`` (número da linha) e ``Tag.sourcepos`` -(posição do início da tag na linha):: - - markup = "<p\n>Paragraph 1</p>\n <p>Paragraph 2</p>" - soup = BeautifulSoup(markup, 'html.parser') - for tag in soup.find_all('p'): - print(tag.sourceline, tag.sourcepos, tag.string) - # (1, 0, u'Paragraph 1') - # (2, 3, u'Paragraph 2') - -Note que os dois interpretadores significam coisas levemente diferentes por -``sourceline`` e ``sourcepos``. Para html.parser, estes números representam -a posição do sinal `menor que`inicial. Para html5lib, representa a posição -do sinal `maior que` final:: - - soup = BeautifulSoup(markup, 'html5lib') - for tag in soup.find_all('p'): - print(tag.sourceline, tag.sourcepos, tag.string) - # (2, 1, u'Paragraph 1') - # (3, 7, u'Paragraph 2') - -Você pode desabilitar esta característica passando ``store_line_numbers=False` -no construtor ``BeautifulSoup``:: - - markup = "<p\n>Paragraph 1</p>\n <p>Paragraph 2</p>" - soup = BeautifulSoup(markup, 'html.parser', store_line_numbers=False) - soup.p.sourceline - # None - -Esta característica é nova no 4.8.1 e os analisadores baseados no lxml -não a suportam. - -Comparando objetos por igualdade -============================== - -O Beautiful Soup diz que dois objetos ``NavigableString`` ou ``Tag`` são -iguais quando eles apresentam as mesma marcação HTML ou XML. No exemplo -abaixo, as duas tags <b> são tratadas como iguais, mesmo estando em partes -diferentes da árvore do objeto, porque ambas estão como "<b>pizza</b>":: - - markup = "<p>I want <b>pizza</b> and more <b>pizza</b>!</p>" - soup = BeautifulSoup(markup, 'html.parser') - first_b, second_b = soup.find_all('b') - print first_b == second_b - # True - - print first_b.previous_element == second_b.previous_element - # False - -Se você quiser verificar se duas variáveis se referem exatamente ao -mesmo objeto, use `is`:: - - print first_b is second_b - # False - -Copiando objetos Beautiful Soup -=============================== - -Você pode utilizar ``copy.copy()`` para criar uma cópia de qualquer ``Tag`` ou -``NavigableString``:: - - import copy - p_copy = copy.copy(soup.p) - print p_copy - # <p>I want <b>pizza</b> and more <b>pizza</b>!</p> - - -A cópia será considerada igual ao original, desde que ela apresente a mesma -marcação que o original, mas não será o mesmo objeto:: - - print soup.p == p_copy - # True - - print soup.p is p_copy - # False - -A única diferença real é que a cópia é completamente separada da árvore -original do Beautiful Soup, como se ``extract()`` fosse chamado para ela:: - - print p_copy.parent - # None - -Isso acontece porque dois objetos ``Tag`` diferentes não podem ocupar o mesmo -espaço ao mesmo tempo. - - -Analisando apenas parte de um documento -======================================= - -Suponhamos que você queira que o Beautiful Soup olhe apenas para as -tags <a> de um documento. É um desperdício de tempo e memória analisar -todo o documento e, posteriormente, analisar novamente apenas para buscar -as tags <a>. Seria muito mais rápido ignorar tudo o que não for <a> em -primeiro lugar. A classe ``SoupStrainer`` permite que você escolha -qual partes do documento serão analisadas. Você deverá penas criar uma -instância de ``SoupStrainer`` e passá-la ao construtor ``BeautifulSoup`` -no argumento ``parse_only``. - -(Note que *esta característica não funcionará se você estiver utilizando -o html5lib*. Se você utilizar o html5lib, todo o documento será analisado. -Isso acontece porque html5lib constantemente reorganiza a árvore de análise -e se alguma parte do documento realmente não fizer parte dela, ela irá quebrar. -Para evitar confusão, no exemplo abaixo, forçarei o Beautiful Soup a usar o -analisador nativo do Python). - -``SoupStrainer`` ----------------- - -A classe ``SoupStrainer`` recebe os mesmos argumentos que qualquer método em `Buscando na árvore`_: :ref:`name <name>`, :ref:`attrs -<attrs>`, :ref:`string <string>`, e :ref:`**kwargs <kwargs>`. Aqui temos três objetos ``SoupStrainer`` :: - - from bs4 import SoupStrainer - - only_a_tags = SoupStrainer("a") - - only_tags_with_id_link2 = SoupStrainer(id="link2") - - def is_short_string(string): - return len(string) < 10 - - only_short_strings = SoupStrainer(string=is_short_string) - -Irei trazer de volta o documento "three sisters" mais uma vez e veremos -como o documento se parece quando é analisado com estes três objetos ``SoupStrainer` -diferentes:: - - html_doc = """ - <html><head><title>The Dormouse's story</title></head> - <body> - <p class="title"><b>The Dormouse's story</b></p> - - <p class="story">Once upon a time there were three little sisters; and their names were - <a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>, - <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and - <a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>; - and they lived at the bottom of a well.</p> - - <p class="story">...</p> - """ - - print(BeautifulSoup(html_doc, "html.parser", parse_only=only_a_tags).prettify()) - # <a class="sister" href="http://example.com/elsie" id="link1"> - # Elsie - # </a> - # <a class="sister" href="http://example.com/lacie" id="link2"> - # Lacie - # </a> - # <a class="sister" href="http://example.com/tillie" id="link3"> - # Tillie - # </a> - - print(BeautifulSoup(html_doc, "html.parser", parse_only=only_tags_with_id_link2).prettify()) - # <a class="sister" href="http://example.com/lacie" id="link2"> - # Lacie - # </a> - - print(BeautifulSoup(html_doc, "html.parser", parse_only=only_short_strings).prettify()) - # Elsie - # , - # Lacie - # and - # Tillie - # ... - # - -Você pode também passar um ``SoupStrainer`` em qualquer método coberto em `Buscando na árvore`_. -Este uso provavelmente não seja muito útil, mas pensei que deveria mencioná-lo:: - - soup = BeautifulSoup(html_doc) - soup.find_all(only_short_strings) - # [u'\n\n', u'\n\n', u'Elsie', u',\n', u'Lacie', u' and\n', u'Tillie', - # u'\n\n', u'...', u'\n'] - -Solucionando Problemas -====================== - -.. _diagnose: - -``diagnose()`` --------------- - -Se você está tendo problemas em entender o que o Beautiful Soup está -fazendo com um documento, passe o documento pela função ``diagnose()``. (Nova no Beautiful Soup 4.2.0.) -O Beautiful Soup irá retornar um relatório mostrando como diferentes parsers -lidam com o documento e irá lhe dizer o Beautiful Soup poderia estar utilizando outro parser:: - - from bs4.diagnose import diagnose - with open("bad.html") as fp: - data = fp.read() - diagnose(data) - - # Diagnostic running on Beautiful Soup 4.2.0 - # Python version 2.7.3 (default, Aug 1 2012, 05:16:07) - # I noticed that html5lib is not installed. Installing it may help. - # Found lxml version 2.3.2.0 - # - # Trying to parse your data with html.parser - # Here's what html.parser did with the document: - # ... - -Olhando para o que diagnose() retorna, poderá lhe dizer como resolver -o seu problema. Mesmo que não consiga, você poderá colar a saída de ``diagnose()`` -quando solicitar ajuda. - -Erros enquanto se analisa um documento --------------------------------------- - -Existem dois tipos diferentes de erros de análise. Existem quebras -quando você passa para o Beautiful Soup um documento e ele retorna uma -exceção, geralmente um ``HTMLParser.HTMLParseError``. E existe o comportamento -inesperado, quando uma árvore de análise parece um pouco diferente do -documento usado para criá-la. - -Quase nenhum destes problemas são parte do Beautiful Soup. Não é -porque o Beautiful Soup é maravilhosamente um software bem escrito. É -porque o Beautiful Soup não inclui nenhum código de análise. Ao invés disso, -ele depende de analisadores externos. Se um analisador não funciona com -certo documento, a melhor solução é tentar um analisador diferente. Veja -`Instalando um analisador`_ para detalhes e uma comparação entre eles. - -Os erros de interpretação mais comuns são ``HTMLParser.HTMLParseError: - -malformed start tag`` e ``HTMLParser.HTMLParseError: bad end -tag``. Existem dois parsers gerados para o parser built in do Python -e a solução é :ref:`install lxml ou html5lib. <parser-installation>` - -Os tipos de erros de comportamento inesperado mais comuns acontecem -quando não é encontrada a tag buscada no documento. Você vê a busca -sendo executada, mas ``find_all()`` retorna ``[]`` ou ``find()`` retorna ``None``. -Este é um problema comum com o analisador HTML nativo do Python que algumas -vezes pula tags que ele não entende. Novamente, a solução é -:ref:`instalar o lxml ou html5lib.<parser-installation>` - -Problemas de incompatibilidade de versões ------------------------------------------ - -* ``SyntaxError: Invalid syntax`` (on the line ``ROOT_TAG_NAME = - u'[document]'``): Causado por rodar a versão Python 2 do - Beautiful Soup no Python 3, sem converter o código. - -* ``ImportError: No module named HTMLParser`` - Causado por rodar a - versão Python 2 do Beautiful Soup no Python 3. - -* ``ImportError: No module named html.parser`` - Causado por rodar a - versão Python 3 do Beautiful Soup no Python 2. - -* ``ImportError: No module named BeautifulSoup`` - Causado por rodar - código do Beautiful Soup 3 em um sistema que não possui o BS3 - instalado. Ou por escrever código Beautiful Soup 4 sem saber que - o nome do pacote é diferente no ``bs4``. - -* ``ImportError: No module named bs4`` - Causado por rodar código Beautiful - Soup 4 em um sistema que não possui o BS4 instalado. - -.. _parsing-xml: - -Analisando um XML ------------------ - -Por padrão, o Beautiful Soup analisa documento como HTML. Para analisar um documento -como XML, passe "xml" como um segundo argumento ao construtor ``BeautifulSoup`` :: - - soup = BeautifulSoup(markup, "xml") - -Você precisará ter :ref:` lxml instalado <parser-installation>`. - -Outros problemas com analisadores ---------------------------------- - -* Se seu script funciona em um computador, mas não em outro, - ou em um ambiente virtual mas não em outro, ou fora do ambiente - virtual mas não dentro dele, provavelmente porque ambos os ambientes - possuem bibliotecas de analisadores difererentes. Por exemplo, você pode - ter desenvolvido um script em um computador que possui lxml instalado, - e então estar tentando rodá-lo no seu computador que possui apenas html5lib - instalado. Veja :ref:`Diferenças entre os interpretadores (parsers)` para entender porque isso importa, - e corrija o problema mencionando uma biblioteca específica no construtor ``BeautifulSoup``. - -* Por tags `HTML e atributos serem case-insensitive - <http://www.w3.org/TR/html5/syntax.html#syntax>`_, todos os três - parsers HTML convertem tags e atributos para lowercase. Isso é, - a marcação <TAG></TAG> é convertida para <tag></tag>. Se você quiser - preservar a formatação anterior das tags e atributos, você precisará - :ref:`analisar o documento como XML. <parsing-xml>` - -.. _misc: - -Diversos --------- - -* ``UnicodeEncodeError: 'charmap' codec can't encode character - u'\xfoo' in position bar`` (ou qualquer outro - ``UnicodeEncodeError``) - Este não é um problema do Beautiful Soup. - Este problema poderá surgir em duas situações: a primeira quando você - tentar imprimir um caractere Unicode que seu console não sabe como - exibir. (Veja `Esta página na wiki do Python - <http://wiki.python.org/moin/PrintFails>`_ para saber mais.). A segunda, - quando você está gravando um arquivo e passa um caractere Unicode que - não é suportado pelo seu codificador padrão. Neste caso, a solução mais - simples é explicitamente converter a string Unicode em UTF-8 com - ``u.encode("utf8")``. - -* ``KeyError: [attr]`` - Caused by accessing ``tag['attr']`` quando a - tag em questão não define o atributo ``attr``. Os erros mais comuns são - ``KeyError: 'href'`` e ``KeyError: - 'class'``. Use ``tag.get('attr')`` se você não tem certeza se ``attr`` está - definido, assim como você faria em um dicionário Python. - -* ``AttributeError: 'ResultSet' object has no attribute 'foo'`` - Isso - geralmente ocorre quando você espera que ``find_all()`` retorne - uma única tag ou string. Mas ``find_all()`` retorn uma _lista_ de tags - e strings--um objeto ``ResultSet``. Você precisa iterar sobre a lista e - buscar ``.foo`` para cada um. Ou, se você realmente quiser apenas um resultado, - deverá usar ``find()`` ao invés de ``find_all()``. - -* ``AttributeError: 'NoneType' object has no attribute 'foo'`` - Isso - geralmente acontece quando é chamado ``find()`` e então se tenta acessar - o atributo `.foo`` o resultado. Mas no seu caso, ``find()`` não encontra nada, - então retorna ``None`` ao invés de retornar uma tag ou uma string. Você precisa - descobrir porque ``find()`` não está retornando nada. - -Melhorando a performance ------------------------- - -O Beautiful Soup nunca será tão rápido quanto os parsers em que -ele foi construido em cima. Se o tempo de resposta se tornar crítico, -se você estiver pagando por hora de uso de um computador ou se há -qualquer outra razão para que o tempo de processamento seja mais -valioso que o tempo de programação, você deve esquecer o Beautiful Soup -e trabalhar diretamente em cima do `lxml <http://lxml.de/>`_. - -Dito isso, existem algumas coisas que você pode fazer para acelerar o -Beautiful Soup. Se você não está utilizando o lxml como seu parser, -meu conselho é que o faça :ref:`start <parser-installation>`. -O Beautiful Soup analisa documentos significativamente mais rápido -utilizando o lxml do que usando o html.parser ou html5lib. - -Você pode acelerar a detecção da codificação significativamente instalando -a biblioteca `cchardet <http://pypi.python.org/pypi/cchardet/>`_ . - -`Analisando apenas parte do documento`_ não irá lhe poupar muito tempo de -análise, mas irá poupar muita memória e fará a `busca` no documento muito -mais rápida. - -Beautiful Soup 3 -================ - -O Beautiful Soup 3 é a versão anterior e não é mais desenvolvida -ativamente. Ela atualmente faz parte da maioria das distribuições -Linux: - -:kbd:`$ apt-get install python-beautifulsoup` - -Também está publicada no PyPi como ``BeautifulSoup``.: - -:kbd:`$ easy_install BeautifulSoup` - -:kbd:`$ pip install BeautifulSoup` - -Você também pode fazer o `download de um tarball do Beautiful Soup 3.2.0 -<http://www.crummy.com/software/BeautifulSoup/bs3/download/3.x/BeautifulSoup-3.2.0.tar.gz>`_. - -Se você rodar ``easy_install beautifulsoup`` ou ``easy_install -BeautifulSoup``, mas seu código não funcionar, você instalou o Beautiful -Soup 3 por engano. Você precisa executar ``easy_install beautifulsoup4``. - -`A documentação do Beautiful Soup 3 está arquivada online -<http://www.crummy.com/software/BeautifulSoup/bs3/documentation.html>`_. - -Portabilidade de código para BS4 --------------------------------- - -A maioria dos códigos escritos em Beautiful Soup 3 irá funcionar no -Beautiful Soup 4 com uma pequena alteração. Tudo que você precisa -fazer é alterar o nome do pacote de ``BeautifulSoup`` para ``bs4``. Então:: - - from BeautifulSoup import BeautifulSoup - -deverá ser assim:: - - from bs4 import BeautifulSoup - -* Se for gerado um ``ImportError`` "No module named BeautifulSoup", o - problema é que você está tentando executar um código Beautiful Soup 3, - mas possui apenas o Beautiful Soup 4 instalado. - -* Se for gerado um ``ImportError`` "No module named bs4", o problema - é que você está tentando executar um código Beautiful Soup 4, mas - possui apenas o Beautiful Soup 3 instalado. - -Apesar do BS4 ser quase totalmente compativel com BS3, a maioria de seus -métodos foram depreciados e renomeados para atender o padrão `PEP 8 -<http://www.python.org/dev/peps/pep-0008/>`_. Existem muitas outras -renomeações e alterações, e algumas delas quebram esta compatibilidade. - -Aqui está o que você irá precisar saber para converter seu código BS3 para BS4: - -Você precisa de um interpretador (parser) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -O Beautiful Soup 3 utilizava o ``SGMLParser`` do Python, um módulo que -foi depreciado e removido no Python 3.0. O Beautiful Soup 4 utiliza o -``html.parser`` por padrão, mas você pode adicionar o lxml ou html5lib -e utilizá-los como alternativa. Veja `Instalando um interpretador (parser)`_ para -comparação. - -Como o ``html.parser`` não é o mesmo analisador que ``SGMLParser``, é possível -que o Beautiful Soup 4 retorne uma árvore de análise diferente da -gerada pelo Beautiful Soup 3 para as mesmas marcações. Se você trocar -``html.parser`` por lxml ou html5lib, você poderá descorbrir que a árvore também -mudará. Se isso acontecer, você precisará atualizar seu código para lidar com a -nova árvore. - -Nomes dos Métodos -^^^^^^^^^^^^^^^^^ - -* ``renderContents`` -> ``encode_contents`` -* ``replaceWith`` -> ``replace_with`` -* ``replaceWithChildren`` -> ``unwrap`` -* ``findAll`` -> ``find_all`` -* ``findAllNext`` -> ``find_all_next`` -* ``findAllPrevious`` -> ``find_all_previous`` -* ``findNext`` -> ``find_next`` -* ``findNextSibling`` -> ``find_next_sibling`` -* ``findNextSiblings`` -> ``find_next_siblings`` -* ``findParent`` -> ``find_parent`` -* ``findParents`` -> ``find_parents`` -* ``findPrevious`` -> ``find_previous`` -* ``findPreviousSibling`` -> ``find_previous_sibling`` -* ``findPreviousSiblings`` -> ``find_previous_siblings`` -* ``getText`` -> ``get_text`` -* ``nextSibling`` -> ``next_sibling`` -* ``previousSibling`` -> ``previous_sibling`` - -Alguns argumentos do construtor do Beautiful Soup foram renomeados pelas -mesmas razões: - -* ``BeautifulSoup(parseOnlyThese=...)`` -> ``BeautifulSoup(parse_only=...)`` -* ``BeautifulSoup(fromEncoding=...)`` -> ``BeautifulSoup(from_encoding=...)`` - -Eu renomeei um método para compatibilidade com Python 3: - -* ``Tag.has_key()`` -> ``Tag.has_attr()`` - -Eu renomeei um atributo para utilizar uma terminologia mais precisa: - -* ``Tag.isSelfClosing`` -> ``Tag.is_empty_element`` - -Eu renomeei três atributos para evitar utilizar palavras reservadas do -Python. Ao contrário das outras, estas alterações *não são compativeis com -versões anteriores.* Se você utilizar estes atributos no BS3, seu código -irá quebrar no BS4 até você corrigí-los. - -* ``UnicodeDammit.unicode`` -> ``UnicodeDammit.unicode_markup`` -* ``Tag.next`` -> ``Tag.next_element`` -* ``Tag.previous`` -> ``Tag.previous_element`` - -Geradores -^^^^^^^^^ - -Eu dei nomes aos geradores de acordo com o PEP-8 e transformei-os -em propriedades: - -* ``childGenerator()`` -> ``children`` -* ``nextGenerator()`` -> ``next_elements`` -* ``nextSiblingGenerator()`` -> ``next_siblings`` -* ``previousGenerator()`` -> ``previous_elements`` -* ``previousSiblingGenerator()`` -> ``previous_siblings`` -* ``recursiveChildGenerator()`` -> ``descendants`` -* ``parentGenerator()`` -> ``parents`` - -Então, ao invés de:: - - for parent in tag.parentGenerator(): - ... - -Você pode escrever:: - - for parent in tag.parents: - ... - -(Mas a versão antiga ainda funcionará.) - -Alguns dos geradores eram utilizados para gerar ``None`` após -finalizado e então parar. Isso era um bug. Agora os geradores -apenas param. - -Existem dois novos geradores, :ref:`.strings e -.stripped_strings <string-generators>`. ``.strings`` gera objetos -NavigableString, e ``.stripped_strings`` gera strings Python com -espaços em branco removidos. - -XML -^^^ -Não existe mais uma classe ``BeautifulStoneSoup`` para analisar XML. Para -analisar XML você deverá passar "xml" como segundo argumento ao construtor -``BeautifulSoup``. Pela mesma razão, o construtor ``BeautifulSoup`` não -reconhece mais o argumento ``isHTML``. - -A manipulação do Beautiful Soup's de tags XML vazias foi melhorada. -Anteriormente, quando você analisava um XML, deveria explicitamente -dizer quais tags seriam consideradas elementos de tag vazios. O -argumento ``selfClosingTags`` não é mais reconhecido. Ao invés disso, -o Beautiful Soup considera qualquer tag vazia como um elemento de tag vazia. -Se você adicionar uma filha a um elemento de tag vazia, ela deixará de ser vazia. - -Entidades -^^^^^^^^^ - -Uma entidade HTML ou XML de entrada é sempre convertida em -seu caractere Unicode correspondente. O Beautiful Soup 3 possuia -inúmeras maneiras redundantes de lidar com entidades, as quais foram -removidas. O construtor ``BeautifulSoup`` não reconhece mais os argumentos -``smartQuotesTo`` ou ``convertEntities``. (`Unicode, -Dammit`_ ainda possui ``smart_quotes_to``, mas seu padrão agora é converter -smart quotes em Unicode.) As constantes ``HTML_ENTITIES``, -``XML_ENTITIES``, e ``XHTML_ENTITIES`` foram removidas, desde que elas -se referiam a uma feature (transformar algumas, mas não todas as entidades -em caracteres Unicode) que não existe mais. -Se você quiser transformar caracteres Unicode novamente em entidades HTML -na saída, ao invés de transformá-las em caracteres UTF-8, você precisará -utilizar um :ref:`output formatter <output_formatters>`. - -Variados -^^^^^^^^ - -:ref:`Tag.string <.string>` agora opera recursivamente. Se a tag A -contém apenas uma tag B e nada mais, então A.string é o mesmo que -B.string. (Anteriormente era None) - -`Atributos com múltiplos valores`_ como ``class`` possuem listas de strings -como valores e não strings. Isso deverá afetar a maneira que você buscará -por classes CSS. - -Se você passar um dos métodos ``find*``, ambos :ref:`string <string>` `e` -um argumento específico de uma tag como :ref:`name <name>`, o Beautiful Soup -irá buscar por tags que atentem o seu critério de argumento específico e que -:ref:`Tag.string <.string>` atenda o valor para :ref:`string <string>`. Isso -`não` irá encontrar as strings por si. Anteriormente, Beautiful Soup ignorava -o argumento específico de uma tag e olhava apenas para as strings. - -O construtor ``BeautifulSoup`` não reconhece mais o argumento `markupMassage`. -É agora responsabilidade do parser de manipular a marcação corretamente. - -As classes raramente usadas do analisador como -``ICantBelieveItsBeautifulSoup`` e ``BeautifulSOAP`` foram removidas. -é agora decisão do analisador como manipular marcações ambiguas. - -O método ``prettify()`` agora retorna uma string Unicode, e não bytestring. diff --git a/doc/source/index.rst b/doc/source/index.rst index ac7409f..08063a5 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -3114,6 +3114,27 @@ You can speed up encoding detection significantly by installing the the document, but it can save a lot of memory, and it'll make `searching` the document much faster. +Translating this documentation +============================== + +New translations of the Beautiful Soup documentation are greatly +appreciated. Translations should be licensed under the MIT license, +just like Beautiful Soup and its English documentation are. + +There are two ways of getting your translation into the main code base +and onto the Beautiful Soup website: + +1. Create a branch of the Beautiful Soup repository, add your + translation, and propose a merge with the main branch, the same + as you would do with a proposed change to the source code. +2. Send a message to the Beautiful Soup discussion group with a link to + your translation, or attach your translation to the message. + +Use the Chinese or Brazilian Portuguese translations as your model. In +particular, please translate ``doc/source/index.rst`` file, rather +than the HTML version of the documentation. This makes it possible to +publish the documentation in a variety of formats, not just HTML. + Beautiful Soup 3 ================ |