Bela Sopa - Guia Rápido

No mundo de hoje, temos toneladas de dados / informações não estruturados (principalmente dados da web) disponíveis gratuitamente. Às vezes, os dados disponíveis gratuitamente são fáceis de ler, às vezes não. Não importa como seus dados estão disponíveis, web scraping é uma ferramenta muito útil para transformar dados não estruturados em dados estruturados que são mais fáceis de ler e analisar. Em outras palavras, uma forma de coletar, organizar e analisar essa enorme quantidade de dados é por meio de web scraping. Então, vamos primeiro entender o que é web scraping.

O que é web scraping?

A extração é simplesmente um processo de extração (de vários meios), cópia e triagem de dados.

Quando fazemos scraping ou extraímos dados ou feeds da web (como de páginas da web ou sites), isso é denominado como web scraping.

Portanto, web scraping, também conhecido como extração de dados da web ou colheita da web, é a extração de dados da web. Resumindo, o web scraping oferece aos desenvolvedores uma maneira de coletar e analisar dados da Internet.

Por que web scraping?

O web scraping fornece uma das grandes ferramentas para automatizar a maioria das coisas que um ser humano faz enquanto navega. O web scraping é usado em uma empresa de várias maneiras -

Dados para Pesquisa

O analista inteligente (como um pesquisador ou jornalista) usa o web scrapper em vez de coletar e limpar manualmente os dados dos sites.

Preços de produtos e comparação de popularidade

Atualmente, existem alguns serviços que usam scrappers da web para coletar dados de vários sites online e usá-los para comparar a popularidade e os preços dos produtos.

Monitoramento de SEO

Existem inúmeras ferramentas de SEO, como Ahrefs, Seobility, SEMrush, etc., que são usadas para análises competitivas e para extrair dados dos sites de seus clientes.

Motores de busca

Existem algumas grandes empresas de TI cujos negócios dependem exclusivamente de web scraping.

Vendas e Marketing

Os dados coletados por meio de web scraping podem ser usados ​​por profissionais de marketing para analisar diferentes nichos e concorrentes ou pelo especialista em vendas para a venda de serviços de marketing de conteúdo ou promoção de mídia social.

Por que Python para Web Scraping?

Python é uma das linguagens mais populares para web scraping, pois pode lidar com a maioria das tarefas relacionadas a crawling com muita facilidade.

Abaixo estão alguns dos pontos sobre por que escolher o python para web scraping:

Fácil de usar

Como a maioria dos desenvolvedores concorda que python é muito fácil de codificar. Não precisamos usar chaves “{}” ou ponto e vírgula “;” em qualquer lugar, o que o torna mais legível e fácil de usar durante o desenvolvimento de web scrapers.

Grande suporte de biblioteca

Python fornece um grande conjunto de bibliotecas para diferentes requisitos, portanto, é apropriado para web scraping, bem como para visualização de dados, aprendizado de máquina etc.

Sintaxe facilmente explicável

Python é uma linguagem de programação muito legível, pois a sintaxe do Python é fácil de entender. Python é muito expressivo e a indentação de código ajuda os usuários a diferenciar diferentes blocos ou concertos no código.

Linguagem digitada dinamicamente

Python é uma linguagem tipada dinamicamente, o que significa que os dados atribuídos a uma variável informam que tipo de variável é. Isso economiza muito tempo e torna o trabalho mais rápido.

Enorme comunidade

A comunidade Python é enorme, o que ajuda você onde quer que você pare enquanto escreve o código.

Introdução à bela sopa

The Beautiful Soup é uma biblioteca python que leva o nome de um poema de Lewis Carroll de mesmo nome em “As Aventuras de Alice no País das Maravilhas”. Beautiful Soup é um pacote python e como o nome sugere, analisa os dados indesejados e ajuda a organizar e formatar os dados da web bagunçados corrigindo HTML incorreto e apresentando-nos em estruturas XML facilmente percorríveis.

Resumindo, Beautiful Soup é um pacote python que nos permite extrair dados de documentos HTML e XML.

Como BeautifulSoup não é uma biblioteca python padrão, precisamos instalá-la primeiro. Vamos instalar a biblioteca BeautifulSoup 4 (também conhecida como BS4), que é a mais recente.

Para isolar nosso ambiente de trabalho para não atrapalhar a configuração existente, vamos primeiro criar um ambiente virtual.

Criação de um ambiente virtual (opcional)

Um ambiente virtual nos permite criar uma cópia de trabalho isolada do python para um projeto específico sem afetar a configuração externa.

A melhor maneira de instalar qualquer máquina de pacote python é usando pip, no entanto, se o pip ainda não estiver instalado (você pode verificar usando - “pip –version” no seu prompt de comando ou shell), você pode instalar dando o comando abaixo -

Ambiente Linux

$sudo apt-get install python-pip

Ambiente Windows

Para instalar o pip no Windows, faça o seguinte -

  • Baixe o get-pip.py em https://bootstrap.pypa.io/get-pip.py ou do github para o seu computador.

  • Abra o prompt de comando e navegue até a pasta que contém o arquivo get-pip.py.

  • Execute o seguinte comando -

>python get-pip.py

É isso, o pip agora está instalado em sua máquina Windows.

Você pode verificar o pip instalado executando o comando abaixo -

>pip --version
pip 19.2.3 from c:\users\yadur\appdata\local\programs\python\python37\lib\site-packages\pip (python 3.7)

Instalando ambiente virtual

Execute o comando abaixo em seu prompt de comando -

>pip install virtualenv

Depois de correr, você verá a imagem abaixo -

O comando abaixo criará um ambiente virtual (“myEnv”) em seu diretório atual -

>virtualenv myEnv

Captura de tela

Para ativar seu ambiente virtual, execute o seguinte comando -

>myEnv\Scripts\activate

Na imagem acima, você pode ver que temos “myEnv” como prefixo que nos diz que estamos no ambiente virtual “myEnv”.

Para sair do ambiente virtual, execute deactivate.

(myEnv) C:\Users\yadur>deactivate
C:\Users\yadur>

Como nosso ambiente virtual está pronto, vamos instalar o beautifulsoup.

Instalando BeautifulSoup

Como BeautifulSoup não é uma biblioteca padrão, precisamos instalá-la. Vamos usar o pacote BeautifulSoup 4 (conhecido como bs4).

Máquina Linux

Para instalar o bs4 no Debian ou Ubuntu Linux usando o gerenciador de pacotes do sistema, execute o comando abaixo -

$sudo apt-get install python-bs4 (for python 2.x)
$sudo apt-get install python3-bs4 (for python 3.x)

Você pode instalar o bs4 usando easy_install ou pip (no caso de você encontrar problemas na instalação usando o gerenciador de sistema).

$easy_install beautifulsoup4
$pip install beautifulsoup4

(Você pode precisar usar easy_install3 ou pip3 respectivamente se estiver usando python3)

Máquina Windows

Instalar o beautifulsoup4 no windows é muito simples, principalmente se você já tem o pip instalado.

>pip install beautifulsoup4

Então agora o beautifulsoup4 está instalado em nossa máquina. Vamos falar sobre alguns problemas encontrados após a instalação.

Problemas após a instalação

Em máquinas com Windows, você pode encontrar um erro de versão incorreta sendo instalada principalmente por meio de -

  • erro: ImportError “No module named HTMLParser”, então você deve executar a versão python 2 do código em Python 3.

  • erro: ImportError “No module named html.parser” erro, então você deve estar executando a versão Python 3 do código em Python 2.

A melhor maneira de escapar das duas situações acima é reinstalar o BeautifulSoup novamente, removendo completamente a instalação existente.

Se você conseguir o SyntaxError “Invalid syntax” na linha ROOT_TAG_NAME = u '[document]', então você precisa converter o código python 2 para python 3, apenas instalando o pacote -

$ python3 setup.py install

ou executando manualmente o script de conversão 2 para 3 do python no diretório bs4 -

$ 2to3-3.2 -w bs4

Instalando um analisador

Por padrão, Beautiful Soup suporta o analisador HTML incluído na biblioteca padrão do Python, no entanto, também oferece suporte a muitos analisadores python externos, como analisador lxml ou analisador html5lib.

Para instalar o analisador lxml ou html5lib, use o comando -

Máquina Linux

