Skip to content

Instantly share code, notes, and snippets.

@danperrout
Last active April 1, 2025 14:37
Show Gist options
  • Save danperrout/b27197056fa38d0d669332647ab89d7a to your computer and use it in GitHub Desktop.
Save danperrout/b27197056fa38d0d669332647ab89d7a to your computer and use it in GitHub Desktop.
API Função TESOURODIRETO Google Sheets
/*
* @return Acesse radaropcoes.com Retorna a cotação atual de um título específico do Tesouro Direto.
* Fonte: https://www.tesourodireto.com.br/titulos/precos-e-taxas.htm
**/
function TESOURODIRETO(bondName, argumento="r") {
let srcURL = "https://api.radaropcoes.com/bonds.json";
let jsondata = UrlFetchApp.fetch(srcURL);
let parsedData = JSON.parse(jsondata.getContentText()).response;
for(let bond of parsedData.TrsrBdTradgList) {
let currBondName = bond.TrsrBd.nm;
if (currBondName.toLowerCase() === bondName.toLowerCase())
if(argumento == "r")
return bond.TrsrBd.untrRedVal;
else
return bond.TrsrBd.untrInvstmtVal;
}
throw new Error("Título não encontrado.");
}
@tuliopascoal
Copy link

@willmoreira7, obrigado por compartilhar.

O problema está explicado então, o Cloudfare está barrando as requisições do Google Script.
Tentei entrar em contato com o pessoal do Tesouro mas sem sucesso, o formulário Fale-Conosco deles parece não estar bem implementado. Assim que seleciono um assunto, o botão 'Enviar Mensagem' desaparace.
Também percebi que existe um número bastante limitado de caracteres.
URL: https://www.tesourotransparente.gov.br/sobre/fale-conosco

Temos que encontrar alguma forma de entrar em contato com eles para averiguar a possibilidade de marcar o(s) IP(s) público do Google Script como falso-positivo ou algo do tipo...
Via Postman deve funcionar porque a requição sai com outro IP sem ser o do Google.

@willmoreira7
Copy link

Acabou de voltar a funcionar

@tuliopascoal
Copy link

Acabou de voltar a funcionar

Pelo Google ou Postman? Aqui pelo Google Script o problema persiste.

@willmoreira7
Copy link

Tinha sido pelo google mesmo, mas testando novamente agora voltou a apresentar o erro

@renanitokazo
Copy link

Será q já era mesmo então? Aqui pelo google:

