From 64753365df3bedd60cde505db792abb20841ada4 Mon Sep 17 00:00:00 2001
From: Leonard Richardson 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. ...
+ #
+ # 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.
+ #
+ # ...
+ # The Dormouse's story Back to the homepage Back to the homepage 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. ... The Dormouse's story ", 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 final no "three sisters". Sua
+``.next_sibling`` é uma string: a conclusão da sentença
+que foi interrompida pelo início da tag .::
+
+ last_a_tag = soup.find("a", id="link3")
+ last_a_tag
+ # Tillie
+
+ last_a_tag.next_sibling
+ # '; and they lived at the bottom of a well.'
+
+Mas no ``.next_element`` da tag , o que é analisado imediatamente
+depois da tag `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 , então
+a palavra "Tillie", então fechando a tag , 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 ,
+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
+ # Tillie
+
+``.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'
+ # ... 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. ... ::
+
+ soup.find_all(has_class_but_no_id)
+ # [ The Dormouse's story Once upon a time there were... ... . Não irá encontrar as tags ,
+porque elas definem "class e "id" ao mesmo tempo. Ela não encontrará
+as tags e The Dormouse's story 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")
+ # [ 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. é uma mãe
+indireta da string e nossa busca também a encontra. Há uma tag 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 ... The Dormouse's story ... do documento foi
+encontrada, mesmo que não esteja na mesma parte da árvore que 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 Once upon a time there were three little sisters; ... The Dormouse's story que contém a tag 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 que contenha uma tag deve aparecer antes da tag 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 ... I wish I was bold. I wish I was bold. A one A one, a two
+ # A one
+ # , a two
+ #
+ # A one, a two
+ # The law firm of Dewey, Cheatem, & Howe The law firm of Dewey, Cheatem, & Howe Il a dit <<Sacré bleu!>>
+ # Il a dit <<Sacré bleu!>>
+ #
+ # Il a dit <<Sacré bleu!>>
+ #
+ # Il a dit <
+ # IL A DIT <Extremely bold
+
+Atributos
+^^^^^^^^^^
+Uma tag pode ter inúmeros atributos. A tag ````
+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
+ #
+
+ del tag['id']
+ del tag['another-attribute']
+ tag
+ #
+
+ 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('')
+ css_soup.p['class']
+ # ["body"]
+
+ css_soup = BeautifulSoup('')
+ 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('')
+ 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('No longer bold
+
+``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 = ""
+ soup = BeautifulSoup(markup)
+ comment = soup.b.string
+ type(comment)
+ # Extremely bold
+
+ del tag['class']
+ del tag['id']
+ tag
+ # Extremely bold
+
+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 = 'I linked to example.com'
+ soup = BeautifulSoup(markup)
+
+ tag = soup.a
+ tag.string = "New link text."
+ tag
+ # New link text.
+
+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("Foo")
+ soup.a.append("Bar")
+
+ soup
+ # FooBar
+ 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("Soup")
+ soup.a.extend(["'s", " ", "on"])
+
+ soup
+ # Soup's on
+ 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("")
+ tag = soup.b
+ tag.append("Hello")
+ new_string = NavigableString(" there")
+ tag.append(new_string)
+ tag
+ # Hello there.
+ 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
+ # Hello there
+ 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("")
+ original_tag = soup.b
+
+ new_tag = soup.new_tag("a", href="http://www.example.com")
+ original_tag.append(new_tag)
+ original_tag
+ #
+
+ new_tag.string = "Link text."
+ original_tag
+ # Link text.
+
+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 = 'I linked to example.com'
+ soup = BeautifulSoup(markup)
+ tag = soup.a
+
+ tag.insert(1, "but did not endorse ")
+ tag
+ # I linked to but did not endorse example.com
+ tag.contents
+ # [u'I linked to ', u'but did not endorse', example.com]
+
+``insert_before()`` e ``insert_after()``
+------------------------------------------
+
+O método ``insert_before()`` insere tags ou strings imediatamente antes de algo
+na árvore::
+
+ soup = BeautifulSoup("stop")
+ tag = soup.new_tag("i")
+ tag.string = "Don't"
+ soup.b.string.insert_before(tag)
+ soup.b
+ # Don'tstop
+
+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
+ # Don't you
")
+
+ print(soup.encode(formatter="html"))
+ #
+
+ print(soup.encode(formatter="html5"))
+ #
+
+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))
+ #
+ #
+ #
aberta. Este parser também adiciona uma tag
vazia ao documento. + +Aqui está o mesmo documento analisado com o parser HTML nativo do Python:: + + BeautifulSoup("", "html.parser") + # + +Assim como html5lib, este parser ignora a tag de fechamento . +Este parser também não realiza nenhuma tentatida de criar um HTML bem +formatado adicionando uma tag . Como lxml, ele nem se importa em +adicionar uma tag . + +Sendo o documento "" 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 = "Sacr\xe9 bleu!
+ + + ''' + + soup = BeautifulSoup(markup) + print(soup.prettify()) + # + # + # + # + # + #+ # Sacré bleu! + #
+ # + # + +Note que a tag 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")) + # + # + # + # ... + +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") + # 'Sacr\xe9 bleu!
' + + soup.p.encode("utf-8") + # 'Sacr\xc3\xa9 bleu!
' + +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"\N{SNOWMAN}" + snowman_soup = BeautifulSoup(markup) + tag = snowman_soup.b + +O caractere SNOWMAN faz parte da documentação UTF-8 (algo como +☃), mas não possui representação para este caractere em ISO-latin-1 ou +ASCII, portanto ele é convertido para "☃" para as essas codificações:: + + print(tag.encode("utf-8")) + # ☃ + + print tag.encode("latin-1") + # ☃ + + print tag.encode("ascii") + # ☃ + +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"I just \x93love\x94 Microsoft Word\x92s smart quotes
" + + UnicodeDammit(markup, ["windows-1252"], smart_quotes_to="html").unicode_markup + # u'I just “love” Microsoft Word’s smart quotes
' + + UnicodeDammit(markup, ["windows-1252"], smart_quotes_to="xml").unicode_markup + # u'I just “love” Microsoft Word’s smart quotes
' + +Você também pode converter Microsoft smart quotes para ASCII:: + + UnicodeDammit(markup, ["windows-1252"], smart_quotes_to="ascii").unicode_markup + # u'I just "love" Microsoft Word\'s smart quotes
' + +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'I just \u201clove\u201d Microsoft Word\u2019s smart quotes
' + +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 = "Paragraph 1
\nParagraph 2
" + 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 = "Paragraph 1
\nParagraph 2
" + 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 são tratadas como iguais, mesmo estando em partes +diferentes da árvore do objeto, porque ambas estão como "pizza":: + + markup = "I want pizza and more pizza!
" + 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 + #I want pizza and more pizza!
+ + +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 de um documento. É um desperdício de tempo e memória analisar +todo o documento e, posteriormente, analisar novamente apenas para buscar +as tags . Seria muito mais rápido ignorar tudo o que não for 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:`nameThe 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.
+ +...
+ """ + + print(BeautifulSoup(html_doc, "html.parser", parse_only=only_a_tags).prettify()) + # + # Elsie + # + # + # Lacie + # + # + # Tillie + # + + print(BeautifulSoup(html_doc, "html.parser", parse_only=only_tags_with_id_link2).prettify()) + # + # Lacie + # + + 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.