$apt-get install python-lxml
$apt-get insall python-html5lib

Máquina Windows

$pip install lxml
$pip install html5lib

Geralmente, os usuários usam lxml para velocidade e é recomendado usar o analisador lxml ou html5lib se você estiver usando uma versão mais antiga do python 2 (antes da versão 2.7.3) ou python 3 (antes da versão 3.2.2), pois o analisador HTML integrado do python é não é muito bom em lidar com versões anteriores.

Preparando uma bela sopa

É hora de testar nosso pacote Beautiful Soup em uma das páginas html (levando a página da web - https://www.tutorialspoint.com/index.htm, você pode escolher qualquer outra página da web que desejar) e extrair algumas informações dela.

No código abaixo, estamos tentando extrair o título da página da web -

from bs4 import BeautifulSoup
import requests
url = "https://www.tutorialspoint.com/index.htm"
req = requests.get(url)
soup = BeautifulSoup(req.text, "html.parser")
print(soup.title)

Resultado

<title>H2O, Colab, Theano, Flutter, KNime, Mean.js, Weka, Solidity, Org.Json, AWS QuickSight, JSON.Simple, Jackson Annotations, Passay, Boon, MuleSoft, Nagios, Matplotlib, Java NIO, PyTorch, SLF4J, Parallax Scrolling, Java Cryptography</title>

Uma tarefa comum é extrair todos os URLs de uma página da web. Para isso, só precisamos adicionar a linha de código abaixo -

for link in soup.find_all('a'):
print(link.get('href'))

Resultado

https://www.tutorialspoint.com/index.htm
https://www.tutorialspoint.com/about/about_careers.htm
https://www.tutorialspoint.com/questions/index.php
https://www.tutorialspoint.com/online_dev_tools.htm
https://www.tutorialspoint.com/codingground.htm
https://www.tutorialspoint.com/current_affairs.htm
https://www.tutorialspoint.com/upsc_ias_exams.htm
https://www.tutorialspoint.com/tutor_connect/index.php
https://www.tutorialspoint.com/whiteboard.htm
https://www.tutorialspoint.com/netmeeting.php
https://www.tutorialspoint.com/index.htm
https://www.tutorialspoint.com/tutorialslibrary.htm
https://www.tutorialspoint.com/videotutorials/index.php
https://store.tutorialspoint.com
https://www.tutorialspoint.com/gate_exams_tutorials.htm
https://www.tutorialspoint.com/html_online_training/index.asp
https://www.tutorialspoint.com/css_online_training/index.asp
https://www.tutorialspoint.com/3d_animation_online_training/index.asp
https://www.tutorialspoint.com/swift_4_online_training/index.asp
https://www.tutorialspoint.com/blockchain_online_training/index.asp
https://www.tutorialspoint.com/reactjs_online_training/index.asp
https://www.tutorix.com
https://www.tutorialspoint.com/videotutorials/top-courses.php
https://www.tutorialspoint.com/the_full_stack_web_development/index.asp
….
….
https://www.tutorialspoint.com/online_dev_tools.htm
https://www.tutorialspoint.com/free_web_graphics.htm
https://www.tutorialspoint.com/online_file_conversion.htm
https://www.tutorialspoint.com/netmeeting.php
https://www.tutorialspoint.com/free_online_whiteboard.htm
http://www.tutorialspoint.com
https://www.facebook.com/tutorialspointindia
https://plus.google.com/u/0/+tutorialspoint
http://www.twitter.com/tutorialspoint
http://www.linkedin.com/company/tutorialspoint
https://www.youtube.com/channel/UCVLbzhxVTiTLiVKeGV7WEBg
https://www.tutorialspoint.com/index.htm
/about/about_privacy.htm#cookies
/about/faq.htm
/about/about_helping.htm
/about/contact_us.htm

Da mesma forma, podemos extrair informações úteis usando beautifulsoup4.

Agora vamos entender mais sobre “sopa” no exemplo acima.

No exemplo de código anterior, analisamos o documento por meio de um belo construtor usando um método de string. Outra maneira é passar o documento por meio de filehandle aberto.

from bs4 import BeautifulSoup
with open("example.html") as fp:
   soup = BeautifulSoup(fp)
soup = BeautifulSoup("<html>data</html>")

Primeiro, o documento é convertido em Unicode e as entidades HTML são convertidas em caracteres Unicode: </p>

import bs4
html = '''<b>tutorialspoint</b>, <i>&web scraping &data science;</i>'''
soup = bs4.BeautifulSoup(html, 'lxml')
print(soup)

Resultado

<html><body><b>tutorialspoint</b>, <i>&web scraping &data science;</i></body></html>

BeautifulSoup então analisa os dados usando um analisador HTML ou você explicitamente diz a ele para analisar usando um analisador XML.

Estrutura da árvore HTML

Antes de examinarmos os diferentes componentes de uma página HTML, vamos primeiro entender a estrutura da árvore HTML.

O elemento raiz na árvore do documento é o html, que pode ter pais, filhos e irmãos e isso é determinado por sua posição na estrutura da árvore. Para mover-se entre os elementos, atributos e texto HTML, você deve mover-se entre os nós da estrutura em árvore.

Suponhamos que a página da web seja conforme mostrado abaixo -

Que se traduz em um documento html da seguinte maneira -

<html><head><title>TutorialsPoint</title></head><h1>Tutorialspoint Online Library</h1><p<<b>It's all Free</b></p></body></html>

O que significa simplesmente que, para o documento html acima, temos uma estrutura de árvore html da seguinte forma -

Quando passamos um documento ou string html para um construtor beautifulsoup, beautifulsoup basicamente converte uma página html complexa em diferentes objetos python. Abaixo, vamos discutir quatro tipos principais de objetos:

  • Tag

  • NavigableString

  • BeautifulSoup

  • Comments

Objetos de Tag

Uma tag HTML é usada para definir vários tipos de conteúdo. Um objeto de tag no BeautifulSoup corresponde a uma tag HTML ou XML na página ou documento real.

>>> from bs4 import BeautifulSoup
>>> soup = BeautifulSoup('<b class="boldest">TutorialsPoint</b>')
>>> tag = soup.html
>>> type(tag)
<class 'bs4.element.Tag'>

As tags contêm muitos atributos e métodos e dois recursos importantes de uma tag são seu nome e atributos.

Nome (tag.name)

Cada tag contém um nome e pode ser acessada através de '.name' como sufixo. tag.name retornará o tipo de tag que é.

>>> tag.name
'html'

Porém, se alterarmos o nome da tag, o mesmo será refletido na marcação HTML gerada pelo BeautifulSoup.

>>> tag.name = "Strong"
>>> tag
<Strong><body><b class="boldest">TutorialsPoint</b></body></Strong>
>>> tag.name
'Strong'

Atributos (tag.attrs)

Um objeto de tag pode ter qualquer número de atributos. A tag <b class = ”boldest”> possui um atributo 'class' cujo valor é “boldest”. Tudo o que NÃO é tag é basicamente um atributo e deve conter um valor. Você pode acessar os atributos acessando as chaves (como acessar “classe” no exemplo acima) ou acessando diretamente por meio de “.attrs”

>>> tutorialsP = BeautifulSoup("<div class='tutorialsP'></div>",'lxml')
>>> tag2 = tutorialsP.div
>>> tag2['class']
['tutorialsP']

Podemos fazer todo tipo de modificação nos atributos de nossa tag (adicionar / remover / modificar).

>>> tag2['class'] = 'Online-Learning'
>>> tag2['style'] = '2007'
>>>
>>> tag2
<div class="Online-Learning" style="2007"></div>
>>> del tag2['style']
>>> tag2
<div class="Online-Learning"></div>
>>> del tag['class']
>>> tag
<b SecondAttribute="2">TutorialsPoint</b>
>>>
>>> del tag['SecondAttribute']
>>> tag
</b>
>>> tag2['class']
'Online-Learning'
>>> tag2['style']
KeyError: 'style'

Atributos com vários valores

Alguns dos atributos HTML5 podem ter vários valores. Mais comumente usado é o atributo de classe, que pode ter vários valores CSS. Outros incluem 'rel', 'rev', 'headers', 'accesskey' e 'accept-charset'. Os atributos de múltiplos valores em uma sopa bonita são mostrados como uma lista.

>>> from bs4 import BeautifulSoup
>>>
>>> css_soup = BeautifulSoup('<p class="body"></p>')
>>> css_soup.p['class']
['body']
>>>
>>> css_soup = BeautifulSoup('<p class="body bold"></p>')
>>> css_soup.p['class']
['body', 'bold']

No entanto, se qualquer atributo contiver mais de um valor, mas não for atributos com vários valores por qualquer versão do padrão HTML, a sopa bonita deixará o atributo sozinho -

>>> id_soup = BeautifulSoup('<p id="body bold"></p>')
>>> id_soup.p['id']
'body bold'
>>> type(id_soup.p['id'])
<class 'str'>

Você pode consolidar vários valores de atributos se transformar uma tag em uma string.

>>> rel_soup = BeautifulSoup("<p> tutorialspoint Main <a rel='Index'> Page</a></p>")
>>> rel_soup.a['rel']
['Index']
>>> rel_soup.a['rel'] = ['Index', ' Online Library, Its all Free']
>>> print(rel_soup.p)
<p> tutorialspoint Main <a rel="Index Online Library, Its all Free"> Page</a></p>

Usando 'get_attribute_list', você obtém um valor que é sempre uma lista, string, independentemente de ser um valor múltiplo ou não.

id_soup.p.get_attribute_list(‘id’)

No entanto, se você analisar o documento como 'xml', não haverá atributos com vários valores -

>>> xml_soup = BeautifulSoup('<p class="body bold"></p>', 'xml')
>>> xml_soup.p['class']
'body bold'

NavigableString

O objeto navigablestring é usado para representar o conteúdo de uma tag. Para acessar o conteúdo, use “.string” com tag.

>>> from bs4 import BeautifulSoup
>>> soup = BeautifulSoup("<h2 id='message'>Hello, Tutorialspoint!</h2>")
>>>
>>> soup.string
'Hello, Tutorialspoint!'
>>> type(soup.string)
>

Você pode substituir a string por outra string, mas não pode editar a string existente.

>>> soup = BeautifulSoup("<h2 id='message'>Hello, Tutorialspoint!</h2>")
>>> soup.string.replace_with("Online Learning!")
'Hello, Tutorialspoint!'
>>> soup.string
'Online Learning!'
>>> soup
<html><body><h2 id="message">Online Learning!</h2></body></html>

BeautifulSoup

BeautifulSoup é o objeto criado quando tentamos extrair um recurso da web. Portanto, é o documento completo que estamos tentando raspar. Na maioria das vezes, é um objeto de tag tratado.

>>> from bs4 import BeautifulSoup
>>> soup = BeautifulSoup("<h2 id='message'>Hello, Tutorialspoint!</h2>")
>>> type(soup)
<class 'bs4.BeautifulSoup'>
>>> soup.name
'[document]'

Comentários

O objeto de comentário ilustra a parte do comentário do documento da web. É apenas um tipo especial de NavigableString.

>>> soup = BeautifulSoup('<p><!-- Everything inside it is COMMENTS --></p>')
>>> comment = soup.p.string
>>> type(comment)
<class 'bs4.element.Comment'>
>>> type(comment)
<class 'bs4.element.Comment'>
>>> print(soup.p.prettify())
<p>
<!-- Everything inside it is COMMENTS -->
</p>

Objetos NavigableString

Os objetos navigablestring são usados ​​para representar texto dentro de tags, em vez das próprias tags.

Neste capítulo, discutiremos sobre como navegar por tags.

Abaixo está o nosso documento html -

>>> html_doc = """
<html><head><title>Tutorials Point</title></head>
<body>
<p class="title"><b>The Biggest Online Tutorials Library, It's all Free</b></p>
<p class="prog">Top 5 most used Programming Languages are:
<a href="https://www.tutorialspoint.com/java/java_overview.htm" class="prog" id="link1">Java</a>,
<a href="https://www.tutorialspoint.com/cprogramming/index.htm" class="prog" id="link2">C</a>,
<a href="https://www.tutorialspoint.com/python/index.htm" class="prog" id="link3">Python</a>,
<a href="https://www.tutorialspoint.com/javascript/javascript_overview.htm" class="prog" id="link4">JavaScript</a> and
<a href="https://www.tutorialspoint.com/ruby/index.htm" class="prog" id="link5">C</a>;
as per online survey.</p>
<p class="prog">Programming Languages</p>
"""
>>>
>>> from bs4 import BeautifulSoup
>>> soup = BeautifulSoup(html_doc, 'html.parser')
>>>

Com base no documento acima, tentaremos passar de uma parte do documento para outra.

Indo para baixo

Uma das partes importantes do elemento em qualquer parte do documento HTML são as tags, que podem conter outras tags / strings (filhos das tags). Beautiful Soup fornece diferentes maneiras de navegar e iterar os filhos da tag.

Navegando usando nomes de tag

A maneira mais fácil de pesquisar uma árvore de análise é pesquisar a marca por seu nome. Se você quiser a tag <head>, use soup.head -

>>> soup.head
<head>&t;title>Tutorials Point</title></head>
>>> soup.title
<title>Tutorials Point</title>

Para obter uma tag específica (como a primeira <b> tag) na tag <body>.

>>> soup.body.b
<b>The Biggest Online Tutorials Library, It's all Free</b>

Usar um nome de tag como um atributo fornecerá apenas a primeira tag com esse nome -

>>> soup.a
<a class="prog" href="https://www.tutorialspoint.com/java/java_overview.htm" id="link1">Java</a>

Para obter todos os atributos da tag, você pode usar o método find_all () -

>>> soup.find_all("a")
[<a class="prog" href="https://www.tutorialspoint.com/java/java_overview.htm" id="link1">Java</a>, <a class="prog" href="https://www.tutorialspoint.com/cprogramming/index.htm" id="link2">C</a>, <a class="prog" href="https://www.tutorialspoint.com/python/index.htm" id="link3">Python</a>, <a class="prog" href="https://www.tutorialspoint.com/javascript/javascript_overview.htm" id="link4">JavaScript</a>, <a class="prog" href="https://www.tutorialspoint.com/ruby/index.htm" id="link5">C</a>]>>> soup.find_all("a")
[<a class="prog" href="https://www.tutorialspoint.com/java/java_overview.htm" id="link1">Java</a>, <a class="prog" href="https://www.tutorialspoint.com/cprogramming/index.htm" id="link2">C</a>, <a class="prog" href="https://www.tutorialspoint.com/python/index.htm" id="link3">Python</a>, <a class="prog" href="https://www.tutorialspoint.com/javascript/javascript_overview.htm" id="link4">JavaScript</a>, <a class="prog" href="https://www.tutorialspoint.com/ruby/index.htm" id="link5">C</a>]

.contents e .children

Podemos pesquisar os filhos da tag em uma lista por seus .contents -

>>> head_tag = soup.head
>>> head_tag
<head><title>Tutorials Point</title></head>
>>> Htag = soup.head
>>> Htag
<head><title>Tutorials Point</title></head>
>>>
>>> Htag.contents
[<title>Tutorials Point</title>
>>>
>>> Ttag = head_tag.contents[0]
>>> Ttag
<title>Tutorials Point</title>
>>> Ttag.contents
['Tutorials Point']

O próprio objeto BeautifulSoup tem filhos. Nesse caso, a tag <html> é filha do objeto BeautifulSoup -

>>> len(soup.contents)
2
>>> soup.contents[1].name
'html'

Uma string não tem .contents, porque não pode conter nada -

>>> text = Ttag.contents[0]
>>> text.contents
self.__class__.__name__, attr))
AttributeError: 'NavigableString' object has no attribute 'contents'

