cc
cei-crawler
npm i cei-crawler
cc

cei-crawler

Crawler para pegar dados do CEI 🤑💰💸

by João Menighin

3.0.1 (see all)License:MITTypeScript:DefinitelyTyped
npm i cei-crawler
Readme

cei-crawler 💸

Travis badge Coveralls badge License: MIT

Crawler para ler dados do Canal Eletrônico do Investidor

Importante (Versão sem captcha)

Para versão antiga do CEI que não possui captcha obrigatório (por enquanto), utilize o cei-crawler v2

Descrição

Essa versão do crawler varre a Nova Area Logada do CEI. Essa área logada possui um captcha para que seja feito o login e por isso existem algumas estratégias de implementação para fazer o bypass do mesmo. Além disso, o CEI agora possui uma API. Tudo que o crawler faz basicamente é encapsular as chamadas dessas API's. Portanto, o formato dos dados vem direto do CEI, não há transformação feita por esse crawler. Sendo assim, caso haja algo estranho ou errado nos dados retornados, provavelmente é o próprio CEI que está retornando.

O cei-crawler utiliza as seguintes dependências:

  • puppeteer-core para navegar com o browser e resolver o captcha.
  • axios para fazer as requisições http.

Caso o cei-crawler tenha te ajudado e você queira fazer alguma doação pra me ajudar a mantê-lo, utilize o QR code abaixo :) Mande também seu nome e usuário do GitHub (caso tenha) que eu coloco aqui no README. Obrigado!

PIX: joao.menighin@gmail.com

Criei o cei-crawler para um projeto de acompanhamento de investimentos. Caso esteja procurando algo nesse sentido, confira o Stoincs!

Instalação

Basta instalar utilizando o NPM:

npm install --save cei-crawler

Utilização

Crie uma instância do CeiCrawler passando os parametros necessários e invoque o método desejado:

let ceiCrawler = new CeiCrawler('username', 'password', {/* options */});
ceiCrawler.login(); // Login é opcional, pois antes de cada método o cei-crawler irá verificar se já esta logado.
                    // A vantagem em realizar o login em um passo diferente é para o tratamento de erros

Login & Captcha

A nova área logada do CEI possui validação por captcha. Não há forma simples de resolver e por isso algumas estratégias de resolução são implementadas. Essas estratégias são setadas na instanciação do crawler, com o objeto de options. As disponíveis são:

raw-token

Nessa estratégia de login, não é necessário informar usuário e senha porém deve-se informar o token e o cache-guid do usuário logado. Essa estratégia é útil caso você possua algum serviço terceiro que faça o login no CEI e pegue o token pra você.

Exemplo:

const ceiCrawler = new CeiCrawler(_, _, { 
    loginOptions: {
        strategy: 'raw-token'
    },
    auth: {
        "cache-guid": "cache-guid do usuário logado",
        token: "JWT do usuário logado"
    }
});

const values = await ceiCrawler.getConsolidatedValues();

user-resolve

Nessa estratégia de login, o usuário será promptado para fazer o login ele mesmo em uma janela de browser que será aberta. O crawler tenta preencher usuário e senha para você de forma que o input manual é somente para resolução do Captcha. Uma vez feito o login, o crawler trata de pegar as credencias e seguir adiante chamando os métodos. Nas opções do login deve-se também ser informado um caminho do browser para que o puppeteer o controle.

Exemplo:

const ceiCrawler = new CeiCrawler('user', 'password', { 
    loginOptions: {
        strategy: 'user-resolve',
        browserPath: 'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe'
    }
});

const values = await ceiCrawler.getConsolidatedValues();

Métodos disponíveis

getConsolidatedValues()

Retorna os investimentos consolidados num valor total e divididos em subcategorias

let consolidated = await ceiCrawler.getConsolidatedValues();

Resultado:

{
  "total": 10000,
  "subTotais": [
    {
      "categoriaProduto": "Renda Variável",
      "totalPosicao": 5000,
      "percentual": 0.5
    },
    {
      "categoriaProduto": "Tesouro Direto",
      "totalPosicao": 5000,
      "percentual": 0.5
    }
  ]
}

getPosition(date, page)

Retorna as posições da tela "Posição" em todas as categorias de investimentos.

ParâmetroTipoDefaultDescrição
dateDtenullData da posição. Caso seja passado null ou nenhum valor, será usada a ultima data de processamento do CEI.
pageNumber1Paginação dos dados. Por default retorna a primeira página.
let position = await ceiCrawler.getPosition();

Resultado:

