Skip to content

Commit

Permalink
feat(project): update site of scrapping
Browse files Browse the repository at this point in the history
  • Loading branch information
lgaticaq committed Apr 3, 2018
1 parent d06eee1 commit c63784d
Show file tree
Hide file tree
Showing 3 changed files with 247 additions and 77 deletions.
151 changes: 126 additions & 25 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,44 +1,128 @@
'use strict'

const http = require('http')
const querystring = require('querystring')
const cheerio = require('cheerio')

module.exports = number => {
/**
* The built http.Agent object.
* @external "http.Agent"
* @see https://nodejs.org/api/http.html#http_class_http_agent
*/

/**
* Get JSESSIONID from response headers
* @param external:"http.Agent" agent
* @returns {Promise<String>} JSESSIONID
*/
const getSessionId = agent => {
return new Promise((resolve, reject) => {
const options = {
hostname: 'www.metrosantiago.cl',
hostname: 'pocae.tstgo.cl',
port: 80,
path: `/contents/guia-viajero/includes/consultarTarjeta/${number}`,
method: 'GET'
path: '/PortalCAE-WAR-MODULE/',
method: 'GET',
agent
}
const req = http.request(options, res => {
const { statusCode } = res
let err
if (statusCode !== 200) {
err = new Error(`Request Failed. Status Code: ${statusCode}`)
}
if (err) {
res.resume()
return reject(err)
}
res.resume()
try {
resolve(res.headers['set-cookie'][0].split('; ')[0].split('=')[1])
} catch (err) {
reject(new Error('Error al obtener el balance'))
}
})
req.on('error', err => reject(err))
req.end()
})
}

/**
* The built http.Agent object.
* @external "http.Agent"
* @see https://nodejs.org/api/http.html#http_class_http_agent
*/

/**
* Get balance of bip card
* @param external:"http.Agent" agent
* @param {String|Number} number Bip number card
* @param {String} sessionId JSESSIONID
* @returns {Promise<Object>} Object with number, message, balance and date
*/
const getBalance = (agent, number, sessionId) => {
return new Promise((resolve, reject) => {
const data = querystring.stringify({
accion: 6,
NumDistribuidor: 99,
NomUsuario: 'usuInternet',
NomHost: 'AFT',
NomDominio: 'aft.cl',
Trx: '',
RutUsuario: 0,
NumTarjeta: number,
bloqueable: ''
})
const options = {
hostname: 'pocae.tstgo.cl',
port: 80,
path: '/PortalCAE-WAR-MODULE/SesionPortalServlet',
method: 'POST',
headers: {
Connection: 'keep-alive',
Pragma: 'no-cache',
'Cache-Control': 'no-cache',
Origin: 'http://pocae.tstgo.cl',
'Upgrade-Insecure-Requests': '1',
'Content-Type': 'application/x-www-form-urlencoded',
'User-Agent':
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3381.0 Safari/537.36',
Accept:
'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
Referer: 'http://pocae.tstgo.cl/PortalCAE-WAR-MODULE/',
'Accept-Encoding': 'gzip, deflate',
'Accept-Language': 'es-419,es;q=0.9',
Cookie: `JSESSIONID=${sessionId}`
},
agent
}
const req = http.request(options, res => {
if (res.statusCode !== 200) {
reject(new Error(`Request Failed. Status Code: ${res.statusCode}`))
} else {
res.setEncoding('utf8')
let rawData = ''
res.on('data', chunk => {
rawData += chunk
})
const rawData = []
res.on('data', chunk => rawData.push(chunk))
res.on('end', () => {
try {
const data = JSON.parse(rawData)
if (data.length === 0) reject(Error('Not found'))
if (data[0].estado !== 0) reject(Error(data[0].mensaje))
const balance = parseInt(data[1].saldo || 0, 10)
let date = null
if (data[1].fecha) {
const iso = data[1].fecha.replace(
/(\d{2})\/(\d{2})\/(\d{4}) (\d{2}):(\d{2})/,
'$3-$2-$1T$4:$5:00-03:00'
)
date = new Date(iso)
const data = Buffer.concat(rawData).toString()
const $ = cheerio.load(data)
let [number, message, balance, date] = $('table')
.find('td[bgcolor="#B9D2EC"]')
.map((index, element) => $(element).text())
.get()
if (balance === '---' || typeof balance === 'undefined') {
reject(new Error('Esta tarjeta no se puede cargar'))
}
let valid = false
if (message === 'Contrato Activo') {
message = 'Tarjeta Valida'
valid = true
}
resolve({
number: number,
balance: balance,
date: date,
message: data[0].mensaje,
valid: data[1].salida
number,
message,
valid,
balance: parseInt(balance.replace(/\D/g, ''), 10),
date: new Date(date)
})
} catch (err) {
reject(err)
Expand All @@ -47,6 +131,23 @@ module.exports = number => {
}
})
req.on('error', err => reject(err))
req.write(data)
req.end()
})
}

/**
* Get balance of bip card
* @param {String|Number} number Bip number card
* @returns {Promise<Object>} Object with number, message, balance and date
*/
module.exports = async number => {
const agent = new http.Agent({ keepAlive: true })
try {
const sessionId = await getSessionId(agent)
const balance = await getBalance(agent, number, sessionId)
return balance
} catch (err) {
throw err
}
}
159 changes: 107 additions & 52 deletions test/test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
'use strict'

const expect = require('chai').expect
const { describe, it, beforeEach } = require('mocha')
const { expect } = require('chai')
const path = require('path')
const nock = require('nock')

const lib = require('../src')
Expand All @@ -9,95 +11,148 @@ describe('bip', () => {
describe('valid', () => {
beforeEach(() => {
nock.disableNetConnect()
nock('http://www.metrosantiago.cl')
.get('/contents/guia-viajero/includes/consultarTarjeta/11111111')
.reply(200, [
{ estado: 0, mensaje: 'Tarjeta Valida' },
{
salida: true,
tarjeta: '11111111',
saldo: '1180',
fecha: '02/01/2016 20:59'
}
])
nock('http://pocae.tstgo.cl')
.get('/PortalCAE-WAR-MODULE/')
.reply(200, 'ok', {
'set-cookie': [
'JSESSIONID=517B19EEA6C1122EC934BDB624CFA413; Path=/PortalCAE-WAR-MODULE'
]
})
nock('http://pocae.tstgo.cl')
.post('/PortalCAE-WAR-MODULE/SesionPortalServlet')
.replyWithFile(200, path.join(__dirname, 'valid.html'))
})

it('should return a balance data', done => {
lib('11111111').then(data => {
expect(data.number).to.eql('11111111')
expect(data.balance).to.eql(1180)
expect(data.date).to.be.a('date')
expect(data.message).to.eql('Tarjeta Valida')
expect(data.valid).to.eql(true)
done()
})
it('should return a balance data', async () => {
const data = await lib('11111111')
expect(data.number).to.eql('11111111')
expect(data.balance).to.eql(1180)
expect(data.date).to.be.a('date')
expect(data.message).to.eql('Tarjeta Valida')
expect(data.valid).to.eql(true)
})
})

describe('wrong status', () => {
beforeEach(() => {
nock.disableNetConnect()
nock('http://www.metrosantiago.cl')
.get('/contents/guia-viajero/includes/consultarTarjeta/11111111')
.reply(200, [
{ estado: 1, mensaje: 'Esta tarjeta no se puede cargar' },
{ salida: false, tarjeta: '11111111' }
])
nock('http://pocae.tstgo.cl')
.get('/PortalCAE-WAR-MODULE/')
.reply(200, 'ok', {
'set-cookie': [
'JSESSIONID=517B19EEA6C1122EC934BDB624CFA413; Path=/PortalCAE-WAR-MODULE'
]
})
nock('http://pocae.tstgo.cl')
.post('/PortalCAE-WAR-MODULE/SesionPortalServlet')
.reply(200, '<table></table>')
})

it('should return an error', done => {
lib('11111111').catch(err => {
it('should return an error', async () => {
try {
await lib('11111111')
} catch (err) {
expect(err.message).to.eql('Esta tarjeta no se puede cargar')
done()
})
}
})
})

describe('wrong status code', () => {
beforeEach(() => {
nock.disableNetConnect()
nock('http://www.metrosantiago.cl')
.get('/contents/guia-viajero/includes/consultarTarjeta/11111111')
nock('http://pocae.tstgo.cl')
.get('/PortalCAE-WAR-MODULE/')
.reply(200, 'ok', {
'set-cookie': [
'JSESSIONID=517B19EEA6C1122EC934BDB624CFA413; Path=/PortalCAE-WAR-MODULE'
]
})
nock('http://pocae.tstgo.cl')
.post('/PortalCAE-WAR-MODULE/SesionPortalServlet')
.reply(301)
})

it('should return an error', done => {
lib('11111111').catch(err => {
it('should return an error', async () => {
try {
await lib('11111111')
} catch (err) {
expect(err.message).to.eql('Request Failed. Status Code: 301')
done()
})
}
})
})

describe('wrong data', () => {
describe('server error', () => {
beforeEach(() => {
nock.disableNetConnect()
nock('http://pocae.tstgo.cl')
.get('/PortalCAE-WAR-MODULE/')
.reply(200, 'ok', {
'set-cookie': [
'JSESSIONID=517B19EEA6C1122EC934BDB624CFA413; Path=/PortalCAE-WAR-MODULE'
]
})
nock('http://pocae.tstgo.cl')
.post('/PortalCAE-WAR-MODULE/SesionPortalServlet')
.replyWithError('Server error')
})

it('should return an error', async () => {
try {
await lib('11111111')
} catch (err) {
expect(err.message).to.eql('Server error')
}
})
})

describe('wrong jssesionid', () => {
beforeEach(() => {
nock.disableNetConnect()
nock('http://www.metrosantiago.cl')
.get('/contents/guia-viajero/includes/consultarTarjeta/11111111')
.reply(200, [])
nock('http://pocae.tstgo.cl')
.get('/PortalCAE-WAR-MODULE/')
.reply(200, 'ok')
})

it('should return an error', done => {
lib('11111111').catch(err => {
expect(err.message).to.eql('Not found')
done()
})
it('should return an error', async () => {
try {
await lib('11111111')
} catch (err) {
expect(err.message).to.eql('Error al obtener el balance')
}
})
})

describe('wrong status code in jssesionid', () => {
beforeEach(() => {
nock.disableNetConnect()
nock('http://pocae.tstgo.cl')
.get('/PortalCAE-WAR-MODULE/')
.reply(301)
})

it('should return an error in jssesionid', async () => {
try {
await lib('11111111')
} catch (err) {
expect(err.message).to.eql('Request Failed. Status Code: 301')
}
})
})

describe('server error', () => {
beforeEach(() => {
nock.disableNetConnect()
nock('http://www.metrosantiago.cl')
.get('/contents/guia-viajero/includes/consultarTarjeta/11111111')
nock('http://pocae.tstgo.cl')
.get('/PortalCAE-WAR-MODULE/')
.replyWithError('Server error')
})

it('should return an error', done => {
lib('11111111').catch(err => {
it('should return an error', async () => {
try {
await lib('11111111')
} catch (err) {
expect(err.message).to.eql('Server error')
done()
})
}
})
})
})

0 comments on commit c63784d

Please sign in to comment.