Em vez de obtê-los como uma lista, use o gerador .children para acessar os filhos da tag -

>>> for child in Ttag.children:
print(child)
Tutorials Point

.descendants

O atributo .descendants permite que você itere sobre todos os filhos de uma tag, recursivamente -

seus filhos diretos e os filhos de seus filhos diretos e assim por diante -

>>> for child in Htag.descendants:
print(child)
<title>Tutorials Point</title>
Tutorials Point

A tag <head> tem apenas um filho, mas tem dois descendentes: a tag <title> e a criança da tag <title>. O objeto beautifulsoup tem apenas um filho direto (a tag <html>), mas tem muitos descendentes -

>>> len(list(soup.children))
2
>>> len(list(soup.descendants))
33

.corda

Se a tag tiver apenas um filho e esse filho for um NavigableString, o filho será disponibilizado como .string -

>>> Ttag.string
'Tutorials Point'

Se o único filho de uma tag for outra tag e essa tag tiver um .string, a tag pai será considerada como tendo o mesmo .string que seu filho -

>>> Htag.contents
[<title>Tutorials Point</title>]
>>>
>>> Htag.string
'Tutorials Point'

No entanto, se uma tag contém mais de uma coisa, então não está claro a que .string deve se referir, então .string é definido como Nenhum -

