Last active
July 20, 2021 06:14
-
-
Save freddiefujiwara/e5e1a0264918111799858267f9a97792 to your computer and use it in GitHub Desktop.
Crawl hellocycling.jp and provide API
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"timeZone": "Asia/Tokyo", | |
"dependencies": { | |
}, | |
"webapp": { | |
"access": "ANYONE_ANONYMOUS", | |
"executeAs": "USER_DEPLOYING" | |
}, | |
"exceptionLogging": "STACKDRIVER", | |
"runtimeVersion": "V8" | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// for API https://script.google.com/macros/s/AKfycbwetE7pJEr-3RJp-nZv1G7s8cqI8BjVtBK0fuyKA7MzldqKCZyo/exec?code={bike code}&callback={callback} | |
function doGet(e) { | |
const sheet = SpreadsheetApp.openById(PropertiesService.getScriptProperties().getProperty("SHEET_ID")); | |
// ports info from spreadsheet | |
const ports = sheet.getSheetByName("ports"); | |
const ports_values = ports.getDataRange().getValues(); | |
const ports_headers = ports_values.shift(); | |
// bikes info from spreadsheet | |
const bikes = sheet.getSheetByName("bikes"); | |
const bikes_values = bikes.getDataRange().getValues(); | |
const bikes_headers = bikes_values.shift(); | |
// bikes info from spreadsheet | |
const history = sheet.getSheetByName("history"); | |
const history_values = history.getDataRange().getValues(); | |
const history_headers = history_values.shift(); | |
//utility functions | |
const getPorts = (row) => { | |
let port = {}; | |
row.map((column, index) => { | |
port[ports_headers[index]] = column; | |
}); | |
return port; | |
}; | |
const getBikes = (row) => { | |
let bike = {}; | |
row.map((column, index) => { | |
bike[bikes_headers[index]] = column; | |
}); | |
return bike; | |
}; | |
let result = { | |
status: "error" | |
}; | |
if (e.parameter.id) { // get data for specific port ex) "?id=3023" | |
// get id from URL parameter | |
const id = e.parameter.id; | |
result.port = ports_values.filter((v) => { | |
return v[0] == id; | |
}).map(getPorts).shift(); | |
//skip if port can't find | |
if (result.port) { | |
result.bikes = bikes_values.filter((value) => { | |
return value[11] == id; | |
}).map(getBikes); | |
const bikes_ids = result.bikes.map((value) => value.code); | |
result.related_bikes = history_values.filter((value) => { | |
return value[1] == id || value[2] == id; | |
}).map((value) => { | |
return value[0]; | |
}).filter(function(elem, index, self) { | |
return self.indexOf(elem) === index; | |
}).filter((value) => { | |
return !bikes_ids.includes(value) | |
}).map((value) => { | |
return bikes_values.filter((v) => { | |
return v[0] === value; | |
}).map(getBikes).shift(); | |
}).filter((value) => value); | |
result.status = "success"; | |
} | |
} else if (e.parameter.code) { // get data for specific bike ex) "?code=A0695" | |
// get code from URL parameter | |
const code = e.parameter.code; | |
// find out taret bike of "code" | |
const bike = bikes_values.filter((value) => { | |
return value[0] === code; | |
}).map(getBikes).shift(); | |
//skip if bike can't find | |
if (bike) { | |
// collect "code"'s history | |
const port_history = history_values.filter((value) => { | |
return value[0] === code; | |
}).map((value) => { | |
return [value[1], value[2]]; | |
}).flat().concat([bike.latest_port_id]).filter((value, index, self) => { | |
return self[index - 1] !== value; | |
}).map((value) => { | |
return ports_values.filter((v) => { | |
return v[0] === value; | |
}).map(getPorts).shift(); | |
}).filter((value) => value); | |
// create result | |
result.bike = bike; | |
result.history = port_history; | |
result.history_map = "https://www.google.com/maps/dir/" + port_history.map((value) => { | |
return value.lat + "," + value.lng; | |
}).flat().join("/"); | |
result.status = "success"; | |
} | |
} else { // get whole data of ports | |
result.ports = ports_values.map(getPorts); | |
result.status = "success"; | |
} | |
// generate output | |
const output = ContentService.createTextOutput(); | |
if (e.parameter.callback === undefined) { | |
output.setMimeType(ContentService.MimeType.JSON); | |
output.setContent(JSON.stringify(result)); | |
} else { | |
output.setMimeType(ContentService.MimeType.JAVASCRIPT); | |
output.setContent(e.parameter.callback + "&&" + e.parameter.callback + "(" + JSON.stringify(result) + ");"); | |
} | |
return output; | |
} | |
// For interval crawler | |
function myFunction() { | |
const data = JSON.parse(UrlFetchApp.fetch("https://www.hellocycling.jp/app/top/port_json") | |
.getContentText()); | |
// ports info from spreadsheet | |
const sheet = SpreadsheetApp.openById(PropertiesService.getScriptProperties().getProperty("SHEET_ID")); | |
const ports = sheet.getSheetByName("ports"); | |
const ports_last = ports.getLastRow(); | |
const ports_values = ports.getDataRange().getValues(); | |
const ports_headers = ports_values.shift(); | |
const ports_new = []; | |
// bikes info from spreadsheet | |
const bikes = sheet.getSheetByName("bikes"); | |
const bikes_last = bikes.getLastRow(); | |
const bikes_values = bikes.getDataRange().getValues(); | |
const bikes_headers = bikes_values.shift(); | |
bikes_headers.pop(); | |
const bikes_new = []; | |
// history info from spreadsheet | |
const history = sheet.getSheetByName("history"); | |
const history_last = history.getLastRow(); | |
const history_values = history.getDataRange().getValues(); | |
const history_headers = history_values.shift(); | |
// analyze data from json | |
for (let [ports_key, ports_value] of Object.entries(data)) { | |
let ports_row = []; | |
ports_headers.forEach((header) => { | |
ports_row.push(ports_value[header]); | |
}); | |
ports_new.push(ports_row); | |
for (let [bikes_key, bikes_value] of Object.entries(ports_value.bike_list)) { | |
let bikes_row = []; | |
bikes_headers.forEach((header) => { | |
bikes_row.push(bikes_value[header]); | |
}); | |
const diff = bikes_values.filter((value) => { | |
return value[0] == bikes_value.code && value[11] != ports_value.id | |
}); | |
if (diff.length === 1) { | |
history_values.push([diff[0][0], diff[0][11], ports_value.id, new Date()]); | |
} | |
bikes_row.push(ports_value.id); | |
bikes_new.push(bikes_row); | |
} | |
} | |
// write "ports" | |
ports.getRange(2, 1, ports_last, ports_headers.length).clearContent(); | |
ports.getRange(2, 1, ports_new.length, ports_headers.length).setValues(ports_new); | |
// write "bikes" | |
bikes.getRange(2, 1, bikes_last, bikes_headers.length + 1).clearContent(); | |
bikes.getRange(2, 1, bikes_new.length, bikes_headers.length + 1).setValues(bikes_new); | |
// write "history" | |
history.getRange(2, 1, history_last, history_headers.length).clearContent(); | |
history.getRange(2, 1, history_values.length, history_headers.length).setValues(history_values); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment