feat(route): japanpost improve data parse and arrangement radar(#7269)

This commit is contained in:
tuzi3040 2021-06-11 03:23:36 +08:00 committed by GitHub
parent 192b1ae283
commit b88e182045
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 172 additions and 86 deletions

View File

@ -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}`;
}
},
},

View File

@ -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 |
| -------- | ------- |

View File

@ -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">
| 日语 | 英语 |
| ---- | ---- |

View File

@ -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'));

View File

@ -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(),
};
};

View File

@ -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(),
};
};

View File

@ -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;

View File

@ -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",