>>> print(soup.html.string)
None

.strings e stripped_strings

Se houver mais de uma coisa dentro de uma tag, você ainda pode olhar apenas para as strings. Use o gerador .strings -

>>> for string in soup.strings:
print(repr(string))
'\n'
'Tutorials Point'
'\n'
'\n'
"The Biggest Online Tutorials Library, It's all Free"
'\n'
'Top 5 most used Programming Languages are: \n'
'Java'
',\n'
'C'
',\n'
'Python'
',\n'
'JavaScript'
' and\n'
'C'
';\n \nas per online survey.'
'\n'
'Programming Languages'
'\n'

Para remover espaços em branco extras, use o gerador .stripped_strings -

>>> for string in soup.stripped_strings:
print(repr(string))
'Tutorials Point'
"The Biggest Online Tutorials Library, It's all Free"
'Top 5 most used Programming Languages are:'
'Java'
','
'C'
','
'Python'
','
'JavaScript'
'and'
'C'
';\n \nas per online survey.'
'Programming Languages'

Subindo

Em uma analogia da "árvore genealógica", cada tag e cada string tem um pai: a tag que o contém:

.parent

Para acessar o elemento pai do elemento, use o atributo .parent.

>>> Ttag = soup.title
>>> Ttag
<title>Tutorials Point</title>
>>> Ttag.parent
<head>title>Tutorials Point</title></head>

Em nosso html_doc, a string de título em si tem um pai: a tag <title> que a contém−

>>> Ttag.string.parent
<title>Tutorials Point</title>

O pai de uma tag de nível superior como <html> é o próprio objeto Beautifulsoup -

>>> htmltag = soup.html
>>> type(htmltag.parent)
<class 'bs4.BeautifulSoup'>

O .parent de um objeto Beautifulsoup é definido como Nenhum -

>>> print(soup.parent)
None

.pais

Para iterar sobre todos os elementos pais, use o atributo .parents.

>>> link = soup.a
>>> link
<a class="prog" href="https://www.tutorialspoint.com/java/java_overview.htm" id="link1">Java</a>
>>>
>>> for parent in link.parents:
if parent is None:
print(parent)
else:
print(parent.name)
p
body
html
[document]

Indo de lado

Abaixo está um documento simples -

>>> sibling_soup = BeautifulSoup("<a><b>TutorialsPoint</b><c><strong>The Biggest Online Tutorials Library, It's all Free</strong></b></a>")
>>> print(sibling_soup.prettify())
<html>
<body>
   <a>
      <b>
         TutorialsPoint
      </b>
      <c>
         <strong>
            The Biggest Online Tutorials Library, It's all Free
         </strong>
      </c>
   </a>
</body>
</html>

No documento acima, as tags <b> e <c> estão no mesmo nível e são filhas da mesma tag. Ambas as tags <b> e <c> são irmãs.

.next_sibling e .previous_sibling

Use .next_sibling e .previous_sibling para navegar entre os elementos da página que estão no mesmo nível da árvore de análise:

>>> sibling_soup.b.next_sibling
<c><strong>The Biggest Online Tutorials Library, It's all Free</strong></c>
>>>
>>> sibling_soup.c.previous_sibling
<b>TutorialsPoint</b>

A tag <b> tem um .next_sibling mas não .previous_sibling, pois não há nada antes da tag <b> no mesmo nível da árvore, mesmo caso é com a tag <c>.

>>> print(sibling_soup.b.previous_sibling)
None
>>> print(sibling_soup.c.next_sibling)
None

As duas strings não são irmãs, pois não têm o mesmo pai.

>>> sibling_soup.b.string
'TutorialsPoint'
>>>
>>> print(sibling_soup.b.string.next_sibling)
None

.next_siblings e .previous_siblings

Para iterar os irmãos de uma tag, use .next_siblings e .previous_siblings.

>>> for sibling in soup.a.next_siblings:
print(repr(sibling))
',\n'
<a class="prog" href="https://www.tutorialspoint.com/cprogramming/index.htm" id="link2">C</a>
',\n'
>a class="prog" href="https://www.tutorialspoint.com/python/index.htm" id="link3">Python</a>
',\n'
<a class="prog" href="https://www.tutorialspoint.com/javascript/javascript_overview.htm" id="link4">JavaScript</a>
' and\n'
<a class="prog" href="https://www.tutorialspoint.com/ruby/index.htm"
id="link5">C</a>
';\n \nas per online survey.'
>>> for sibling in soup.find(id="link3").previous_siblings:
print(repr(sibling))
',\n'
<a class="prog" href="https://www.tutorialspoint.com/cprogramming/index.htm" id="link2">C</a>
',\n'
<a class="prog" href="https://www.tutorialspoint.com/java/java_overview.htm" id="link1">Java</a>
'Top 5 most used Programming Languages are: \n'

Indo e voltando

Agora, vamos voltar às duas primeiras linhas em nosso exemplo “html_doc” anterior -

&t;html><head><title>Tutorials Point</title></head>
<body>
<h4 class="tagLine"><b>The Biggest Online Tutorials Library, It's all Free</b></h4>

Um analisador HTML pega a string de caracteres acima e a transforma em uma série de eventos como “abrir uma tag <html>”, “abrir uma tag <head>”, “abrir a tag <title>”, “adicionar uma string”, “Feche a tag </title>”, “feche a tag </head>”, “abra uma tag <h4>” e assim por diante. BeautifulSoup oferece diferentes métodos para reconstruir a análise inicial do documento.

.next_element e .previous_element

O atributo .next_element de uma tag ou string aponta para tudo o que foi analisado imediatamente depois. Às vezes, é semelhante a .next_sibling, mas não é totalmente igual. Abaixo está a tag <a> final em nosso documento de exemplo “html_doc”.

>>> last_a_tag = soup.find("a", id="link5")
>>> last_a_tag
<a class="prog" href="https://www.tutorialspoint.com/ruby/index.htm" id="link5">C</a>
>>> last_a_tag.next_sibling
';\n \nas per online survey.'

No entanto, o .next_element dessa tag <a>, o que foi analisado imediatamente após a tag <a>, não é o resto da frase: é a palavra “C”:

>>> last_a_tag.next_element
'C'

O comportamento acima ocorre porque na marcação original, a letra “C” apareceu antes do ponto e vírgula. O analisador encontrou uma marca <a>, depois a letra “C”, depois a marca de fechamento </a>, depois o ponto-e-vírgula e o resto da frase. O ponto-e-vírgula está no mesmo nível da tag <a>, mas a letra “C” foi encontrada primeiro.

O atributo .previous_element é exatamente o oposto de .next_element. Ele aponta para qualquer elemento analisado imediatamente antes deste.

>>> last_a_tag.previous_element
' and\n'
>>>
>>> last_a_tag.previous_element.next_element
<a class="prog" href="https://www.tutorialspoint.com/ruby/index.htm" id="link5">C</a>

.next_elements e .previous_elements

Usamos esses iteradores para avançar e voltar para um elemento.

>>> for element in last_a_tag.next_e lements:
print(repr(element))
'C'
';\n \nas per online survey.'
'\n'
<p class="prog">Programming Languages</p>
'Programming Languages'
'\n'

Existem muitos métodos do Beautifulsoup, que nos permitem pesquisar uma árvore de análise. Os dois métodos mais comuns e usados ​​são find () e find_all ().

Antes de falar sobre find () e find_all (), vamos ver alguns exemplos de diferentes filtros que você pode passar para esses métodos.

Tipos de Filtros

