feat(route): japanpost improve data parse and arrangement radar(#7269)
This commit is contained in:
parent
192b1ae283
commit
b88e182045
|
|
@ -1733,13 +1733,13 @@
|
|||
'trackings.post': [
|
||||
{
|
||||
title: '郵便・荷物の追跡',
|
||||
docs: 'https://docs.rsshub.app/other.html#ri-ben-you-bian',
|
||||
docs: 'https://docs.rsshub.app/other.html#ri-ben-you-bian-you-bian-zhui-ji-サービス',
|
||||
source: '/services/srv/search/direct',
|
||||
target: (params, url) => {
|
||||
const reqCode = new URL(url).searchParams.get('reqCodeNo1').toUpperCase();
|
||||
const locale = new URL(url).searchParams.get('locale').toLowerCase();
|
||||
if ((reqCode.search(/^(?:\d{12}|[A-Z]{2}\d{9}[A-Z]{2})$/) === 0 && locale === 'ja') || locale === 'en') {
|
||||
return `/japanpost/${reqCode}/${locale}`;
|
||||
if ((reqCode.search(/^(?:\d{11,12}|[A-Z]{2}\d{9}[A-Z]{2})$/) === 0 && locale === 'ja') || locale === 'en') {
|
||||
return `/japanpost/track/${reqCode}/${locale}`;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ Official Website: [https://www.ssm.gov.mo/apps1/PreventWuhanInfection/en.aspx](h
|
|||
|
||||
### Track & Trace Service
|
||||
|
||||
<RouteEn author="tuzi3040" example="/japanpost/EJ123456789JP/en" path="/japanpost/:reqCode/:locale?" :paramsDesc="['Package Number', 'Language, default to japanese `ja`']" radar="1" rssbud="1">
|
||||
<RouteEn author="tuzi3040" example="/japanpost/track/EJ123456789JP/en" path="/japanpost/track/:reqCode/:locale?" :paramsDesc="['Package Number', 'Language, default to japanese `ja`']" radar="1" rssbud="1">
|
||||
|
||||
| Japanese | English |
|
||||
| -------- | ------- |
|
||||
|
|
|
|||
|
|
@ -686,7 +686,7 @@ type 为 all 时,category 参数不支持 cost 和 free
|
|||
|
||||
### 郵便追跡サービス
|
||||
|
||||
<Route author="tuzi3040" example="/japanpost/EJ123456789JP/ja" path="/japanpost/:reqCode/:locale?" :paramsDesc="['运单号', '语言,默认为`ja`']" radar="1" rssbud="1">
|
||||
<Route author="tuzi3040" example="/japanpost/track/EJ123456789JP/ja" path="/japanpost/track/:reqCode/:locale?" :paramsDesc="['运单号', '语言,默认为`ja`']" radar="1" rssbud="1">
|
||||
|
||||
| 日语 | 英语 |
|
||||
| ---- | ---- |
|
||||
|
|
|
|||
|
|
@ -2082,7 +2082,7 @@ router.get('/leboncoin/ad/:query', require('./routes/leboncoin/ad.js'));
|
|||
router.get('/dhl/:id', require('./routes/dhl/shipment-tracking'));
|
||||
|
||||
// Japanpost
|
||||
router.get('/japanpost/:reqCode/:locale?', require('./routes/japanpost/index'));
|
||||
router.get('/japanpost/track/:reqCode/:locale?', require('./routes/japanpost/track'));
|
||||
|
||||
// 中华人民共和国商务部
|
||||
router.get('/mofcom/article/:suffix', require('./routes/mofcom/article'));
|
||||
|
|
|
|||
|
|
@ -1,67 +0,0 @@
|
|||
const got = require('@/utils/got');
|
||||
const cheerio = require('cheerio');
|
||||
const utils = require('./utils');
|
||||
|
||||
const baseTitle = '日本郵便';
|
||||
const baseUrl = 'https://trackings.post.japanpost.jp/services/srv/search/direct?';
|
||||
|
||||
const util = new utils();
|
||||
util.expandEven();
|
||||
util.expandReverse();
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const reqCode = ctx.params.reqCode;
|
||||
const reqReqCode = 'reqCodeNo1=' + reqCode;
|
||||
let locale;
|
||||
switch (ctx.params.locale) {
|
||||
case 'ja':
|
||||
locale = 'ja';
|
||||
break;
|
||||
case 'en':
|
||||
locale = 'en';
|
||||
break;
|
||||
default:
|
||||
locale = 'ja';
|
||||
}
|
||||
const reqLocale = '&locale=' + locale;
|
||||
const link = baseUrl + reqReqCode + reqLocale;
|
||||
|
||||
const response = await got({
|
||||
method: 'get',
|
||||
url: link,
|
||||
});
|
||||
|
||||
const $ = cheerio.load(response.data);
|
||||
const list = $('.tableType01').eq(1).find('tr').slice(2);
|
||||
|
||||
const listEven = list.even();
|
||||
|
||||
const packageType = $('.tableType01').eq(0).find('tr').eq(1).find('td').eq(1).text();
|
||||
|
||||
ctx.state.data = {
|
||||
title: `${baseTitle} ${packageType} ${reqCode}`,
|
||||
link: link,
|
||||
description: 'Reserved for further development.',
|
||||
item: listEven
|
||||
.reverse()
|
||||
.map((index, item) => {
|
||||
item = $(item);
|
||||
const itemTd = item.find('td');
|
||||
const packageStatus = itemTd.eq(1).text().trim();
|
||||
const packageRegion = itemTd.eq(4).text().trim();
|
||||
const packageOffice = itemTd.eq(3).text().trim();
|
||||
const itemTitle = `${packageStatus} ${packageRegion} ${packageOffice}`;
|
||||
const itemDescription = itemTd.eq(2).text();
|
||||
const itemPubDateText = itemTd.eq(0).text();
|
||||
const itemGuid = util.generateGuid(itemTitle + itemDescription + itemPubDateText);
|
||||
return {
|
||||
title: itemTitle,
|
||||
description: itemDescription,
|
||||
pubDate: new Date(itemPubDateText),
|
||||
link: link,
|
||||
guid: itemGuid.slice(0, 32),
|
||||
};
|
||||
})
|
||||
.get(),
|
||||
};
|
||||
};
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
const got = require('@/utils/got');
|
||||
const cheerio = require('cheerio');
|
||||
const utils = require('./utils');
|
||||
|
||||
let baseTitle = '日本郵便';
|
||||
const baseUrl = 'https://trackings.post.japanpost.jp/services/srv/search/direct?';
|
||||
|
||||
utils.expandEven();
|
||||
utils.expandOdd();
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const reqCode = ctx.params.reqCode;
|
||||
const reqReqCode = 'reqCodeNo1=' + reqCode;
|
||||
|
||||
let locale = 'ja';
|
||||
if (ctx.params.locale === 'en') {
|
||||
locale = 'en';
|
||||
baseTitle = 'Japanpost';
|
||||
}
|
||||
const reqLocale = '&locale=' + locale;
|
||||
|
||||
const link = baseUrl + reqReqCode + reqLocale;
|
||||
|
||||
const response = await got({
|
||||
method: 'get',
|
||||
url: link,
|
||||
});
|
||||
|
||||
const $ = cheerio.load(response.data);
|
||||
const list = $('.tableType01').eq(1).find('tr').slice(2);
|
||||
const officeList = $('.tableType03').eq(0).find('tr').slice(1);
|
||||
|
||||
if (!list.length) {
|
||||
const resErrorText = $('.tableType01').eq(0).find('tr').eq(2).find('td').eq(1).text().trim();
|
||||
throw new Error(resErrorText);
|
||||
}
|
||||
|
||||
const listEven = list.even();
|
||||
const listOdd = list.odd();
|
||||
|
||||
const packageType = $('.tableType01').eq(0).find('tr').eq(1).find('td').eq(1).text().trim();
|
||||
|
||||
let lastItemTimeStamp;
|
||||
let tz;
|
||||
|
||||
ctx.state.data = {
|
||||
title: `${baseTitle} ${packageType} ${reqCode}`,
|
||||
link: link,
|
||||
description: `${baseTitle} ${packageType} ${reqCode}`,
|
||||
language: locale,
|
||||
item: listEven
|
||||
.map((index, item) => {
|
||||
const itemTd = $(item).find('td');
|
||||
const packageStatus = itemTd.eq(1).text().trim();
|
||||
const packageRegion = itemTd.eq(4).text().trim();
|
||||
const packageOffice = itemTd.eq(3).text().trim();
|
||||
const packageOfficeZipCode = listOdd.eq(index).find('td').eq(0).text().trim();
|
||||
const itemTitle = `${packageStatus} ${packageOffice} ${packageRegion}`;
|
||||
const packageTrackRecord = itemTd.eq(2).text().trim();
|
||||
let itemDescription = `${packageStatus}<br>`;
|
||||
itemDescription += packageTrackRecord ? `${packageTrackRecord}<br>` : '';
|
||||
itemDescription += packageOfficeZipCode ? `${packageOfficeZipCode} ` : '';
|
||||
itemDescription += packageOffice ? `${packageOffice} ` : '';
|
||||
itemDescription += `${packageRegion}`;
|
||||
|
||||
if (index === 0) {
|
||||
if (officeList.length) {
|
||||
const officeItemList = officeList
|
||||
.map((i, e) => {
|
||||
const eTd = $(e).find('td');
|
||||
let officeItem = eTd.eq(0).text().trim();
|
||||
officeItem += ` ${eTd.eq(1).html().trim()}`;
|
||||
officeItem += ` ${eTd.eq(2).html().trim()}`;
|
||||
return officeItem;
|
||||
})
|
||||
.get();
|
||||
itemDescription += '<br>';
|
||||
for (const i of officeItemList) {
|
||||
itemDescription += `<br>${i}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const itemPubDateText = itemTd.eq(0).text().trim();
|
||||
const itemGuid = utils.generateGuid(itemTitle + itemDescription + itemPubDateText);
|
||||
|
||||
let thisItemTimeStamp;
|
||||
[thisItemTimeStamp, tz] = utils.parseDatetime(itemPubDateText, packageOffice, packageRegion, tz, locale);
|
||||
if (lastItemTimeStamp) {
|
||||
if (thisItemTimeStamp <= lastItemTimeStamp) {
|
||||
thisItemTimeStamp = lastItemTimeStamp + 1000;
|
||||
}
|
||||
}
|
||||
lastItemTimeStamp = thisItemTimeStamp;
|
||||
|
||||
return {
|
||||
title: itemTitle,
|
||||
description: itemDescription,
|
||||
pubDate: new Date(thisItemTimeStamp),
|
||||
link: link,
|
||||
guid: itemGuid.slice(0, 32),
|
||||
};
|
||||
})
|
||||
.get(),
|
||||
};
|
||||
};
|
||||
|
|
@ -1,8 +1,17 @@
|
|||
const cheerio = require('cheerio');
|
||||
const crypto = require('crypto');
|
||||
|
||||
function utils() {
|
||||
this.expandOdd = function () {
|
||||
const cityTimezones = require('city-timezones');
|
||||
const dayjs = require('dayjs');
|
||||
const customParseFormat = require('dayjs/plugin/customParseFormat');
|
||||
const utc = require('dayjs/plugin/utc');
|
||||
const timezone = require('dayjs/plugin/timezone');
|
||||
dayjs.extend(customParseFormat);
|
||||
dayjs.extend(utc);
|
||||
dayjs.extend(timezone);
|
||||
|
||||
const utils = {
|
||||
expandOdd: () => {
|
||||
cheerio.prototype.odd = function () {
|
||||
const odds = [];
|
||||
this.each(function (index, item) {
|
||||
|
|
@ -12,9 +21,8 @@ function utils() {
|
|||
});
|
||||
return cheerio(odds);
|
||||
};
|
||||
};
|
||||
|
||||
this.expandEven = function () {
|
||||
},
|
||||
expandEven: () => {
|
||||
cheerio.prototype.even = function () {
|
||||
const evens = [];
|
||||
this.each(function (index, item) {
|
||||
|
|
@ -24,9 +32,8 @@ function utils() {
|
|||
});
|
||||
return cheerio(evens);
|
||||
};
|
||||
};
|
||||
|
||||
this.expandReverse = function () {
|
||||
},
|
||||
expandReverse: () => {
|
||||
cheerio.prototype.reverse = function () {
|
||||
const reverses = [];
|
||||
this.each(function (index, item) {
|
||||
|
|
@ -35,14 +42,53 @@ function utils() {
|
|||
reverses.reverse();
|
||||
return cheerio(reverses);
|
||||
};
|
||||
};
|
||||
|
||||
this.generateGuid = function (t) {
|
||||
},
|
||||
generateGuid: (t) => {
|
||||
const hash = crypto.createHash('sha512');
|
||||
hash.update(t);
|
||||
const r = hash.digest('hex').toUpperCase();
|
||||
return r;
|
||||
};
|
||||
}
|
||||
},
|
||||
parseDatetime: (t, o, r, tz, l) => {
|
||||
const formatJaDate = 'YYYY/MM/DD';
|
||||
const formatJaDateTime = 'YYYY/MM/DD HH:mm';
|
||||
const formatEnDate = 'MM/DD/YYYY';
|
||||
const formatEnDateTime = 'MM/DD/YYYY HH:mm';
|
||||
let customFormat;
|
||||
|
||||
switch (l) {
|
||||
case 'ja':
|
||||
customFormat = dayjs(t, formatJaDate, true).isValid() ? formatJaDate : dayjs(t, formatJaDateTime, true).isValid() ? formatJaDateTime : undefined;
|
||||
break;
|
||||
case 'en':
|
||||
customFormat = dayjs(t, formatEnDate, true).isValid() ? formatEnDate : dayjs(t, formatEnDateTime, true).isValid() ? formatEnDateTime : undefined;
|
||||
break;
|
||||
}
|
||||
if (!customFormat) {
|
||||
return [new Date(t).getTime(), tz];
|
||||
}
|
||||
|
||||
if (o) {
|
||||
if (o.indexOf('郵便局') !== -1) {
|
||||
tz = 'Asia/Tokyo';
|
||||
} else {
|
||||
const oS = o.replace(' EMS', '').replace(' INT', '');
|
||||
try {
|
||||
try {
|
||||
tz = cityTimezones.lookupViaCity(oS)[0].timezone;
|
||||
} catch {
|
||||
tz = cityTimezones.lookupViaCity(r)[0].timezone;
|
||||
}
|
||||
} catch {
|
||||
// empty
|
||||
}
|
||||
}
|
||||
}
|
||||
return [
|
||||
dayjs.tz(t, customFormat, tz).valueOf(),
|
||||
tz,
|
||||
];
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = utils;
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@
|
|||
"bbcodejs": "0.0.4",
|
||||
"cheerio": "1.0.0-rc.3",
|
||||
"chrono-node": "2.2.6",
|
||||
"city-timezones": "^1.2.0",
|
||||
"crypto-js": "4.0.0",
|
||||
"currency-symbol-map": "4.0.4",
|
||||
"dayjs": "1.10.3",
|
||||
|
|
|
|||
Loading…
Reference in New Issue