Skip to content

Commit

Permalink
create a new method to get dividends data
Browse files Browse the repository at this point in the history
  • Loading branch information
thiagodds committed Apr 1, 2020
1 parent f588d18 commit 3d373d8
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 2 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ node_modules
package-lock.json
.vscode
.nyc_output
coverage
coverage
.env
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"devDependencies": {
"ava": "^2.4.0",
"coveralls": "^3.0.9",
"nyc": "^15.0.0"
"nyc": "^15.0.0",
"dotenv": "^8.2.0"
}
}
9 changes: 9 additions & 0 deletions src/lib/CeiCrawler.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const puppeteer = require('puppeteer');
const StockHistoryCrawler = require('./StockHistoryCrawler');
const DividendsCrawler = require('./DividendsCrawler');
const typedefs = require("./typedefs");
const PuppeteerUtils = require('./PuppeteerUtils');

Expand Down Expand Up @@ -86,6 +87,14 @@ class CeiCrawler {
return await StockHistoryCrawler.getStockHistory(this._page, this.options, startDate, endDate);
}

/**
* @returns {typedefs.DividendData} - List of available Dividends information
*/
async getDividends() {
await this._login();
return await DividendsCrawler.getDividends(this._page);
}

}

module.exports = CeiCrawler;
65 changes: 65 additions & 0 deletions src/lib/DividendsCrawler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
const typedefs = require("./typedefs");

const PAGE = {
URL: 'https://cei.b3.com.br/CEI_Responsivo/ConsultarProventos.aspx',
SEARCH_BUTTON: '#ctl00_ContentPlaceHolder1_btnConsultar',
SEARCH_WAITFOR: "#ctl00_ContentPlaceHolder1_lblAtualizadoEm",
TABLE_CLASS_NAME: 'responsive',
}

const DIVIDENDS_TABLE_HEADERS = [
{prop: 'stock', type: 'string'},
{prop: 'stockType', type: 'string'},
{prop: 'code', type: 'string'},
{prop: 'date', type: 'date'},
{prop: 'type', type: 'string'},
{prop: 'quantity', type: 'int'},
{prop: 'factor', type: 'int'},
{prop: 'grossValue', type: 'float'},
{prop: 'netValue', type: 'float'}
];

class DividendsCrawler {

/**
* Gets dividends data available on CEI page.
* @param {puppeteer.Page} page - Logged page to work with
* @returns {typedefs.DividendData} - List of available Dividends information
*/
static async getDividends(page) {
await page.goto(PAGE.URL);
await page.click(PAGE.SEARCH_BUTTON);
await page.waitFor(PAGE.SEARCH_WAITFOR);

/* istanbul ignore next */
const dividendsData = await page.evaluate((selector, headers) => {
let rows = [];
const dividendsTables = Array.from(document.getElementsByClassName(selector));

// Helper function
const parseValue = (value, type) => {
if (type === 'string') return value;
if (type === 'int') return parseInt(value.replace('.', ''));
if (type === 'float') return parseFloat(value.replace('.', '').replace(',', '.'));
if (type === 'date') return new Date(value.split('/').reverse()).getTime();
}

// If there are multiple institutions, there will be a table for each one.
for (const table of dividendsTables) {
const data = Array.from(table.rows).slice(1, table.rows.length -1)
.map(row => Array.from(row.cells).reduce((p, c, i) => {
p[headers[i].prop] = parseValue(c.innerText, headers[i].type)
return p;
}));

rows = rows.concat(data);
}

return rows;
}, PAGE.TABLE_CLASS_NAME, DIVIDENDS_TABLE_HEADERS);

return dividendsData.map(d => ({...d, date: new Date(d.date)}));
}
}

module.exports = DividendsCrawler;
12 changes: 12 additions & 0 deletions src/lib/typedefs.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,16 @@ const puppeteer = require('puppeteer');
* @memberof typdefs
*/

/**
* @typedef DividendData
* @property {String} stockType - Type of Stock (ON, PN, CI)
* @property {String} code - The code of the stock
* @property {Date} date - Dividend payment date (can be a future date for scheduled payment)
* @property {String} type - Dividend type (Rendimento, JPC, Dividendo)
* @property {Number} quantity - Quantity of stock dividend is based
* @property {Number} factor - Multiply factor for each stock unit
* @property {Number} grossValue - Dividend value before taxes
* @property {Number} netValue - Dividend value after taxes
* @memberof typdefs
*/
exports.unused = {};
9 changes: 9 additions & 0 deletions test/app.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ const CeiCrawler = require('../src/app')
const fs = require('fs')
const typedefs = require("../src/lib/typedefs");

const dotenv = require('dotenv');

dotenv.config();

test.before(t => {
if (!process.env.CEI_USERNAME || !process.env.CEI_PASSWORD) {
throw Error('You should set environment variables CEI_USERNAME and CEI_PASSWORD in order to run tests');
Expand Down Expand Up @@ -65,6 +69,11 @@ test.serial('stock-history-invalid-dates-with-cap-on', async t => {
t.true(result.length > 0);
});

test.serial('dividends', async t => {
const result = await t.context.ceiCrawler.getDividends();
t.true(result.length > 0);
});

test.serial('login-fail', async t => {
await t.throwsAsync(async () => {
const wrongCeiCrawler = new CeiCrawler('1234', 'invalidPassword');
Expand Down

0 comments on commit 3d373d8

Please sign in to comment.