Temos diferentes filtros que podemos passar para esses métodos e a compreensão desses filtros é crucial, pois esses filtros são usados ​​repetidamente, em toda a API de pesquisa. Podemos usar esses filtros com base no nome da tag, em seus atributos, no texto de uma string ou em uma combinação desses.

Uma linha

Um dos tipos mais simples de filtro é uma string. Passar uma string para o método de pesquisa e Beautifulsoup realizará uma correspondência com aquela string exata.

O código abaixo encontrará todas as tags <p> no documento -

>>> markup = BeautifulSoup('<p>Top Three</p><p><pre>Programming Languages are:</pre></p><p><b>Java, Python, Cplusplus</b></p>')
>>> markup.find_all('p')
[<p>Top Three</p>, <p></p>, <p><b>Java, Python, Cplusplus</b></p>]

Expressão regular

Você pode encontrar todas as tags começando com uma determinada string / tag. Antes disso, precisamos importar o módulo re para usar a expressão regular.

>>> import re
>>> markup = BeautifulSoup('<p>Top Three</p><p><pre>Programming Languages are:</pre></p><p><b>Java, Python, Cplusplus</b></p>')
>>>
>>> markup.find_all(re.compile('^p'))
[<p>Top Three</p>, <p></p>, <pre>Programming Languages are:</pre>, <p><b>Java, Python, Cplusplus</b></p>]

Lista

Você pode passar várias tags para localizar, fornecendo uma lista. O código abaixo encontra todas as tags <b> e <pre> -

>>> markup.find_all(['pre', 'b'])
[<pre>Programming Languages are:</pre>, <b>Java, Python, Cplusplus</b>]

Verdadeiro

True retornará todas as tags que puder encontrar, mas nenhuma string por conta própria -

>>> markup.find_all(True)
[<html><body><p>Top Three</p><p></p><pre>Programming Languages are:</pre>
<p><b>Java, Python, Cplusplus</b> </p> </body></html>, 
<body><p>Top Three</p><p></p><pre> Programming Languages are:</pre><p><b>Java, Python, Cplusplus</b></p>
</body>, 
<p>Top Three</p>, <p></p>, <pre>Programming Languages are:</pre>, <p><b>Java, Python, Cplusplus</b></p>, <b>Java, Python, Cplusplus</b>]

Para retornar apenas as marcas da sopa acima -

>>> for tag in markup.find_all(True):
(tag.name)
'html'
'body'
'p'
'p'
'pre'
'p'
'b'

encontrar tudo()

Você pode usar find_all para extrair todas as ocorrências de uma tag específica da resposta da página como -

Sintaxe

find_all(name, attrs, recursive, string, limit, **kwargs)

Vamos extrair alguns dados interessantes do IMDB - “Filmes com melhor classificação” de todos os tempos.

>>> url="https://www.imdb.com/chart/top/?ref_=nv_mv_250"
>>> content = requests.get(url)
>>> soup = BeautifulSoup(content.text, 'html.parser')
#Extract title Page
>>> print(soup.find('title'))
<title>IMDb Top 250 - IMDb</title>

#Extracting main heading
>>> for heading in soup.find_all('h1'):
   print(heading.text)
Top Rated Movies

#Extracting sub-heading
>>> for heading in soup.find_all('h3'):
   print(heading.text)
   
IMDb Charts
You Have Seen
   IMDb Charts
   Top India Charts
Top Rated Movies by Genre
Recently Viewed

Acima, podemos ver que find_all nos dará todos os itens que correspondem aos critérios de pesquisa que definimos. Todos os filtros que podemos usar com find_all () podem ser usados ​​com find () e outros métodos de pesquisa também como find_parents () ou find_siblings ().

encontrar()

Como vimos acima, find_all () é usado para escanear todo o documento para encontrar todo o conteúdo, mas algo, o requisito é encontrar apenas um resultado. Se você sabe que o documento contém apenas uma tag <body>, é perda de tempo pesquisar o documento inteiro. Uma maneira é chamar find_all () com limit = 1 toda vez ou podemos usar o método find () para fazer o mesmo -

Sintaxe

find(name, attrs, recursive, string, **kwargs)

Portanto, a seguir, dois métodos diferentes fornecem a mesma saída -

>>> soup.find_all('title',limit=1)
[<title>IMDb Top 250 - IMDb</title>]
>>>
>>> soup.find('title')
<title>IMDb Top 250 - IMDb</title>

Nas saídas acima, podemos ver que o método find_all () retorna uma lista contendo um único item, enquanto o método find () retorna um único resultado.

Outra diferença entre os métodos find () e find_all () é -

>>> soup.find_all('h2')
[]
>>>
>>> soup.find('h2')

Se o método soup.find_all () não puder encontrar nada, ele retornará uma lista vazia enquanto find () retornará Nenhum.

find_parents () e find_parent ()

Ao contrário dos métodos find_all () e find () que percorrem a árvore, observando os descendentes da tag, os métodos find_parents () e find_parents () fazem o oposto, eles percorrem a árvore para cima e olham para os pais de uma tag (ou string).

Sintaxe

find_parents(name, attrs, string, limit, **kwargs)
find_parent(name, attrs, string, **kwargs)

>>> a_string = soup.find(string="The Godfather")
>>> a_string
'The Godfather'
>>> a_string.find_parents('a')
[<a href="/title/tt0068646/" title="Francis Ford Coppola (dir.), Marlon Brando, Al Pacino">The Godfather</a>]
>>> a_string.find_parent('a')
<a href="/title/tt0068646/" title="Francis Ford Coppola (dir.), Marlon Brando, Al Pacino">The Godfather</a>
>>> a_string.find_parent('tr')
<tr>

<td class="posterColumn">
<span data-value="2" name="rk"></span>
<span data-value="9.149038526210072" name="ir"></span>
<span data-value="6.93792E10" name="us"></span>
<span data-value="1485540" name="nv"></span>
<span data-value="-1.850961473789928" name="ur"></span>
<a href="/title/tt0068646/"> <img alt="The Godfather" height="67" src="https://m.media-amazon.com/images/M/MV5BM2MyNjYxNmUtYTAwNi00MTYxLWJmNWYtYzZlODY3ZTk3OTFlXkEyXkFqcGdeQXVyNzkwMjQ5NzM@._V1_UY67_CR1,0,45,67_AL_.jpg" width="45"/>
</a> </td>
<td class="titleColumn">
2.
<a href="/title/tt0068646/" title="Francis Ford Coppola (dir.), Marlon Brando, Al Pacino">The Godfather</a>
<span class="secondaryInfo">(1972)</span>
</td>
<td class="ratingColumn imdbRating">
<strong title="9.1 based on 1,485,540 user ratings">9.1</strong>
</td>
<td class="ratingColumn">
<div class="seen-widget seen-widget-tt0068646 pending" data-titleid="tt0068646">
<div class="boundary">
<div class="popover">
<span class="delete"> </span><ol><li>1<li>2<li>3<li>4<li>5<li>6<li>7<li>8<li>9<li>10</li>0</li></li></li></li&td;</li></li></li></li></li></ol> </div>
</div>
<div class="inline">
<div class="pending"></div>
<div class="unseeable">NOT YET RELEASED</div>
<div class="unseen"> </div>
<div class="rating"></div>
<div class="seen">Seen</div>
</div>
</div>
</td>
<td class="watchlistColumn">

<div class="wlb_ribbon" data-recordmetrics="true" data-tconst="tt0068646"></div>
</td>
</tr>
>>>
>>> a_string.find_parents('td')
[<td class="titleColumn">
2.
<a href="/title/tt0068646/" title="Francis Ford Coppola (dir.), Marlon Brando, Al Pacino">The Godfather</a>
<span class="secondaryInfo">(1972)</span>
</td>]

Existem oito outros métodos semelhantes -

find_next_siblings(name, attrs, string, limit, **kwargs)
find_next_sibling(name, attrs, string, **kwargs)

find_previous_siblings(name, attrs, string, limit, **kwargs)
find_previous_sibling(name, attrs, string, **kwargs)

find_all_next(name, attrs, string, limit, **kwargs)
find_next(name, attrs, string, **kwargs)

find_all_previous(name, attrs, string, limit, **kwargs)
find_previous(name, attrs, string, **kwargs)

Onde,

find_next_siblings() e find_next_sibling() os métodos irão iterar sobre todos os irmãos do elemento que vêm depois do atual.

