Solucionado (ver solução)
Solucionado
(ver solução)
9
respostas

Não retorna os valores do etherscan

Estou tentando pegar os valores de transações de: https://etherscan.io/token/0xfc98e825a2264d890f9a1e68ed50e1526abccacd?a=0x70d5eadcb367bcf733fc98b441def1c7c5eec187 via webscraping.

Porém, ele retorna nonetype.

from selenium import webdriver
from bs4 import BeautifulSoup

url = ('https://etherscan.io/token/0xfc98e825a2264d890f9a1e68ed50e1526abccacd?a=0x70d5eadcb367bcf733fc98b441def1c7c5eec187')

driver = webdriver.Chrome()
driver.get(url)

resp = driver.page_source
#print(resp)

driver.close()

soup = BeautifulSoup(resp, 'html.parser')

soup.findAll('div', id = 'maindiv').get_text()

O que posso fazer para que traga os valores corretos?

9 respostas

Oii Ana, como você está?

Seria a coluna quantity? Como tem vários valores na página, você manda um print marcando os valores que você deseja obter? Dessa forma consigo te ajudar de forma mais direcionada.

Fico no aguardo.

Grande abraço!

Olá Nádia, obrigada por responder.

Eu gostaria de pegar esses valores: TxnHash, Method, Age, From, To e Quantity

Oiii Ana, espero que esteja tudo bem com você.

Observei pelo código que você disponibilizou que você está utilizando o Selenium e isso é um ótimo começo. Páginas de mercado financeiro geralmente são custosas para fazer scrapping, é algo normal nesse meio.

Ao inspencionar a página do site Etherscan, podemos perceber que a tabela de interesse está localizada dentro de um iframe, ou seja, possui uma inclusão de outros arquivos HTML dentro do HTML original, como mostro abaixo:

Imagem que mostra o código do iframe na página

Sendo assim, se você inspecionar a página e abrir o link que o iframe aponta precedendo-o pela URL padrão https://etherscan.io/, verá um site que possui apenas a tabela de interesse e é através dele que iremos obter as informações necessárias.

Entretanto, temos um porém, observe que o iframe possui um token de acesso e ele varia de usuário para usuário. Então, para capturarmos os elementos dessa página seguiremos os passos abaixo:

  • Abrir a página principal de interesse;
  • Obter o código fonte desta página;
  • Através do código fonte, capturar o iframe;
  • Abrir a página do iframe;
  • Obter o código fonte da página;
  • Transformar o HTML em uma tabela do pandas para facilitar análise.

Veja como fica em código:

from selenium import webdriver
from bs4 import BeautifulSoup
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.common.keys import Keys


import pandas as pd
import time


url_principal = ("https://etherscan.io/token/0xfc98e825a2264d890f9a1e68ed50e1526abccacd?a=0x70d5eadcb367bcf733fc98b441def1c7c5eec187")

driver = webdriver.Chrome(ChromeDriverManager().install())
driver.get(url_principal)

resp = driver.page_source
soup = BeautifulSoup(resp, 'html')
link_iframe_tabela = soup.find('iframe', id='tokentxnsiframe')['src']

url_base = "https://etherscan.io"
url_dados_tabela = f'{url_base}{link_iframe_tabela}'

driver.find_element_by_tag_name('body').send_keys(Keys.COMMAND + 't') 

time.sleep(5)

driver.get(url_dados_tabela)

dados = driver.page_source

tabela_inicial = pd.read_html(dados)[0]
tabela_inicial.drop(['Unnamed: 0', 'Unnamed: 8'], axis = 1, inplace=True)
tabela_inicial.rename({'Unnamed: 3': 'Updated to', 'Unnamed: 5': 'Type'}, axis=1, inplace=True)
print(tabela_inicial)

driver.close()

Algumas manipulações foram feitas para excluir e renomear colunas do dataframe. O dataframe final ficará da seguinte maneira:

Imagem com o resultado do dataframe

A tabela do site é paginada, possui 249 páginas, como mostro abaixo:

Imagem que mostra que a tabela do site possui 249 páginas, no canto superior direito da página

No código de exemplo, apenas a primeira está sendo capturada. Deixo como desafio para você, capturar as informações das demais páginas.

Espero ter ajudado e fico à disposição para sanar qualquer dúvida.

Grande abraço e bons estudos!

Nossa, perfeito. Muito obrigada

Estou tentando fazer desta forma, mas retorna "None"

print(soup.find('div', class_="d-inline-block"))

Ana, por ele estar retornando None, significa que não está encontrando essa classe. Anexa uma captura de tela fazendo favor de qual trecho do site é referente a essa classe, sobre qual informação você deseja obter com o código print(soup.find('div', class_="d-inline-block")).

Fico no aguardo, a gente vai se falando.

Nádia, primeiramente obrigada por estar me ajudando. Sobre o código, eu estou tentando pegar a class da página, para tentar pegar os valores de todas as páginas, e estou sem saber o pq não retorna o valor e como fazer o loop.

from selenium import webdriver
from bs4 import BeautifulSoup
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.common.keys import Keys
import pandas as pd
import time


url_principal = ("https://etherscan.io/token/0xfc98e825a2264d890f9a1e68ed50e1526abccacd?a=0x70d5eadcb367bcf733fc98b441def1c7c5eec187")

driver = webdriver.Chrome(ChromeDriverManager().install())
driver.get(url_principal)

resp = driver.page_source
soup = BeautifulSoup(resp, 'html')
link_iframe_tabela = soup.find('iframe', id='tokentxnsiframe')['src']

url_base = "https://etherscan.io"
url_dados_tabela = f'{url_base}{link_iframe_tabela}'