{
  "paginaAtual": 1,
  "totalPaginas": 1,
  "itens": [
    {
      "categoriaProduto": "RendaVariavel",
      "tipoProduto": "Acao",
      "descricaoTipoProduto": "Ações",
      "posicoes": [
        {
          "id": "gfw2455-8a79-4127-990b-587sa37",
          "temBloqueio": false,
          "instituicao": "INTER DISTRIBUIDORA DE TITULOS E VALORES MOBILIARIOS LTDA",
          "quantidade": 100,
          "valorAtualizado": 2377.00,
          "precoFechamento": 23.77,
          "produto": "BIDI4 - BANCO INTER S.A.",
          "tipo": "PN",
          "marcacoes": [],
          "codigoNegociacao": "BIDI4",
          "documentoInstituicao": "358743882",
          "existeLogotipo": false,
          "disponivel": 100,
          "documento": "48377283492",
          "razaoSocial": "BANCO INTER S.A.",
          "codigoIsin": "BRBRHEU2",
          "distribuicao": "114",
          "escriturador": "BANCO BRADESCO S/A",
          "valorBruto": 0
        }
      ],
      "totalPosicao": 2377.00,
      "totalItemsPagina": 1
    },
    {
      "categoriaProduto": "TesouroDireto",
      "tipoProduto": "TesouroDireto",
      "descricaoTipoProduto": "Tesouro Direto",
      "posicoes": [
        {
          "id": "hfd4564-e70a-4596-93fd-987654dvbhw",
          "temBloqueio": false,
          "instituicao": "XP INVESTIMENTOS CCTVM S/A",
          "quantidade": 1.01,
          "valorAtualizado": 2200,
          "vencimento": "2024-08-15T00:00:00",
          "valorAplicado": 2000,
          "produto": "Tesouro IPCA+ 2024",
          "marcacoes": [],
          "documentoInstituicao": "8573938583",
          "existeLogotipo": false,
          "indexador": "IPCA",
          "disponivel": 1.01,
          "documento": "7658493485",
          "codigoIsin": "VRSIYASU@",
          "valorBruto": 2038,
          "nomeTituloPublico": "Tesouro IPCA+ 2024",
          "valorLiquido": 29882,
          "percRentabilidadeContratada": 4.71
        }
      ],
      "totalPosicao": 22000,
      "totalItemsPagina": 5
    }
  ],
  "detalheStatusCode": 0,
  "excecoes": []
}

getPositionDetail(id, category, type)

Retorna o detalhe de uma posição da lista anterior.

ParâmetroTipoDefaultDescrição
idStringundefinedUUID da posição. Foi observado que o UUID de uma mesma posição pode mudar ao longo do tempo e essa requisição falhar após pegar a lista com o getPosition()
categoryStringundefinedCategoria da posição informada no método getPosition().
typeStringundefinedTipo da posição informada no método getPosition().
let positionDetail = await ceiCrawler.getPositionDetail('gfw2455-8a79-4127-990b-587sa37', 'RendaVariavel', 'Acao');

Resultado:

{
  "codigoIsin": "BRBIDIACNPR0",
  "distribuicao": "114",
  "empresa": "BANCO INTER S.A.",
  "escriturador": "BANCO BRADESCO S/A",
  "codigoNegociacao": "BIDI4",
  "disponivel": 100,
  "indisponivel": 0,
  "quantidade": 100,
  "marcacoes": [],
  "possuiMarcacoes": false,
  "existeLogotipo": false,
  "documentoInstituicao": "358743882"
}

getAccountStatement(startDate, endDate, page)

Retorna as movimentações da aba "Movimentação" no CEI.

ParâmetroTipoDefaultDescrição
startDateDatenullData de inicio para trazer as movimentações. Caso null, será utilizada a ultima data de processamento do CEI menos 1 mês.
endDateDatenullData fim para trazer as movimentações. Caso null, será utilizada a ultima data de processamento do CEI.
pageNumber1Paginação dos dados. Por default retorna a primeira página.
let accountStatement = await ceiCrawler.getAccountStatement();

Resultado:

{
  "paginaAtual": 1,
  "totalPaginas": 2,
  "itens": [
    {
      "data": "2021-08-02T00:00:00",
      "movimentacoes": [
        {
          "tipoOperacao": "Credito",
          "tipoMovimentacao": "Juros Sobre Capital Próprio",
          "nomeProduto": "BIDI4 - BANCO INTER S.A.",
          "instituicao": "INTER DISTRIBUIDORA DE TITULOS E VALORES MOBILIARIOS LTDA",
          "quantidade": 100,
          "valorOperacao": 1.49,
          "precoUnitario": 0.01
        }
      ],
      "totalItemsPagina": 1
    },
    {
      "data": "2021-07-30T00:00:00",
      "movimentacoes": [
        {
          "tipoOperacao": "Debito",
          "tipoMovimentacao": "Transferência",
          "nomeProduto": "ALZR11 - ALIANZA TRUST RENDA IMOBILIARIA FDO INV IMOB",
          "instituicao": "RICO INVESTIMENTOS - GRUPO XP",
          "quantidade": 5
        },
        {
          "tipoOperacao": "Credito",
          "tipoMovimentacao": "Transferência",
          "nomeProduto": "ALZR11 - ALIANZA TRUST RENDA IMOBILIARIA FDO INV IMOB",
          "instituicao": "XP INVESTIMENTOS CCTVM S/A",
          "quantidade": 5
        }
      ],
      "totalItemsPagina": 2
    }
  ],
  "detalheStatusCode": 0,
  "excecoes": []
}