find_previous_siblings() e find_previous_sibling() os métodos irão iterar sobre todos os irmãos que vêm antes do elemento atual.

find_all_next() e find_next() os métodos irão iterar sobre todas as tags e strings que vêm após o elemento atual.

find_all_previous e find_previous() métodos irão iterar sobre todas as tags e strings que vêm antes do elemento atual.

Seletores CSS

A biblioteca BeautifulSoup para suportar os seletores CSS mais comumente usados. Você pode pesquisar elementos usando seletores CSS com a ajuda do método select ().

Aqui estão alguns exemplos -

>>> soup.select('title')
[<title>IMDb Top 250 - IMDb</title>, <title>IMDb Top Rated Movies</title>]
>>>
>>> soup.select("p:nth-of-type(1)")
[<p>The Top Rated Movie list only includes theatrical features.</p>, <p> class="imdb-footer__copyright _2-iNNCFskmr4l2OFN2DRsf">© 1990- by IMDb.com, Inc.</p>]
>>> len(soup.select("p:nth-of-type(1)"))
2
>>> len(soup.select("a"))
609
>>> len(soup.select("p"))
2

>>> soup.select("html head title")
[<title>IMDb Top 250 - IMDb</title>, <title>IMDb Top Rated Movies</title>]
>>> soup.select("head > title")
[<title>IMDb Top 250 - IMDb</title>]

#print HTML code of the tenth li elemnet
>>> soup.select("li:nth-of-type(10)")
[<li class="subnav_item_main">
<a href="/search/title?genres=film_noir&sort=user_rating,desc&title_type=feature&num_votes=25000,">Film-Noir
</a> </li>]

Um dos aspectos importantes do BeautifulSoup é pesquisar a árvore de análise e permite que você faça alterações no documento da web de acordo com sua necessidade. Podemos fazer alterações nas propriedades da tag usando seus atributos, como o método .name, .string ou .append (). Ele permite que você adicione novas tags e strings a uma tag existente com a ajuda dos métodos .new_string () e .new_tag (). Existem outros métodos também, como .insert (), .insert_before () ou .insert_after () para fazer várias modificações em seu documento HTML ou XML.

Alterar nomes e atributos de tag

Depois de criar a sopa, é fácil fazer modificações como renomear a tag, fazer modificações em seus atributos, adicionar novos atributos e excluir atributos.

>>> soup = BeautifulSoup('<b class="bolder">Very Bold</b>')
>>> tag = soup.b

A modificação e adição de novos atributos são as seguintes -

>>> tag.name = 'Blockquote'
>>> tag['class'] = 'Bolder'
>>> tag['id'] = 1.1
>>> tag
<Blockquote class="Bolder" id="1.1">Very Bold</Blockquote>

Os atributos de exclusão são os seguintes -

>>> del tag['class']
>>> tag
<Blockquote id="1.1">Very Bold</Blockquote>
>>> del tag['id']
>>> tag
<Blockquote>Very Bold</Blockquote>

Modificando .string

Você pode modificar facilmente o atributo .string da tag -

>>> markup = '<a href="https://www.tutorialspoint.com/index.htm">Must for every <i>Learner>/i<</a>'
>>> Bsoup = BeautifulSoup(markup)
>>> tag = Bsoup.a
>>> tag.string = "My Favourite spot."
>>> tag
<a href="https://www.tutorialspoint.com/index.htm">My Favourite spot.</a>

Acima, podemos ver se a tag contém alguma outra tag, ela e todo o seu conteúdo serão substituídos por novos dados.

acrescentar()

Adicionar novos dados / conteúdos a uma tag existente é usando o método tag.append (). É muito semelhante ao método append () na lista Python.

>>> markup = '<a href="https://www.tutorialspoint.com/index.htm">Must for every <i>Learner</i></a>'
>>> Bsoup = BeautifulSoup(markup)
>>> Bsoup.a.append(" Really Liked it")
>>> Bsoup
<html><body><a href="https://www.tutorialspoint.com/index.htm">Must for every <i>Learner</i> Really Liked it</a></body></html>
>>> Bsoup.a.contents
['Must for every ', <i>Learner</i>, ' Really Liked it']

NavigableString () e .new_tag ()

Caso você queira adicionar uma string a um documento, isso pode ser feito facilmente usando o construtor append () ou NavigableString () -

>>> soup = BeautifulSoup("<b></b>")
>>> tag = soup.b
>>> tag.append("Start")
>>>
>>> new_string = NavigableString(" Your")
>>> tag.append(new_string)
>>> tag
<b>Start Your</b>
>>> tag.contents
['Start', ' Your']

Note: Se você encontrar algum erro de nome ao acessar a função NavigableString (), da seguinte maneira−

NameError: o nome 'NavigableString' não foi definido

Basta importar o diretório NavigableString do pacote bs4 -

>>> from bs4 import NavigableString

Podemos resolver o erro acima.

Você pode adicionar comentários à sua tag existente ou pode adicionar alguma outra subclasse de NavigableString, basta chamar o construtor.

>>> from bs4 import Comment
>>> adding_comment = Comment("Always Learn something Good!")
>>> tag.append(adding_comment)
>>> tag
<b>Start Your<!--Always Learn something Good!--></b>
>>> tag.contents
['Start', ' Your', 'Always Learn something Good!']

Adicionar uma nova tag inteira (não anexar a uma tag existente) pode ser feito usando o método embutido Beautifulsoup, BeautifulSoup.new_tag () -

>>> soup = BeautifulSoup("<b></b>")
>>> Otag = soup.b
>>>
>>> Newtag = soup.new_tag("a", href="https://www.tutorialspoint.com")
>>> Otag.append(Newtag)
>>> Otag
<b><a href="https://www.tutorialspoint.com"></a></b>

Apenas o primeiro argumento, o nome da tag, é obrigatório.

inserir()

Semelhante ao método .insert () na lista python, tag.insert () irá inserir um novo elemento, entretanto, ao contrário de tag.append (), o novo elemento não necessariamente vai no final do conteúdo de seu pai. Novo elemento pode ser adicionado em qualquer posição.

>>> markup = '<a href="https://www.djangoproject.com/community/">Django Official website <i>Huge Community base</i></a>'
>>> soup = BeautifulSoup(markup)
>>> tag = soup.a
>>>
>>> tag.insert(1, "Love this framework ")
>>> tag
<a href="https://www.djangoproject.com/community/">Django Official website Love this framework <i>Huge Community base</i></a>
>>> tag.contents
['Django Official website ', 'Love this framework ', <i>Huge Community base</i
>]
>>>

insert_before () e insert_after ()

Para inserir alguma tag ou string antes de algo na árvore de análise, usamos insert_before () -

>>> soup = BeautifulSoup("Brave")
>>> tag = soup.new_tag("i")
>>> tag.string = "Be"
>>>
>>> soup.b.string.insert_before(tag)
>>> soup.b
<b><i>Be</i>Brave</b>

Da mesma forma, para inserir alguma tag ou string logo após algo na árvore de análise, use insert_after ().

>>> soup.b.i.insert_after(soup.new_string(" Always "))
>>> soup.b
<b><i>Be</i> Always Brave</b>
>>> soup.b.contents
[<i>Be</i>, ' Always ', 'Brave']

Claro()

Para remover o conteúdo de uma tag, use tag.clear () -

>>> markup = '<a href="https://www.tutorialspoint.com/index.htm">For <i>technical & Non-technical&lr;/i> Contents</a>'
>>> soup = BeautifulSoup(markup)
>>> tag = soup.a
>>> tag
<a href="https://www.tutorialspoint.com/index.htm">For <i>technical & Non-technical</i> Contents</a>
>>>
>>> tag.clear()
>>> tag
<a href="https://www.tutorialspoint.com/index.htm"></a>

extrair()

Para remover uma tag ou strings da árvore, use PageElement.extract ().

>>> markup = '<a href="https://www.tutorialspoint.com/index.htm">For <i&gr;technical & Non-technical</i> Contents</a>'
>>> soup = BeautifulSoup(markup)
>>> a_tag = soup.a
>>>
>>> i_tag = soup.i.extract()
>>>
>>> a_tag
<a href="https://www.tutorialspoint.com/index.htm">For Contents</a>
>>>
>>> i_tag
<i>technical & Non-technical</i>
>>>
>>> print(i_tag.parent)
None

decompor()

O tag.decompose () remove uma tag da árvore e exclui todo o seu conteúdo.

>>> markup = '<a href="https://www.tutorialspoint.com/index.htm">For <i>technical & Non-technical</i> Contents</a>'
>>> soup = BeautifulSoup(markup)
>>> a_tag = soup.a
>>> a_tag
<a href="https://www.tutorialspoint.com/index.htm">For <i>technical & Non-technical</i> Contents</a>
>>>
>>> soup.i.decompose()
>>> a_tag
<a href="https://www.tutorialspoint.com/index.htm">For Contents</a>
>>>

Substituir com()

Como o nome sugere, a função pageElement.replace_with () substituirá a tag ou string antiga pela nova tag ou string na árvore -

>>> markup = '<a href="https://www.tutorialspoint.com/index.htm">Complete Python <i>Material</i></a>'
>>> soup = BeautifulSoup(markup)
>>> a_tag = soup.a
>>>
>>> new_tag = soup.new_tag("Official_site")
>>> new_tag.string = "https://www.python.org/"
>>> a_tag.i.replace_with(new_tag)
<i>Material</i>
>>>
>>> a_tag
<a href="https://www.tutorialspoint.com/index.htm">Complete Python <Official_site>https://www.python.org/</Official_site></a>

Na saída acima, você notou que replace_with () retorna a tag ou string que foi substituída (como “Material” em nosso caso), então você pode examiná-lo ou adicioná-lo de volta a outra parte da árvore.

embrulho()

O pageElement.wrap () incluiu um elemento na tag que você especificou e retorna um novo wrapper -

>>> soup = BeautifulSoup("<p>tutorialspoint.com</p>")
>>> soup.p.string.wrap(soup.new_tag("b"))
<b>tutorialspoint.com</b>
>>>
>>> soup.p.wrap(soup.new_tag("Div"))
<Div><p><b>tutorialspoint.com</b></p></Div>

desembrulhar()

O tag.unwrap () é exatamente o oposto de wrap () e substitui uma tag por qualquer coisa dentro dessa tag.

>>> soup = BeautifulSoup('<a href="https://www.tutorialspoint.com/">I liked <i>tutorialspoint</i></a>')
>>> a_tag = soup.a
>>>
>>> a_tag.i.unwrap()
<i></i>
>>> a_tag
<a href="https://www.tutorialspoint.com/">I liked tutorialspoint</a>

Acima, você notou que, assim como o replace_with (), o unbrap () retorna a tag que foi substituída.

Abaixo está mais um exemplo de unbrap () para entendê-lo melhor -

>>> soup = BeautifulSoup("<p>I <strong>AM</strong> a <i>text</i>.</p>")
>>> soup.i.unwrap()
<i></i>
>>> soup
<html><body><p>I <strong>AM</strong> a text.</p></body></html>

Desembrulhar () é bom para eliminar a marcação.

Todos os documentos HTML ou XML são escritos em alguma codificação específica como ASCII ou UTF-8. No entanto, quando você carrega esse documento HTML / XML no BeautifulSoup, ele foi convertido para Unicode.

>>> markup = "<p>I will display £</p>"
>>> Bsoup = BeautifulSoup(markup)
>>> Bsoup.p
<p>I will display £</p>
>>> Bsoup.p.string
'I will display £'

O comportamento acima ocorre porque o BeautifulSoup usa internamente a sub-biblioteca chamada Unicode, Dammit, para detectar a codificação de um documento e depois convertê-lo em Unicode.

Porém, nem sempre, o Unicode, Dammit adivinha corretamente. Como o documento é pesquisado byte a byte para adivinhar a codificação, leva muito tempo. Você pode economizar algum tempo e evitar erros, se você já conhece a codificação, passando-a para o construtor BeautifulSoup como from_encoding.

Abaixo está um exemplo em que o BeautifulSoup identifica incorretamente um documento ISO-8859-8 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'
>>>

Para resolver o problema acima, passe para BeautifulSoup usando from_encoding -

>>> soup = BeautifulSoup(markup, from_encoding="iso-8859-8")
>>> soup.h1
<h1>ולש </h1>
>>> soup.original_encoding
'iso-8859-8'
>>>

Outro novo recurso adicionado do BeautifulSoup 4.4.0 é exclude_encoding. Pode ser usado, quando você não sabe a codificação correta, mas tem certeza de que Unicode, Dammit está mostrando resultado errado.

>>> soup = BeautifulSoup(markup, exclude_encodings=["ISO-8859-7"])

Codificação de saída

A saída de um BeautifulSoup é um documento UTF-8, independentemente do documento inserido no BeautifulSoup. Abaixo de um documento, onde os caracteres polidos estão no formato ISO-8859-2.

html_markup = """
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<HTML>
<HEAD>
<META HTTP-EQUIV="content-type" CONTENT="text/html; charset=iso-8859-2">
</HEAD>
<BODY>
ą ć ę ł ń ó ś ź ż Ą Ć Ę Ł Ń Ó Ś Ź Ż
</BODY>
</HTML>
"""


>>> soup = BeautifulSoup(html_markup)
>>> print(soup.prettify())
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
   <head>
      <meta content="text/html; charset=utf-8" http-equiv="content-type"/>
   </head>
   <body>
      ą ć ę ł ń ó ś ź ż Ą Ć Ę Ł Ń Ó Ś Ź Ż
   </body>
</html>

No exemplo acima, se você notar, a tag <meta> foi reescrita para refletir o documento gerado a partir do BeautifulSoup agora está no formato UTF-8.

Se você não quiser a saída gerada em UTF-8, pode atribuir a codificação desejada em prettify ().

>>> print(soup.prettify("latin-1"))
b'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">\n<html>\n <head>\n <meta content="text/html; charset=latin-1" http-equiv="content-type"/>\n </head>\n <body>\n ą ć ę ł ń \xf3 ś ź ż Ą Ć Ę Ł Ń \xd3 Ś Ź Ż\n </body>\n</html>\n'

No exemplo acima, codificamos o documento completo, no entanto, você pode codificar qualquer elemento particular da sopa como se fosse uma string python -

>>> soup.p.encode("latin-1")
b'<p>0My first paragraph.</p>'
>>> soup.h1.encode("latin-1")
b'<h1>My First Heading</h1>'

Todos os caracteres que não podem ser representados na codificação escolhida serão convertidos em referências numéricas de entidade XML. Abaixo está um exemplo -

>>> markup = u"<b>\N{SNOWMAN}</b>"
>>> snowman_soup = BeautifulSoup(markup)
>>> tag = snowman_soup.b
>>> print(tag.encode("utf-8"))
b'<b>\xe2\x98\x83</b>'

Se você tentar codificar o acima em “latin-1” ou “ascii”, irá gerar “☃”, indicando que não há representação para isso.

>>> print (tag.encode("latin-1"))
b'<b>☃</b>'
>>> print (tag.encode("ascii"))
b'<b>☃</b>'

Unicode, droga

Unicode, Dammit é usado principalmente quando o documento recebido está em formato desconhecido (principalmente em idioma estrangeiro) e queremos codificar em algum formato conhecido (Unicode) e também não precisamos do Beautifulsoup para fazer tudo isso.

O ponto de partida de qualquer projeto BeautifulSoup é o objeto BeautifulSoup. Um objeto BeautifulSoup representa o documento HTML / XML de entrada usado para sua criação.

Podemos passar uma string ou um objeto semelhante a um arquivo para Beautiful Soup, onde os arquivos (objetos) são armazenados localmente em nossa máquina ou em uma página da web.

Os objetos BeautifulSoup mais comuns são -

  • Tag
  • NavigableString
  • BeautifulSoup
  • Comment

Comparando objetos para igualdade

De acordo com a bela sopa, duas strings navegáveis ​​ou objetos de tag são iguais se representarem a mesma marcação HTML / XML.

Agora vamos ver o exemplo abaixo, onde as duas tags <b> são tratadas como iguais, embora vivam em partes diferentes da árvore de objetos, porque ambas se parecem com “<b> Java </b>”.

>>> markup = "<p>Learn Python and <b>Java</b> and advanced <b>Java</b>! from Tutorialspoint</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

No entanto, para verificar se as duas variáveis ​​se referem aos mesmos objetos, você pode usar o seguinte−

>>> print(first_b is second_b)
False

Copiando objetos da bela sopa

Para criar uma cópia de qualquer tag ou NavigableString, use a função copy.copy (), assim como abaixo -

>>> import copy
>>> p_copy = copy.copy(soup.p)
>>> print(p_copy)
<p>Learn Python and <b>Java</b> and advanced <b>Java</b>! from Tutorialspoint</p>
>>>

Embora as duas cópias (original e copiada) contenham a mesma marcação, no entanto, as duas não representam 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 de objetos Beautiful Soup original, como se extract () tivesse sido chamada nela.

>>> print(p_copy.parent)
None

O comportamento acima é devido a dois objetos tag diferentes que não podem ocupar o mesmo espaço ao mesmo tempo.

Existem várias situações em que você deseja extrair tipos específicos de informações (apenas <a> tags) usando Beautifulsoup4. A classe SoupStrainer em Beautifulsoup permite que você analise apenas uma parte específica de um documento recebido.

Uma maneira é criar um SoupStrainer e passá-lo para o construtor Beautifulsoup4 como o argumento parse_only.

SoupStrainer

Um SoupStrainer informa à BeautifulSoup quais partes são extraídas, e a árvore de análise consiste apenas nesses elementos. Se você restringir as informações necessárias a uma parte específica do HTML, isso irá acelerar o resultado da pesquisa.

product = SoupStrainer('div',{'id': 'products_list'})
soup = BeautifulSoup(html,parse_only=product)

As linhas de código acima analisam apenas os títulos de um site de produto, que pode estar dentro de um campo de tag.

Da mesma forma, como acima, podemos usar outros objetos soupStrainer, para analisar informações específicas de uma tag HTML. Abaixo estão alguns dos exemplos -

from bs4 import BeautifulSoup, SoupStrainer

#Only "a" tags
only_a_tags = SoupStrainer("a")

#Will parse only the below mentioned "ids".
parse_only = SoupStrainer(id=["first", "third", "my_unique_id"])
soup = BeautifulSoup(my_document, "html.parser", parse_only=parse_only)

#parse only where string length is less than 10
def is_short_string(string):
   return len(string) < 10
   
only_short_strings =SoupStrainer(string=is_short_string)

Manipulação de erros

Existem dois tipos principais de erros que precisam ser tratados no BeautifulSoup. Esses dois erros não são do seu script, mas da estrutura do snippet, porque a API BeautifulSoup lança um erro.

Os dois principais erros são os seguintes -

AttributeError

É causado quando a notação de ponto não encontra uma marca irmã para a marca HTML atual. Por exemplo, você pode ter encontrado este erro, devido à falta da “etiqueta âncora”, a chave de custo lançará um erro ao atravessar e requer uma etiqueta âncora.

KeyError

Este erro ocorre se o atributo de tag HTML necessário estiver ausente. Por exemplo, se não tivermos o atributo data-pid em um snippet, a chave pid lançará o erro de chave.

Para evitar os dois erros listados acima ao analisar um resultado, esse resultado será ignorado para garantir que um snippet malformado não seja inserido nos bancos de dados -

except(AttributeError, KeyError) as er:
pass

diagnosticar()

Sempre que encontrarmos alguma dificuldade em entender o que o BeautifulSoup faz em nosso documento ou HTML, basta passá-lo para a função diagnose (). Ao passar o arquivo de documento para a função diagnose (), podemos mostrar como uma lista de diferentes analisadores lida com o documento.

Abaixo está um exemplo para demonstrar o uso da função diagnose () -

from bs4.diagnose import diagnose

with open("20 Books.html",encoding="utf8") as fp:
   data = fp.read()
   
diagnose(data)

Resultado

Erro de análise

Existem dois tipos principais de erros de análise. Você pode obter uma exceção como HTMLParseError, ao alimentar seu documento no BeautifulSoup. Você também pode obter um resultado inesperado, onde a árvore de análise BeautifulSoup parece muito diferente do resultado esperado do documento de análise.

Nenhum dos erros de análise é causado por BeautifulSoup. É por causa do analisador externo que usamos (html5lib, lxml) uma vez que BeautifulSoup não contém nenhum código de analisador. Uma maneira de resolver o erro de análise acima é usar outro analisador.

from HTMLParser import HTMLParser

try:
   from HTMLParser import HTMLParseError
except ImportError, e:
   # From python 3.5, HTMLParseError is removed. Since it can never be
   # thrown in 3.5, we can just define our own class as a placeholder.
   class HTMLParseError(Exception):
      pass

O analisador HTML embutido no Python causa dois erros de análise mais comuns, HTMLParser.HTMLParserError: tag de início malformada e HTMLParser.HTMLParserError: tag de fim ruim e, para resolver isso, é usar outro analisador principalmente: lxml ou html5lib.

Outro tipo comum de comportamento inesperado é que você não consegue encontrar uma marca que sabe que está no documento. No entanto, quando você executa find_all () retorna [] ou find () retorna None.

Isso pode ser devido ao analisador HTML embutido em python, que às vezes pula tags que não entende.

Erro do analisador XML

Por padrão, o pacote BeautifulSoup analisa os documentos como HTML, no entanto, é muito fácil de usar e manipula XML malformado de uma maneira muito elegante usando beautifulsoup4.

Para analisar o documento como XML, você precisa ter um analisador lxml e apenas passar o “xml” como o segundo argumento para o construtor Beautifulsoup -

soup = BeautifulSoup(markup, "lxml-xml")

ou

soup = BeautifulSoup(markup, "xml")

Um erro comum de análise de XML é -

AttributeError: 'NoneType' object has no attribute 'attrib'

Isso pode acontecer caso algum elemento esteja faltando ou não esteja definido ao usar a função find () ou findall ().

Outros erros de análise

A seguir estão alguns dos outros erros de análise que vamos discutir nesta seção -

Questão ambiental

Além dos erros de análise mencionados acima, você pode encontrar outros problemas de análise, como problemas ambientais em que seu script pode funcionar em um sistema operacional, mas não em outro sistema operacional, ou pode funcionar em um ambiente virtual, mas não em outro ambiente virtual ou pode não funcionar fora do ambiente virtual. Todos esses problemas podem ocorrer porque os dois ambientes têm diferentes bibliotecas de analisador disponíveis.

Recomenda-se conhecer ou verificar seu analisador padrão em seu ambiente de trabalho atual. Você pode verificar o analisador padrão atual disponível para o ambiente de trabalho atual ou então passar explicitamente a biblioteca do analisador necessária como segundos argumentos para o construtor BeautifulSoup.

Não diferencia maiúsculas de minúsculas

Como as tags e atributos HTML não diferenciam maiúsculas de minúsculas, todos os três analisadores HTML convertem nomes de tags e atributos em letras minúsculas. No entanto, se você deseja preservar as tags e atributos de maiúsculas ou maiúsculas, é melhor analisar o documento como XML.

UnicodeEncodeError

Vamos dar uma olhada no segmento de código abaixo -

soup = BeautifulSoup(response, "html.parser")
   print (soup)

Resultado

UnicodeEncodeError: 'charmap' codec can't encode character '\u011f'

O problema acima pode ser devido a duas situações principais. Você pode estar tentando imprimir um caractere Unicode que seu console não sabe como exibir. Segundo, você está tentando gravar em um arquivo e passa um caractere Unicode que não é compatível com sua codificação padrão.

Uma maneira de resolver o problema acima é codificar o texto / caractere de resposta antes de fazer a sopa para obter o resultado desejado, como segue -

responseTxt = response.text.encode('UTF-8')

KeyError: [attr]

É causado pelo acesso à 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 não tiver certeza se attr está definido.

for item in soup.fetch('a'):
   try:
      if (item['href'].startswith('/') or "tutorialspoint" in item['href']):
      (...)
   except KeyError:
      pass # or some other fallback action

AttributeError

Você pode encontrar AttributeError da seguinte forma -

AttributeError: 'list' object has no attribute 'find_all'

O erro acima ocorre principalmente porque você esperava que find_all () retornasse uma única tag ou string. No entanto, soup.find_all retorna uma lista de elementos python.

Tudo o que você precisa fazer é iterar pela lista e coletar dados desses elementos.