-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
executable file
·250 lines (228 loc) · 8.09 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
const AWS = require('aws-sdk');
const launchChrome = require('@serverless-chrome/lambda');
const CDP = require('chrome-remote-interface');
const puppeteer = require('puppeteer');
const account = require('./account');
exports.handler = async (event, context, callback) => {
context.callbackWaitsForEmptyEventLoop = false;
const query = {
place: '東京',
raceNo: '10',
racerNo: '1',
amount: '100',
};
if (event) {
const inputParams = {
place: event['place'],
raceNo: event['raceNo'],
racerNo: event['racerNo'],
amount: event['amount'],
};
Object.assign(query, inputParams);
}
const amountRemoveTwoDigit = query.amount.replace(/00$/, '');
let slsChrome = null;
let browser = null;
let page = null;
try {
// serverless-chromeを起動し、PuppeteerからWebSocketで接続する
slsChrome = await launchChrome();
browser = await puppeteer.connect({
browserWSEndpoint: (await CDP.Version()).webSocketDebuggerUrl, // eslint-disable-line
});
page = await browser.newPage();
await Promise.all([
// 画面内にないものをクリックしようとするとイベントが発火しないため全画面表示される大きさに設定
page.setViewport({width: 1920, height: 2000}),
page.goto('https://www.ipat.jra.go.jp/'),
]);
if ((await page.$('[name="inetid"]')) === null) {
throw new Error('you can not buy');
}
await page.type('[name="inetid"]', account.INETID);
await Promise.all([
page.click('.button a'),
page.waitForSelector('[name="i"]'),
]);
if ((await page.$('[name="i"]')) === null) {
throw new Error('inetid login error');
}
console.log('inetidを入力してログインしました');
// input login
await page.type('[name="i"]', account.USERID);
await page.type('[name="p"]', account.PASSWORD);
await page.type('[name="r"]', account.PARS);
// submit
await Promise.all([
page.click('.buttonModern a'),
page.waitForNavigation(),
]);
// トップページの前にお知らせがある場合
if (
(await page.$('[ui-sref="bet.basic"]')) === null &&
(await page.$('[ui-sref="home"]')) !== null
) {
await Promise.all([
page.click('[ui-sref="home"]'),
page.waitForSelector('[ui-sref="bet.basic"]'),
]);
}
const betButton = await page.$('[ui-sref="bet.basic"]');
if (betButton === null) {
throw new Error('you can not buy');
}
// 未検証
const betDisabled = await betButton.getProperty('disabled');
if (await betDisabled.jsonValue()) {
throw new Error('you can not buy');
}
await Promise.all([
page.click('[ui-sref="bet.basic"]'),
page.waitForSelector('.place-name'),
]);
// 場所指定
const placeItems = await page.$$('.place-name');
if (placeItems === null) {
throw new Error('login error');
}
console.log('ログインに成功しました');
for (let placeItem of placeItems) {
const placeNameTag = await placeItem.$('span');
const placeNameText = await placeNameTag.getProperty('textContent');
const placeName = await placeNameText.jsonValue();
if (placeName.slice(0, 2) == query.place) {
await Promise.all([
placeItem.click(),
page.waitForSelector('.race-no'),
]);
break;
}
}
// レース指定
const raceItems = await page.$$('.race-no');
if (raceItems === null) {
throw new Error('place error');
}
console.log('開催場を指定しました');
for (let raceItem of raceItems) {
const raceNoTag = await raceItem.$('span');
const raceNoText = await raceNoTag.getProperty('textContent');
const raceNo = await raceNoText.jsonValue();
if (raceNo == query.raceNo) {
await Promise.all([
raceItem.click(),
page.waitForSelector('#bet-basic-type'),
]);
break;
}
}
// 式別指定
const betTypeDropDown = await page.$('#bet-basic-type');
const betItems = await betTypeDropDown.$$('option');
if (betItems === null) {
throw new Error('race error');
}
console.log('レース番号を指定しました');
let betValue;
for (let betItem of betItems) {
const betItemNameLabel = await betItem.getProperty('label');
const betItemName = await betItemNameLabel.jsonValue();
if (betItemName == '複勝') {
const betItemDropDownValue = await betItem.getProperty('value');
betValue = await betItemDropDownValue.jsonValue();
break;
}
}
await Promise.all([
page.select('#bet-basic-type', betValue),
page.waitForSelector('.winplace-table'),
]);
console.log('式別を指定しました');
// 馬番指定
const horseListTable = await page.$('.winplace-table');
const horseNumberItems = await horseListTable.$$('tr');
const mouse = page.mouse;
let isSetRacer = false;
for (let horseNumberItem of horseNumberItems) {
const racerNoElement = await horseNumberItem.$('racer-no');
if (racerNoElement == null) {
continue;
}
const racerNoTag = await racerNoElement.$('span');
const racerNoText = await racerNoTag.getProperty('textContent');
const racerNo = await racerNoText.jsonValue();
if (racerNo == query.racerNo) {
const clickElement = await horseNumberItem.$('.racer-first');
const rect = await clickElement.boundingBox();
await Promise.all([
mouse.move(parseFloat(rect.x + 20), parseFloat(rect.y + 20)),
page.waitFor(1000),
mouse.click(parseFloat(rect.x + 20), parseFloat(rect.y + 20), {
button: 'left',
clickCount: 1,
delay: 0,
}),
page.waitForSelector('.selection-amount'),
]);
isSetRacer = true;
break;
}
}
if (!isSetRacer) {
throw new Error('racer error');
}
console.log('馬番を指定しました');
// 金額指定
const amountSection = await page.$('.selection-amount');
const amountItem = await amountSection.$('input');
await amountItem.focus();
const amountRemoveTwoDigitArray = amountRemoveTwoDigit.split('');
for (let amountRemoveTwoDigitString of amountRemoveTwoDigitArray) {
await amountItem.press(amountRemoveTwoDigitString);
}
page.waitFor(1000);
console.log('金額を指定しました');
// 確定
const setButtonSection = await page.$('.selection-buttons');
const selectionButtons = await setButtonSection.$$('button');
const setButton = selectionButtons[1];
await Promise.all([setButton.click(), page.waitFor(3000)]);
const completeButton = selectionButtons[2];
await Promise.all([completeButton.click(), page.waitFor(3000)]);
console.log('馬券をセットしました');
// 購入
const betConfirmBox = await page.$('#bet-list-top');
const betConfirmBoxTable = await betConfirmBox.$('table');
const betConfirmBoxTableRecords = await betConfirmBoxTable.$$('tr');
const sumInput = await betConfirmBoxTableRecords[4].$('input');
await sumInput.focus();
const ammountArray = query.amount.split('');
for (let ammountString of ammountArray) {
await sumInput.press(ammountString);
}
const purchaceButton = await betConfirmBoxTableRecords[5].$('button');
await Promise.all([
purchaceButton.click(),
page.waitForSelector('error-window'),
]);
const commonConfirmBox = await page.$('error-window');
const commonConfirmFooter = await commonConfirmBox.$('.dialog-footer');
const confirmOkButton = await commonConfirmFooter.$('button');
await Promise.all([confirmOkButton.click(), page.waitFor(3000)]);
console.log('馬券を購入しました');
return callback(null, JSON.stringify({result: 'OK'}));
} catch (err) {
console.error(err);
return callback(null, JSON.stringify({result: 'NG'}));
} finally {
if (page) {
await page.close();
}
if (browser) {
await browser.disconnect();
}
if (slsChrome) {
await slsChrome.kill();
}
}
};