driver.find_element_by_tag_name('body').send_keys(Keys.COMMAND + 't') 

time.sleep(5)

driver.get(url_dados_tabela)

dados = driver.page_source

tabela_inicial = pd.read_html(dados)[0]
tabela_inicial.drop(['Unnamed: 0', 'Unnamed: 8'], axis = 1, inplace=True)
tabela_inicial.rename({'Unnamed: 3': 'Updated to', 'Unnamed: 5': 'Type'}, axis=1, inplace=True)
print(tabela_inicial)

driver.close()

print(soup.find_next('li', class_='page-item disabled').text)

Insira aqui a descrição dessa imagem para ajudar na acessibilidade

solução!

Oii Ana, desculpe pela demora em retornar.

Na verdade, a classe responsável por retornar o número de elementos da página é a page-link, como mostro na imagem abaixo:

Imagem que mostra a classe que informa a quantidade total de páginas ao inspecionar o elemento

Se pegarmos esse dado, virá o texto "Page 1 of 249", nisso, como o nosso objetivo é saber a quantidade total de páginas que teremos que percorrer, o número que nos interessa é o valor 249, certo? Nisso, podemos recorrer a um recurso do Python para separar essa string por espaços e pegarmos o último elemento dessa lista. Podemos fazer isso através da função split e como queremos o último elemento utilizaremos o índice -1, como mostro abaixo:

texto = "Page 1 of 249"
texto.split(' ')
# resultado: ['Page', '1', 'of', '249']
texto.split(' ')[-1]
# resultado: '249'

Após pegar a quantidade de páginas que teremos que percorrer, o único parâmetro que devemos mudar na URL do iframe é o do número de páginas, caracterizado pelo p, veja que na URL que mostro abaixo temos p=1 que indica que estamos na primeira página:

https://etherscan.io//token/generic-tokentxns2?m=normal&contractAddress=0xfc98e825a2264d890f9a1e68ed50e1526abccacd&a=0x70d5eadcb367bcf733fc98b441def1c7c5eec187&sid=0c2e52e2744d41ceb6fdc26c0bfddeaa&p=1

Com base nisso, o código para percorrer as páginas e capturar todos os dados ficará da seguinte forma:

from selenium import webdriver
from bs4 import BeautifulSoup
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.common.keys import Keys

import pandas as pd
import time

url_principal = ("https://etherscan.io/token/0xfc98e825a2264d890f9a1e68ed50e1526abccacd?a=0x70d5eadcb367bcf733fc98b441def1c7c5eec187")

driver = webdriver.Chrome(ChromeDriverManager().install())
driver.get(url_principal)

resp = driver.page_source
soup = BeautifulSoup(resp, 'html')
link_iframe_tabela = soup.find('iframe', id='tokentxnsiframe')['src']

url_base = "https://etherscan.io"
url_dados_tabela = f'{url_base}{link_iframe_tabela}'

driver.find_element_by_tag_name('body').send_keys(Keys.COMMAND + 't') 

time.sleep(5)

driver.get(url_dados_tabela)

dados = driver.page_source

soup = BeautifulSoup(dados, 'html.parser')

quantidade_total_de_paginas = soup.find('span', class_='page-link text-nowrap')

quantidade_total_de_paginas = int(quantidade_total_de_paginas.text.split(' ')[-1])

url_dados_tabela = url_dados_tabela.split('&p=1')[0]

dataframes = []

for pagina in range(1, quantidade_total_de_paginas+1):
    time.sleep(2)
    driver.get(f'{url_dados_tabela}&p={pagina}')
    dados = driver.page_source
    tabela = pd.read_html(dados)[0]
    tabela.drop(['Unnamed: 0', 'Unnamed: 8'], axis = 1, inplace=True)
    tabela.rename({'Unnamed: 3': 'Updated to', 'Unnamed: 5': 'Type'}, axis=1, inplace=True)
    dataframes.append(tabela)

print(dataframes)

todos_os_dados = pd.concat(dataframes)
todos_os_dados.reset_index(inplace=True, drop=True)

print(todos_os_dados)

driver.close()

No código acima abrirmos todas as páginas e salvamos o resultado do em uma lista de dataframes e após isso juntamos essas informações em um único dataframe utilizando o pd.concat.

O resultado ficará da seguinte forma: Imagem que mostra o dataframe da variável todos_os_dados resultante do código acima, que possui 6224 linhas

Veja que o dataframe final informa que temos 6224 linhas e esse valor é exatamente a quantidade de transações que há na página.

Imagem que mostra a quantidade de dados que tem na página

Um detalhe é que como percorremos muitas páginas, o código tem uma tendência a uma demora na execução. Em minha máquina tive uma média de 15 minutos de execução. Pode parecer muito, mas é um tempo esperado, uma vez que temos muitos dados para capturar.

Um observação importante, é que o site fornece a opção de exportar os dados como csv, que fica no final da página principal:

Imagem que mostra a opção de exportar os dados como cvs logo abaixo da quantidade de páginas

Logo em seguida abrirá uma tela para que você escolha a data das informações que é capaz de exportar os 5.000 primeiros registros:

Imagem com o fundo branco que mostra a opção de escolha da data das informações

Após selecionar as datas um arquivo .csv será gerado e você poderá transformar esses dados em um dataframe ou até mesmo analisar via excel de uma forma simples e rápida. Então, temos também essa opção, que dependendo do seu caso de uso pode vir a seu favor em algum momento.

Fico à disposição.

Grande abraço!

Nádia, não sei nem como te agradecer. Ficou muito claro agora. A necessidade é justamente automatizar, por isso não estou utilizando a forma de pegar via csv. Obrigada