getIpos(date, page)

Retorna os IPOs da tela "Ofertas Públicas" no CEI.

ParâmetroTipoDefaultDescrição
dateDatenullData de consulta. Caso seja passado null ou nenhum valor, será usada a ultima data de processamento do CEI.
pageNumber1Paginação dos dados. Por default retorna a primeira página.
let ipos = await ceiCrawler.getIPOs();

Resultado:

{
  "paginaAtual": 1,
  "totalPaginas": 1,
  "itens": [
    {
      "data": "2021-07-27T00:00:00",
      "ofertasPublicas": [
        {
          "id": "c80c8b8f-62d2-4b48-b242-b0f310cfa95a",
          "dataLiquidacao": "2021-07-27T00:00:00",
          "nomeEmpresa": "INVESTO ETF MSCI US TECHNOLOGY FDO INV IND INV EXT",
          "tipoOferta": "OUTRO",
          "oferta": "ETF INVESTO",
          "nomeInstituicao": "INTER DISTRIBUIDORA DE TITULOS E VALORES MOBILIARIOS LTDA",
          "quantidade": 10,
          "preco": 10,
          "valor": 100
        }
      ],
      "totalItemsPagina": 1
    }
  ],
  "detalheStatusCode": 0,
  "excecoes": []
}

getIPODetail(id)

Retorna o detalhe de uma posição da lista anterior.

ParâmetroTipoDefaultDescrição
idStringundefinedUUID do IPO. Foi observado que o UUID de um mesmo IPO pode mudar ao longo do tempo e essa requisição falhar após pegar a lista com o getIPOs()
let ipoDetail = await ceiCrawler.getIPODetail('c80c8b8f-62d2-4b48-b242-b0f310cfa95a');

Resultado:

{
  "nomeProduto": "OUTRO INVESTO ETF MSCI US TECHNOLOGY FDO INV IND INV EXT",
  "nomeInstituicao": "INTER DISTRIBUIDORA DE TITULOS E VALORES MOBILIARIOS LTDA",
  "ativo": {
    "nomeEmpresa": "INVESTO ETF MSCI US TECHNOLOGY FDO INV IND INV EXT",
    "ticker": "USTK11L",
    "oferta": "ETF INVESTO",
    "codigoIsin": "BRUSTKCTF007"
  },
  "valores": {
    "preco": 10,
    "precoMaximo": 0,
    "valor": 100
  },
  "reserva": {
    "modalidade": "Compra/Integralização de cotas do ETF INVESTO",
    "quantidade": 10,
    "valor": 0
  },
  "quantidadeAlocada": 10,
  "dataLiquidacao": "2021-07-27T00:00:00"
}

getStockTransactions(startDate, endDate, page)

Retorna os dados da aba "Negociação" no CEI.

ParâmetroTipoDefaultDescrição
startDateDatenullData de inicio para trazer as negociações. Caso null, será utilizada a ultima data de processamento do CEI menos 1 mês.
endDateDatenullData fim para trazer as negociações. Caso null, será utilizada a ultima data de processamento do CEI.
pageNumber1Paginação dos dados. Por default retorna a primeira página.
let stockTransactions = await ceiCrawler.getStockTransactions();

Resultado:

{
  "paginaAtual": 1,
  "totalPaginas": 1,
  "itens": [
    {
      "data": "2021-07-20T00:00:00",
      "totalCompra": 1000,
      "totalVenda": 0,
      "negociacaoAtivos": [
        {
          "tipoMovimentacao": "Compra",
          "mercado": "Mercado à Vista",
          "nomeInstituicao": "RICO INVESTIMENTOS - GRUPO XP",
          "codigoNegociacao": "PNVL3",
          "quantidade": 100,
          "preco": 10.00,
          "valor": 1000.00
        }
      ],
      "totalItemsPagina": 1
    }
  ],
  "detalheStatusCode": 0,
  "excecoes": []
}

getProvisionedEvents(date, page)

Retorna os eventos da tela "Eventos Provisionados" no CEI.

ParâmetroTipoDefaultDescrição
dateDatenullData de consulta. Caso seja passado null ou nenhum valor, será usada a ultima data de processamento do CEI.
pageNumber1Paginação dos dados. Por default retorna a primeira página.
let events = await ceiCrawler.getProvisionedEvents();

Resultado:

{
  "totalValorLiquido": 8.62,
  "paginaAtual": 1,
  "totalPaginas": 1,
  "itens": [
    {
      "id": "9cc87804-f9ae-143a-acfb-c953f38c72dd",
      "produto": "WEGE3        - WEG S/A",
      "tipo": "ON",
      "tipoEvento": "JUROS SOBRE CAPITAL PRÓPRIO",
      "previsaoPagamento": "2021-08-11T00:00:00",
      "instituicao": "INTER DISTRIBUIDORA DE TITULOS E VALORES MOBILIARIOS LTDA",
      "quantidade": 300,
      "precoUnitario": 0.03,
      "valorLiquido": 8.62,
      "totalItemsPagina": 1
    }
  ],
  "detalheStatusCode": 0,
  "excecoes": []
}

getProvisionedEventDetail(id)

Retorna o detalhe de um evento provisionado da lista anterior.

ParâmetroTipoDefaultDescrição
idStringundefinedUUID do evento. Foi observado que o UUID de um mesmo evento pode mudar ao longo do tempo e essa requisição falhar após pegar a lista com o getProvisionedEvents()
let eventDetail = await ceiCrawler.getProvisionedEventDetail('9cc87804-f9ae-143a-acfb-c953f38c72dd');

Resultado:

{
  "codigoNegociacao": "WEGE3",
  "codigoIsin": "BRWEGEACNOR0",
  "distribuicao": "202",
  "escriturador": "BANCO BRADESCO S/A",
  "empresa": "WEG S/A",
  "dataAprovacao": "2021-03-23T00:00:00",
  "dataAtualizacao": "2021-03-30T00:00:00",
  "dataEx": "2021-03-29T00:00:00",
  "impostoRenda": 15,
  "valorImpostoRenda": 1.52,
  "valorBruto": 10.14,
  "disponivel": 100,
  "indisponivel": 0,
  "produto": "WEGE3        - WEG S/A",
  "tipo": "ON",
  "tipoEvento": "JUROS SOBRE CAPITAL PRÓPRIO",
  "previsaoPagamento": "2021-08-11T00:00:00",
  "quantidade": 100,
  "precoUnitario": 0.03,
  "valorLiquido": 8.62
}

Opções

Na criação de um CeiCrawler é possivel especificar alguns valores para o parâmetro options que modificam a forma que o crawler funciona. As opções são:

PropriedadeTipoDefaultDescrição
debugBooleanfalseSe true, printa mensages de debug no log.
loginOptions.strategyStringuser-resolveEstratégia utilizada no login. Veja Login & Captcha para mais informações.
loginOptions.browserPathStringundefinedCaminho para o executavél do browser que será controlado para resolucao do Captcha. Veja Login & Captcha para mais informações.
auth.tokenStringundefinedToken JWT do usuário logado no CEI. Utilizado quando a estratégia de login é raw-token
auth.cache-guidStringundefinedUUID da sessão do usuário logado no CEI. Utilizado quando a estratégia de login é raw-token

Exemplo:

const ceiCrawlerOptions = {
    debug: true,
    loginOptions: {
      strategy: 'user-resolve',
      browserPath: 'path/to/browser.exe'
    }
};

let ceiCrawler = new CeiCrawler('username', 'password', ceiCrawlerOptions);

Error Handling

O CEI Crawler possui um exceção própria, CeiCrawlerError, que é lançada em alguns cenários. Essa exceção possui um atributo type para te direcionar no tratamento:

typeDescrição
UNAUTHORIZEDLançada quando uma request retorna 401. Isso pode significar que o token utiliza é inválido ou expirou.
BAD_REQUESTLançada quando uma requisição falha por má formação. Pode ser um parâmetro errado, uma data menor que o limite minimo, etc.
TOO_MANY_REQUESTSO CEI faz throttling de requisições. Se ao usar o crawler você fizer muitas requisições rapidamente esse erro pode ser retornado
INVALID_LOGIN_STRATEGYLançada quando informada uma estratégia de login inválida.

Exemplo de como fazer um bom tratamento de erros:

const CeiCrawler = require('cei-crawler');
const { CeiErrorTypes } = require('cei-crawler')

const ceiCrawler = new CeiCrawler('usuario', 'senha', { navigationTimeout: 20000 });

try {
  const positions = ceiCrawler.getPositions();
} catch (err) {
  if (err.name === 'CeiCrawlerError') {
    if (err.type === CeiErrorTypes.UNAUTHORIZED)
      // Handle unauthrozied
    else if (err.type === CeiErrorTypes.TOO_MANY_REQUESTS)
      // Handle too many requests
    // else ...
  } else {
    // Handle generic errors
  }
}

Licença

MIT

No alternatives found
No tutorials found
Add a tutorial
No dependencies found

Rate & Review

100
No reviews found
Be the first to rate