Created
March 6, 2025 12:58
-
-
Save cocoabox/f52e5ca9d5d6f416a87228447c7975f9 to your computer and use it in GitHub Desktop.
クロネコヤマトの配達状況をJSONで出力する
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
// | |
// 使い方: node kuroneko-yamato-tracking.js [伝票番号] | jq | |
// OR : const kuroneko_yamato_tracking = reuqire('./kuroneko_yamato_tracking'); | |
// const tracking_info_dict = await kuroneko_yamato_tracking('0000-0000-0000'); | |
// | |
const cheerio = require('cheerio'); | |
async function kuroneko_yamato_tracking(tracking_number) { | |
tracking_number = tracking_number.trim().replaceAll(/[\-]/g, ''); | |
try { | |
const body = (new URLSearchParams({ | |
number00: '1', | |
number01: tracking_number | |
})).toString(); | |
const response = await fetch('https://toi.kuronekoyamato.co.jp/cgi-bin/tneko', { | |
method: 'POST', | |
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, | |
body, | |
}); | |
const html = await response.text(); | |
const $ = cheerio.load(html); | |
let out = {}; | |
$('div.parts-tracking-invoice-block').each((_, block) => { | |
const report_title = $(block).find('.tracking-invoice-block-title')?.first()?.text().trim(); | |
const tracking_num = report_title?.match(/件目:(.*)$/)?.[1]; | |
const state_title = $(block).find('.tracking-invoice-block-state-title')?.first()?.text().trim(); | |
if (state_title === '伝票番号誤り') { | |
throw {error:'not-found'}; | |
} | |
const state_summary = $(block).find('.tracking-invoice-block-state-summary')?.first()?.text().trim(); | |
const state_note = $(block).find('.tracking-invoice-block-state-note')?.first()?.text().trim(); | |
out = {...out, report_title, tracking_num, state_title, state_summary, state_note}; | |
const extra_info = []; | |
$(block).find('.tracking-invoice-block-summary > ul > li').each( (_, li) => { | |
const key = $(li).find('.item').first().text(); | |
const key_str = key.match(/^(.*?):$/)?.[1] ?? key; | |
const val = $(li).find('.data').first().text(); | |
extra_info.push({key: key_str, val}); | |
if (key_str === 'お届け予定日時') { | |
date_mat = val.match(/^([0-9]+)\/([0-9]+)$/); | |
if (date_mat) { | |
const eta_date_elements = { | |
month : parseInt(date_mat[1]), | |
date : parseInt(date_mat[2]), | |
}; | |
out = {...out, eta_date_elements}; | |
} | |
} | |
} ); | |
out = {...out, extra_info}; | |
const events = []; | |
$(block).find('.tracking-invoice-block-detail > ol > li').each((_, li) => { | |
const event = $(li).find('.item')?.first()?.text(); | |
const date = $(li).find('.date')?.first()?.text(); | |
const date_mat = date.match(/^(([0-9]+)年)?([0-9]+)月([0-9]+)日 ([0-9]+):([0-9]+)/); | |
const date_elements = { | |
year: date_mat[2] ? parseInt(date_mat[2]) : null, | |
month: date_mat[3] ? parseInt(date_mat[3]) : null, | |
date: date_mat[4] ? parseInt(date_mat[4]) : null, | |
hour: date_mat[5] ? parseInt(date_mat[5]) : null, | |
minute: date_mat[6] ? parseInt(date_mat[6]) : null, | |
}; | |
const where = $(li).find('.name')?.first()?.text(); | |
if (event && date && where) | |
events.push({event, date, date_elements, where}); | |
}); | |
out = {...out, events: events.reverse()}; | |
}); | |
return out; | |
} catch (error) { | |
console.error('Error:', error); | |
throw error; | |
} | |
} | |
module.exports = kuroneko_yamato_tracking; | |
if (require.main === module) { | |
const args = process.argv.slice(2); | |
if (args.length !== 1) { | |
console.warn('Usage: node . [TRACKING_NUMBER]'); | |
return process.exit(1); | |
} | |
const tracking_num = args[0]; | |
kuroneko_yamato_tracking(tracking_num).then(out => { | |
console.log(JSON.stringify(out)); | |
}).catch(error => { console.log(JSON.stringify(error)); process.exit(1); }); | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment