Eu estou fazendo um scraping de umas informações de preço, mas me parece que existe um erro no get_text() que eu ainda não entendi
De primeria, eu estou tentando uma estrutura mais simples de print
from urllib.request import urlopen
from bs4 import BeautifulSoup
url = 'https://tepbac.com/gia-thuy-san/cat/2-thuy-san/'
response = urlopen(url)
html = response.read()
soup = BeautifulSoup(html, 'html.parser')
print(soup.find('a', class_="h6").get_text())
print(soup.find('td', class_="text-right text-danger font-weight-bold").get_text())
print(soup.find_next('td').get_text())
print(soup.find('td', class_="text-truncate").get_text())
e me vem o erro
Eu estou usando o find _next no terceiro item porque quando eu descrimino no class correto {'class':'text-right'}) ele me repete o valor do segundo {'class':'text-right text-danger font-weight-bold'}— que é o preço e não a data
AttributeError Traceback (most recent call last)
<ipython-input-54-b84b9a4eca20> in <module>
11 print(soup.find('a', class_="h6").get_text())
12 print(soup.find('td', class_="text-right text-danger font-weight-bold").get_text())
---> 13 print(soup.find_next('td').get_text())
14 print(soup.find('td', class_="text-truncate").get_text())
AttributeError: 'NoneType' object has no attribute 'get_text'
Claro que esse print é só para checar se o scraping está funcionando. Eu preciso puxar uma tabela inteira!
Então, eu tenho um
for
que eu estou ajustando para fazer o meu df
for item in listings:
market = {}
market['specie'] = item.find('a', {'class':'h6'}).getText()
market['price'] = item.find('td', {'class':'text-right text-danger font-weight-bold'}).getText()
market['date'] = item.find('td', {'class':'text-right'}).getText()
market['city'] = item.find('td class', {'a rel':'nofollow'}).getText()
markets.append(market)
pricing = pd.DataFrame(markets)
pricing
e vem o mesmo erro
AttributeError Traceback (most recent call last)
<ipython-input-34-d14b83920384> in <module>
2 market = {}
----> 4 market['specie'] = item.find('a', {'class':'h6'}).getText()
5 market['price'] = item.find('td', {'class':'text-right text-danger font-weight-bold'}).getText()
6 market['date'] = item.find('td', {'class':'text-right'}).getText()
AttributeError: 'NoneType' object has no attribute 'getText'
Enfim...alguma luz??
Olá Luiz,
O que está acontecendo é que o
find
não está retornando nada, e assim não é possível executar o
getText()
a partir de um retorno vazio.
Eu não entendo muito bem como funciona o
find_next
mas trocando essa parte por
soup.find_all('td', class_="text-right")[1].get_text()
consegui executar o seu primeiro código sem erros (o
[1]
vai selecionar apenas o segundo item de todos os encontrados).
Aplicando isso no for o
city
também apresentou o mesmo problema, mas coincidentemente a solução é igual:
# Dentro do for
market['specie'] = item.find('a', {'class':'h6'}).getText()
market['price'] = item.find('td', {'class':'text-right text-danger font-weight-bold'}).getText()
market['date'] = item.find_all('td', {'class':'text-right'})[1].getText()
market['city'] = item.find_all('a')[1].getText()
Testa se isso resolve e qualquer coisa é só falar!
Eu tenho um erro anterior que as minhas listas estão vindo vazias e aí o código roda, mas não tráz nada...
Veja só..
markets = []
listings = soup.find('div', {'class': 'bg-white rounded'})
Esse código em traz um div com um tabela dentro. O conteúdo tá todo dentro dessa tabela
A minha variável listing [] traz tudo certinho para eu rodar o FOR
for item in listings:
market = {}
market['specie'] = item.find('a', {'class':'h6'}).getText()
market['price'] = item.find('td', {'class':'text-right text-danger font-weight-bold'}).getText()
market['date'] = item.find_all('td', {'class':'text-right'})[1].getText()
market['city'] = item.find_all('a')[1].getText()
markets.append(market)
shrimp_pricing = pd.DataFrame(markets)
shrimp_pricing
Mas ainda assim me retorna um erro porque as variáveis que eu criei estão vazias
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-32-5d47b0c177c5> in <module>
2 market = {}
----> 4 market['specie'] = item.find('a', {'class':'h6'}).getText()
5 market['price'] = item.find('td', {'class':'text-right text-danger font-weight-bold'}).getText()
6 market['date'] = item.find_all('td', {'class':'text-right'})[1].getText()
TypeError: slice indices must be integers or None or have an __index__ method
E ainda não cosengui! :-/
No código
listings = soup.find('div', {'class': 'bg-white rounded'})
como está sendo utilizado o
find
vai ser retornado apenas 1 item que é a
div bg-white
completa, mas para o
for
o necessário é passar uma lista de valores e não apenas 1 item.
Olhando na página como temos uma tabela e o que queremos selecionar é cada linha (cada
tr
), o melhor caminho é então selecionar todas as tags
tr
com o
find_all()
# Aqui o listings vai ser uma lista onde cada item da lista é um tr da página
listings = soup.find_all('tr')
Exemplo completo:
from urllib.request import urlopen
from bs4 import BeautifulSoup
import pandas as pd
url = 'https://tepbac.com/gia-thuy-san/cat/2-thuy-san/'
response = urlopen(url)
html = response.read()
soup = BeautifulSoup(html, 'html.parser')
markets = []
listings = soup.find_all('tr')
print(listings)
for item in listings:
market = {}
market['specie'] = item.find('a', {'class':'h6'}).getText()
market['price'] = item.find('td', {'class':'text-right text-danger font-weight-bold'}).getText()
market['date'] = item.find_all('td', {'class':'text-right'})[1].getText()
market['city'] = item.find_all('a')[1].getText()
markets.append(market)
shrimp_pricing = pd.DataFrame(markets)
shrimp_pricing