Erro ao se conectar a API { [Exception: Request failed for https://www.tesourodireto.com.br returned code 403. Truncated server response: <title>Just a moment...</title><meta htt... (use muteHttpExceptions option to examine full response)] name: 'Exception' }

@kleitonramires
Copy link

Aqui, Google Script ainda fora.

@estevaobassani
Copy link

Aqui voltou um pouco pelo google script, mas caiu novamente

@CaioFilipe93
Copy link

Fora do ar, ajuda nós Daniel
Captura de tela 2024-08-20 120929

@LeoRio-GH
Copy link

Eu estava pegando os dados pelo site: "https://taxas-tesouro.com/". Mas acredito que o site deva ter sido bloqueado também, pois parou de atualizar em 19/08. Acho que o Excel também está bloqueado no endereço do arquivo JSON. Quais alternativas restam?

@tuliopascoal
Copy link

Eu estava pegando os dados pelo site: "https://taxas-tesouro.com/". Mas acredito que o site deva ter sido bloqueado também, pois parou de atualizar em 19/08. Acho que o Excel também está bloqueado no endereço do arquivo JSON. Quais alternativas restam?

A aplicação deles, muito provavelmente, também dependia da API do Tesouro Direto via Google.
Ou então, a Cloudfare está identificando as requições da aplicação deles como bot e bloqueando os accessos.

@willmoreira7
Copy link

Acredito que tudo o que eles estão identificando como bot estão bloqueando, tentei criar uma API propria aqui para fazer o testes e deu o mesmo erro.

image

@danperrout
Copy link
Author

Cloudflare está bloqueando mesmo.

Para quem tiver interesse na prória API, vcs podem usar uma das seguintes alternativas para desenvolver:

  • Python: Selenium
  • Nodejs: Puppeteer

@tuliopascoal
Copy link

Será que não daria para fazer algo com um simples cURL?
Creio que o Cloudfare não iria bloquear num primeiro moment (somente se a quantidade de requisições se tornar suspeita).

@rafaelgp23
Copy link

rafaelgp23 commented Aug 22, 2024

Pessoal, testei na máquina local aqui usando essa sugestão que achei no youtube: Scrape Websites with 403 Errors and bypass cloudflare
https://www.youtube.com/watch?v=OF100qsZPdI

No teste usando o treasurybondsinfo.json o resultado foi EXATAMENTE como no video: request em python normal o return code é 403, usando o import sugerido foi 200 e consigo o resultado esperado.

Então TALVEZ isso seria uma solução? Sugestões de como botar um script python desse rodando na internet pra podermos usar?

Código/protótipo python (usando versão 3.11.9, Windows10), rodei direto no cmd:

pip install cloudscraper
python
import cloudscraper
scraper = cloudscraper.create_scraper()
url = 'https://www.tesourodireto.com.br/json/br/com/b3/tesourodireto/service/api/treasurybondsinfo.json'
res = scraper.get(url)
print(res.status_code)
print(res.text)

EDIT: mas quando tento rodar isso no pythonanywhere.com, ainda volta 403 =/

@danperrout
Copy link
Author

@rafaelgp23

EDIT: mas quando tento rodar isso no pythonanywhere.com, ainda volta 403 =/

O Cloudflare deve ter bloqueado todos os IPs das grandes, por isso está bloqueando.. ao meu ver tem que ter uma solução via SELENIUM mesmo, simulando o uso do navegador.

@glauberramos
Copy link

Estou com o mesmo problema : /

@blechner
Copy link

Alguém conseguiu alguma solução para o script voltar a funcionar no google sheets? Talvez a única solução seja ter um outro site que retorne esse json do tesouro, daí o script acessaria ele em vez de acessar api do tesouro diretamente... mas alguém teria q implementar esse site e garantir que ele consiga chamar a api do tesouro de tempos em tempos sem ser bloqueado também :)

@BDonadelli
Copy link

BDonadelli commented Aug 23, 2024

@rafaelgp23

EDIT: mas quando tento rodar isso no pythonanywhere.com, ainda volta 403 =/

O Cloudflare deve ter bloqueado todos os IPs das grandes, por isso está bloqueando.. ao meu ver tem que ter uma solução via SELENIUM mesmo, simulando o uso do navegador.

via selenium:
https://github.com/BDonadelli/Finance-playground/blob/main/DT_TesouroDireto_Dia_planilha_v2.ipynb

PS: um possibilidade é por no agendador de tarefas da sua maquina o script https://github.com/BDonadelli/Finance-playground/blob/main/DT_TesouroDireto_Dia.py para executar na frequencia q quiser. Ele faz uma copia do conteudo do tesouro para seu github (no meu caso https://raw.githubusercontent.com/BDonadelli/Finance-playground/main/data/tesouro_direto.json)
Na api do googlesheets , TesouroDireto.gs, troque a url do tesouro por essa do github (https://raw.githubusercontent....)
(assumindo que sua máquina conversa com o GitHub)

@gabrielgasp
Copy link

gabrielgasp commented Aug 23, 2024

Eu fiz uma aplicação em Go pra pegar as informações na API do tesouro e salvar em cache. Ela expoe uma API com dois endpoints pra puxar os dados (lista tudo ou por nome). Consegui fazer o bypass da Cloudflare usando uma lib que permite impersonar o chrome no request.

Tentei na AWS e GCP mas não rolou, devem bloquear todos os IPs das clouds grandes. Como eu só preciso disso localmente, joguei num Raspberry Pi que tenho aqui e funciona redondo.

Se alguém quiser usar de base o repo é esse: https://github.com/gabrielgasp/go-taxa-tesouro

Exportei uma collection do Postman no repo porque tava com preguiça de fazer README. Tem um .env.example simples e um Dockerfile pronto.

Edit: Consegui deployar no Railway e parece estar funcionando, só não sei quanto tempo vai durar, mas enquanto durar fiquem a vontade pra usar:

Listar todos: https://tesouro.gabrielgaspar.dev/bonds
Por nome: https://tesouro.gabrielgaspar.dev/bonds/{bondName} (usa hyphen no lugar dos espaços tipo tesouro-ipca+-2035)

Configurei pra rodar o scrapping a cada 5 min de segunda a sexta de 8h às 19h, vamos ver amanha durante o dia como fica.

Update 23/08/2024: estão bloqueando 🥲

@carmodurante
Copy link

carmodurante commented Aug 23, 2024

Olá Pessoal, como maneira alternativa estou usando import xml do site https://taxas-tesouro.com, já usava assim antes mas até voltar a funcionar o script, da pra fazer dessa maneira.

Exemplo Titulo do IPCA+ 2045:
=VALUE(REGEXREPLACE(importxml(concat("https://taxas-tesouro.com/resgatar/","tesouro-ipca+-2045/"),"normalize-space(/html/body/div/div[1]/div/div[2]/main/div/div/div[1]/div[4]/div[2]/span)"),"[^\d.]",""))*1000

Como Fazer:

Só alterar a URL do titulo que deseja e incluir o xpath full no local indicado.
=VALUE(REGEXREPLACE(importxml(concat("https://taxas-tesouro.com/resgatar/","TITULO AQUI"),"normalize-space(XPATHFULL-AQUI)"),"[^\d.]",""))*1000

O titulo é só pegar da URL:
image

O xpath full pega assim:
image

@gabrielgasp
Copy link

gabrielgasp commented Aug 23, 2024

Olá Pessoal, como maneira alternativa estou usando import xml do site https://taxas-tesouro.com, já usava assim antes mas até voltar a funcionar o script, da pra fazer dessa maneira.

Exemplo Titulo do IPCA+ 2045: =VALUE(REGEXREPLACE(importxml(concat("https://taxas-tesouro.com/resgatar/","tesouro-ipca+-2045/"),"normalize-space(/html/body/div/div[1]/div/div[2]/main/div/div/div[1]/div[4]/div[2]/span)"),"[^\d.]",""))*1000

Como Fazer:

Só alterar a URL do titulo que deseja e incluir o xpath full no local indicado. =VALUE(REGEXREPLACE(importxml(concat("https://taxas-tesouro.com/resgatar/","TITULO AQUI"),"normalize-space(XPATHFULL-AQUI)"),"[^\d.]",""))*1000

O titulo é só pegar da URL: image

O xpath full pega assim: image

O problema é que o https://taxas-tesouro.com/ também parece estar sofrendo bloqueio pra buscar as informações do Tesouro. Se você reparar, a última atualização que ele tem é do dia 19.

@rafaelgp23
Copy link

rafaelgp23 commented Aug 23, 2024

@carmodurante eu cogitei essa solução, vai uma potencial dica pra vc:

Se olhar os Response Headers do https://www.tesourodireto.com.br/json/br/com/b3/tesourodireto/service/api/treasurybondsinfo.json

server: cloudflare
x-frame-options: SAMEORIGIN
x-frame-options: ALLOW-FROM http://bvmf.bmfbovespa.com.br, http://www2.bmfbovespa.com.br, http://www.bmf.com.br, http://www2.bmf.com.br, https://www2.cetip.com.br, http://estatisticas.cetip.com.br/

Não manjo disso, mas to interpretando que esses domínios acima talvez tenham permissão de chamada dessa API, sem incorrer no problema que estamos tendo.

Talvez se encontrar aonde nos sites desses domínios estejam usando o api/treasurybondsinfo.json, daria pra usar o importxml neles.

@Celogol
Copy link

Celogol commented Aug 23, 2024

Eu não sou muito bom em programação, por acaso alguém conseguiu criar um script ou função para o google planilha para capturar as taxas do Tesouro Direto do site "https://www.tesouroinfo.com/", ele esta com as taxas atualizadas diferente do site "https://taxas-tesouro.com/ " que estão com as taxas congelas desde o dia 19. Talvez com esse script resolva nossos problemas....
Se alguém puder ajudar e colocar o código aqui no grupo, agradeço

@antonio-junior
Copy link

Pra pegar o IPCA+ 2029 eu fiz assim:
=IMPORTXML("https://www.tesouroinfo.com/"; "/html/body/div[1]/div[3]/table[1]/tbody/tr[18]/td[5]/text()")

O segundo parametro é o xpath. Pra pegar faz como o @carmodurante explicou no screenshot.

@carmodurante
Copy link

@Celogol e @rafaelgp23
Estava tentando usar a API que o site do https://www.tesouroinfo.com/api-documentation diponibiliza mas fiz um teste e ainda ta em testes não disponibilizaram dados desse ano.

Como alternativa eu fiz um query direto do html mesmo utilizando a função IMPORTHTML, da pra usar de boas assim.

Aqui ele trás a tabela completa com os dados de todos os titulos, da pra brincar se alguem quiser:

image

Tabela Resgatar:
=importhtml("https://www.tesouroinfo.com/","table",4)

Tabela Investir:
=importhtml("https://www.tesouroinfo.com/","table",2)

Se quiserem utilizar de uma forma que retorne apenas o valor de um titulo especifico só utilizar essa formula:
=REGEXREPLACE(QUERY(query(importhtml("https://www.tesouroinfo.com/","table",4), "select Col5 where Col2 = 'Ipca+ 2045' ", -1), "SELECT * OFFSET 1", 0),"[^\d.]","")*1000

image

Para alterar o titulo que retorna é só mudar na formula o Col2 = 'Nome Titulo' de acordo com o nome que esta na tabela.

Desse jeito via IMPORTHTML é melhor do que fazer pelo importxml e fullpath que falei ali acima, porque qualquer alteração na tela ele já para de funcionar, e esse aqui pega direto a tabela e fazemos a manipulação dos dados em cima dela.

@tuliopascoal
Copy link

@carmodurante : o tesouroinfo.com está com as taxas atualizadas? Não estão sofrendo do mesmo problema também?

De qualquer maneira, o site tesouroinfo.com tá retornando HTTP error 500 aqui.

@carmodurante
Copy link

carmodurante commented Aug 24, 2024

@tuliopascoal Que estranho aqui esta normal, pode ser que tenha caido de madrugada pra alguma atualização.
E sim está atualizado, mas api que está sendo chamanda no site não está exposta, esta vindo do google analytics, e a que eles disponibilizaram é meme.
Então por enquanto com IMPORTHTML é oque está funcionando pra mim, até achar alguma API utilizavel.

@tuliopascoal
Copy link

@carmodurante Obrigado meu caro. Confirmo que o sistema do TesouroInfo voltou ao normal aqui, e conseguir fazer as alterações necessárias na minhas tabelas.

Enquanto isso, vamos aguardar a situação do bloqueio da CloudFare :(

@cristianoscaranci
Copy link

@carmodurante Obrigado. Se puder, favor me tirar uma dúvida.
Com o =importhtml("https://www.tesouroinfo.com/";"table";4), funcionou trocando as vírgulas por ponto e vírgula.
Tentei fazer o mesmo com o =REGEXREPLACE(QUERY(query(importhtml("https://www.tesouroinfo.com/";"table";4), "select Col5 where Col2 = 'Ipca+ 2045' ", -1), "SELECT * OFFSET 1", 0),"[^\d.]","")*1000
trocando todas as vírgulas por ponto e vírgula e como acima, mesclando. Deu erro em ambas.

@mateusguenter
Copy link

@carmodurante Obrigado. Se puder, favor me tirar uma dúvida. Com o =importhtml("https://www.tesouroinfo.com/";"table";4), funcionou trocando as vírgulas por ponto e vírgula. Tentei fazer o mesmo com o =REGEXREPLACE(QUERY(query(importhtml("https://www.tesouroinfo.com/";"table";4), "select Col5 where Col2 = 'Ipca+ 2045' ", -1), "SELECT * OFFSET 1", 0),"[^\d.]","")*1000 trocando todas as vírgulas por ponto e vírgula e como acima, mesclando. Deu erro em ambas.

Para mim estava a dar erro, mas retirei o REGEXREPLACE e funcionou:
=QUERY(query(importhtml("https://www.tesouroinfo.com/";"table";4); "select Col5 where Col2 = 'Selic 2027' "; -1); "SELECT * OFFSET 1"; 0)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment