├── .gitignore
├── .prettierrc
├── .eslintrc.json
├── lib
├── helper.js
└── parser.js
├── index.js
├── package.json
├── README.md
├── LICENSE
└── yarn.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "printWidth": 100,
3 | "singleQuote": true
4 | }
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": ["airbnb", "prettier"],
3 | "plugins": ["prettier"],
4 | "rules": {
5 | "prettier/prettier": ["error"]
6 | }
7 | }
--------------------------------------------------------------------------------
/lib/helper.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | stringBetween: (input, start, end) => {
3 | return input.match(new RegExp(`${start}([\\S\\s]*?)${end}`))[1];
4 | },
5 | tdValue: input => {
6 | return input.match(/
]*?>(.*?)<\/td>/g);
7 | },
8 | removeHtml: input => {
9 | return input.replace(/<[^>]*>?/gm, '');
10 | },
11 | toNumber: input => {
12 | return Number(input.replace(/,/g, ''));
13 | }
14 | };
15 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | const parser = require('./lib/parser');
2 |
3 | module.exports = {
4 | getBalance: async (username, password) => {
5 | try {
6 | const IP = await parser.getIP();
7 | await parser.login(username, password, IP);
8 | await parser.openSettlementMenu();
9 | const balance = await parser.balance();
10 | await parser.logout();
11 | return balance;
12 | } catch (err) {
13 | await parser.logout();
14 | throw err;
15 | }
16 | },
17 |
18 | getSettlement: async (username, password) => {
19 | try {
20 | const IP = await parser.getIP();
21 | await parser.login(username, password, IP);
22 | await parser.openSettlementMenu();
23 | const settlement = await parser.settlement();
24 | await parser.logout();
25 | return settlement;
26 | } catch (err) {
27 | await parser.logout();
28 | throw err;
29 | }
30 | }
31 | };
32 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "nodejs-bca-scraper",
3 | "version": "1.0.0",
4 | "description": "Plugin untuk mendapatkan saldo terakhir dan mutasi rekening BCA via klikbca tanpa menggunakan official API dari Bank BCA.",
5 | "keywords": [
6 | "bankbca",
7 | "klikbca",
8 | "bca",
9 | "saldo",
10 | "mutasi",
11 | "rekening"
12 | ],
13 | "main": "index.js",
14 | "author": "Achmad Apriady ",
15 | "license": "MIT",
16 | "dependencies": {
17 | "moment": "^2.24.0",
18 | "request": "^2.88.0",
19 | "request-promise-native": "^1.0.7"
20 | },
21 | "devDependencies": {
22 | "eslint": "5.3.0",
23 | "eslint-config-airbnb": "17.1.0",
24 | "eslint-config-prettier": "^6.0.0",
25 | "eslint-plugin-import": "^2.14.0",
26 | "eslint-plugin-jsx-a11y": "^6.1.1",
27 | "eslint-plugin-prettier": "^3.1.0",
28 | "eslint-plugin-react": "^7.11.0",
29 | "prettier": "^1.18.2"
30 | }
31 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # nodejs-bca-scraper
2 |
3 | Plugin untuk membantu anda mendapatkan informasi saldo terakhir rekening BCA anda serta mutasi rekening BCA anda pada hari itu melalui KlikBCA.
4 |
5 | ## Cara Install
6 |
7 | ```bash
8 | npm install --save nodejs-bca-scraper
9 | ```
10 |
11 | atau
12 |
13 | ```bash
14 | yarn add nodejs-bca-scraper
15 | ```
16 |
17 | ## Penggunaan
18 |
19 | ```javascript
20 | const bca = require('nodejs-bca-scraper');
21 | ```
22 |
23 | ### Cek Saldo Terakhir
24 |
25 | ```javascript
26 | bca
27 | .getBalance(USERNAME, PASSWORD)
28 | .then(res => {
29 | console.log('saldo ', res);
30 | })
31 | .catch(err => {
32 | console.log('error ', err);
33 | });
34 | ```
35 |
36 | ### Cek Settlement Pada Hari Itu
37 |
38 | ```javascript
39 | bca
40 | .getSettlement(USERNAME, PASSWORD)
41 | .then(res => {
42 | console.log('settlement ', res);
43 | })
44 | .catch(err => {
45 | console.log('error ', err);
46 | });
47 | ```
48 |
49 | # License
50 |
51 | MIT
52 |
53 | # Author
54 |
55 | [Achmad Apriady](mailto:achmad.apriady@gmail.com)
56 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Achmad Apriady
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/lib/parser.js:
--------------------------------------------------------------------------------
1 | const request = require('request-promise-native');
2 | const moment = require('moment');
3 | const { stringBetween, tdValue, removeHtml, toNumber } = require('./helper');
4 |
5 | const j = request.jar();
6 | const rp = request.defaults({
7 | headers: {
8 | 'User-Agent':
9 | 'Mozilla/5.0 (Linux; U; Android 2.3.7; en-us; Nexus One Build/GRK39F) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1'
10 | },
11 | jar: j
12 | });
13 |
14 | module.exports = {
15 | getIP: async () => {
16 | const ipify = await request({
17 | uri: 'https://api.ipify.org/?format=json',
18 | json: true
19 | });
20 | return ipify.ip;
21 | },
22 |
23 | login: (username, password, ip) => {
24 | const options = {
25 | method: 'POST',
26 | uri: 'https://m.klikbca.com/authentication.do',
27 | form: {
28 | 'value(user_id)': username,
29 | 'value(pswd)': password,
30 | 'value(Submit)': 'LOGIN',
31 | 'value(actions)': 'login',
32 | 'value(user_ip)': ip,
33 | user_ip: ip,
34 | 'value(mobile)': true,
35 | mobile: true
36 | },
37 | headers: {
38 | Referer: 'https://m.klikbca.com/login.jsp'
39 | }
40 | };
41 | return rp(options)
42 | .then(result => {
43 | const success = result.includes('MENU UTAMA');
44 | if (!success) {
45 | let err = stringBetween(result, "var err='", "';");
46 | err = err || '';
47 | throw Error(err);
48 | }
49 | return true;
50 | })
51 | .catch(err => {
52 | throw err.message;
53 | });
54 | },
55 |
56 | openSettlementMenu: () => {
57 | const options = {
58 | method: 'POST',
59 | uri: 'https://m.klikbca.com/accountstmt.do?value(actions)=menu',
60 | headers: {
61 | Referer: 'https://m.klikbca.com/authentication.do'
62 | }
63 | };
64 | return rp(options);
65 | },
66 |
67 | balance: () => {
68 | const options = {
69 | method: 'POST',
70 | uri: 'https://m.klikbca.com/balanceinquiry.do',
71 | headers: {
72 | Referer: 'https://m.klikbca.com/accountstmt.do?value(actions)=menu'
73 | }
74 | };
75 | return rp(options)
76 | .then(result => {
77 | return {
78 | rekening: stringBetween(result, "| ", ' | '),
79 | saldo: toNumber(
80 | stringBetween(result, "", ' | ')
81 | )
82 | };
83 | })
84 | .catch(err => {
85 | throw err.message;
86 | });
87 | },
88 |
89 | settlement: async () => {
90 | const options = {
91 | method: 'POST',
92 | uri: 'https://m.klikbca.com/accountstmt.do?value(actions)=acct_stmt',
93 | headers: {
94 | Referer: 'https://m.klikbca.com/accountstmt.do?value(actions)=menu'
95 | }
96 | };
97 | try {
98 | const now = moment();
99 | const date = now.format('DD');
100 | const month = now.format('MM');
101 | const year = now.format('YYYY');
102 |
103 | await rp(options);
104 | options.uri = 'https://m.klikbca.com/accountstmt.do?value(actions)=acctstmtview';
105 | options.headers.Referer = 'https://m.klikbca.com/accountstmt.do?value(actions)=acct_stmt';
106 | options.form = {
107 | r1: 1,
108 | 'value(D1)': 0,
109 | 'value(startDt)': date,
110 | 'value(startMt)': month,
111 | 'value(startYr)': year,
112 | 'value(endDt)': date,
113 | 'value(endMt)': month,
114 | 'value(endYr)': year
115 | };
116 | const result = await rp(options);
117 | const cleanStmt = [];
118 | if (!result.includes('TIDAK ADA TRANSAKSI')) {
119 | let stmt = stringBetween(result, 'KETERANGAN', ' |