summaryrefslogtreecommitdiff
path: root/doc.ptbr
diff options
context:
space:
mode:
Diffstat (limited to 'doc.ptbr')
-rw-r--r--doc.ptbr/source/6.1.jpgbin0 -> 22619 bytes
-rw-r--r--doc.ptbr/source/conf.py256
-rw-r--r--doc.ptbr/source/index.rst3261
3 files changed, 3517 insertions, 0 deletions
diff --git a/doc.ptbr/source/6.1.jpg b/doc.ptbr/source/6.1.jpg
new file mode 100644
index 0000000..97014f0
--- /dev/null
+++ b/doc.ptbr/source/6.1.jpg
Binary files differ
diff --git a/doc.ptbr/source/conf.py b/doc.ptbr/source/conf.py
new file mode 100644
index 0000000..cd679b5
--- /dev/null
+++ b/doc.ptbr/source/conf.py
@@ -0,0 +1,256 @@
+# -*- coding: utf-8 -*-
+#
+# Beautiful Soup documentation build configuration file, created by
+# sphinx-quickstart on Thu Jan 26 11:22:55 2012.
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys, os
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#sys.path.insert(0, os.path.abspath('.'))
+
+# -- General configuration -----------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = []
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'Beautiful Soup'
+copyright = u'2004-2015, Leonard Richardson'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = '4'
+# The full version, including alpha/beta/rc tags.
+release = '4.4.0'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = []
+
+# The reST default role (used for this markup: `text`) to use for all documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+
+# -- Options for HTML output ---------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. See the documentation for
+# a list of builtin themes.
+html_theme = 'default'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further. For a list of options available for each theme, see the
+# documentation.
+#html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+#html_theme_path = []
+
+# The name for this set of Sphinx documents. If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar. Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+#html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+#html_domain_indices = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+#html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+#html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+#html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it. The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = None
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'BeautifulSoupdoc'
+
+
+# -- Options for LaTeX output --------------------------------------------------
+
+# The paper size ('letter' or 'a4').
+#latex_paper_size = 'letter'
+
+# The font size ('10pt', '11pt' or '12pt').
+#latex_font_size = '10pt'
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, documentclass [howto/manual]).
+latex_documents = [
+ ('index', 'BeautifulSoup.tex', u'Beautiful Soup Documentation',
+ u'Leonard Richardson', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# If true, show page references after internal links.
+#latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+#latex_show_urls = False
+
+# Additional stuff for the LaTeX preamble.
+#latex_preamble = ''
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_domain_indices = True
+
+
+# -- Options for manual page output --------------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+ ('index', 'beautifulsoup', u'Beautiful Soup Documentation',
+ [u'Leonard Richardson'], 1)
+]
+
+
+# -- Options for Epub output ---------------------------------------------------
+
+# Bibliographic Dublin Core info.
+epub_title = u'Beautiful Soup'
+epub_author = u'Leonard Richardson'
+epub_publisher = u'Leonard Richardson'
+epub_copyright = u'2012, Leonard Richardson'
+
+# The language of the text. It defaults to the language option
+# or en if the language is not set.
+#epub_language = ''
+
+# The scheme of the identifier. Typical schemes are ISBN or URL.
+#epub_scheme = ''
+
+# The unique identifier of the text. This can be a ISBN number
+# or the project homepage.
+#epub_identifier = ''
+
+# A unique identification for the text.
+#epub_uid = ''
+
+# HTML files that should be inserted before the pages created by sphinx.
+# The format is a list of tuples containing the path and title.
+#epub_pre_files = []
+
+# HTML files shat should be inserted after the pages created by sphinx.
+# The format is a list of tuples containing the path and title.
+#epub_post_files = []
+
+# A list of files that should not be packed into the epub file.
+#epub_exclude_files = []
+
+# The depth of the table of contents in toc.ncx.
+#epub_tocdepth = 3
+
+# Allow duplicate toc entries.
+#epub_tocdup = True
diff --git a/doc.ptbr/source/index.rst b/doc.ptbr/source/index.rst
new file mode 100644
index 0000000..f596d44
--- /dev/null
+++ b/doc.ptbr/source/index.rst
@@ -0,0 +1,3261 @@
+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&eacute; 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("&ldquo;Dammit!&rdquo; 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 "&amp;", "&lt;",
+e "&gt;", 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, &amp; 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&amp;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 &lt;&lt;Sacr&eacute; bleu!&gt;&gt;</p>"
+ soup = BeautifulSoup(french)
+ print(soup.prettify(formatter="minimal"))
+ # <html>
+ # <body>
+ # <p>
+ # Il a dit &lt;&lt;Sacré bleu!&gt;&gt;
+ # </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 &lt;&lt;Sacr&eacute; bleu!&gt;&gt;
+ # </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 "&#9731" para as essas codificações::
+
+ print(tag.encode("utf-8"))
+ # <b>☃</b>
+
+ print tag.encode("latin-1")
+ # <b>&#9731;</b>
+
+ print tag.encode("ascii")
+ # <b>&#9731;</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 &ldquo;love&rdquo; Microsoft Word&rsquo;s smart quotes</p>'
+
+ UnicodeDammit(markup, ["windows-1252"], smart_quotes_to="xml").unicode_markup
+ # u'<p>I just &#x201C;love&#x201D; Microsoft Word&#x2019;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.