mirror of
https://github.com/DIYgod/RSSHub.git
synced 2025-12-06 05:03:44 +08:00
feat: add support for BUPT portal (#3290)
This commit is contained in:
@@ -104,6 +104,16 @@ pageClass: routes
|
|||||||
|
|
||||||
<Route author="RicardoMing" example="/bupt/grs" path="/bupt/grs" />
|
<Route author="RicardoMing" example="/bupt/grs" path="/bupt/grs" />
|
||||||
|
|
||||||
|
### 信息门户
|
||||||
|
|
||||||
|
<Route author="RicardoMing" example="/bupt/portal" path="/bupt/portal" />
|
||||||
|
|
||||||
|
::: warning 注意
|
||||||
|
信息门户的通知需要通过统一身份认证后才能获取,因此需要在校园网或校园 VPN 环境下自建。
|
||||||
|
|
||||||
|
设置环境变量: `BUPT_USERNAME` 用户名为学号, `BUPT_PASSWORD` 统一身份认证的密码。
|
||||||
|
:::
|
||||||
|
|
||||||
## 常州大学
|
## 常州大学
|
||||||
|
|
||||||
### 教务处
|
### 教务处
|
||||||
|
|||||||
@@ -98,6 +98,10 @@ const calculateValue = () => {
|
|||||||
chuiniu: {
|
chuiniu: {
|
||||||
member: envs.CHUINIU_MEMBER,
|
member: envs.CHUINIU_MEMBER,
|
||||||
},
|
},
|
||||||
|
bupt: {
|
||||||
|
username: envs.BUPT_USERNAME,
|
||||||
|
password: envs.BUPT_PASSWORD,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
calculateValue();
|
calculateValue();
|
||||||
|
|||||||
@@ -1309,6 +1309,7 @@ router.get('/21caijing/channel/:name', require('./routes/21caijing/channel'));
|
|||||||
// 北京邮电大学
|
// 北京邮电大学
|
||||||
router.get('/bupt/yz/:type', require('./routes/universities/bupt/yz'));
|
router.get('/bupt/yz/:type', require('./routes/universities/bupt/yz'));
|
||||||
router.get('/bupt/grs', require('./routes/universities/bupt/grs'));
|
router.get('/bupt/grs', require('./routes/universities/bupt/grs'));
|
||||||
|
router.get('/bupt/portal', require('./routes/universities/bupt/portal'));
|
||||||
|
|
||||||
// VOCUS 方格子
|
// VOCUS 方格子
|
||||||
router.get('/vocus/publication/:id', require('./routes/vocus/publication'));
|
router.get('/vocus/publication/:id', require('./routes/vocus/publication'));
|
||||||
|
|||||||
172
lib/routes/universities/bupt/portal.js
Normal file
172
lib/routes/universities/bupt/portal.js
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
const config = require('@/config').value;
|
||||||
|
const got = require('@/utils/got');
|
||||||
|
const cheerio = require('cheerio');
|
||||||
|
const url = require('url');
|
||||||
|
|
||||||
|
function isToday(time) {
|
||||||
|
return new Date().getTime() - new Date(time).getTime() < 86400000;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPubDate(time) {
|
||||||
|
return isToday(time) ? new Date() : new Date(time + ' 08:00:00');
|
||||||
|
}
|
||||||
|
|
||||||
|
const base = 'http://my.bupt.edu.cn';
|
||||||
|
const sourceTimezoneOffset = -8;
|
||||||
|
|
||||||
|
let portalCookie = null;
|
||||||
|
let authCookie = null;
|
||||||
|
let castgc = null;
|
||||||
|
|
||||||
|
module.exports = async (ctx) => {
|
||||||
|
if (!config.bupt || !config.bupt.username || !config.bupt.password) {
|
||||||
|
throw 'BUPT Portal RSS is disabled due to the lack of <a href="https://docs.rsshub.app/university.html#bei-jing-you-dian-da-xue">relevant config</a>';
|
||||||
|
}
|
||||||
|
|
||||||
|
const reqUrl = url.resolve(base, '/index.portal?.pn=p1778');
|
||||||
|
let reqRes = await got({
|
||||||
|
method: 'get',
|
||||||
|
followRedirect: false,
|
||||||
|
url: reqUrl,
|
||||||
|
headers: {
|
||||||
|
cookie: portalCookie,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Login
|
||||||
|
if (reqRes.statusCode === 302) {
|
||||||
|
if (reqRes.headers['set-cookie'] === undefined) {
|
||||||
|
portalCookie = null;
|
||||||
|
throw 'Can not obtain portalCookie';
|
||||||
|
}
|
||||||
|
portalCookie = reqRes.headers['set-cookie'].toString().match(/JSESSIONID=.{37}/)[0];
|
||||||
|
|
||||||
|
const authRes = await got({
|
||||||
|
method: 'get',
|
||||||
|
followRedirect: false,
|
||||||
|
url: reqRes.headers.location,
|
||||||
|
headers: {
|
||||||
|
cookie: `${authCookie}; ${castgc}`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (authRes.statusCode === 200) {
|
||||||
|
authCookie = authRes.headers['set-cookie'].toString().match(/JSESSIONID=.{37}/)[0];
|
||||||
|
const authPage = cheerio.load(authRes.data);
|
||||||
|
|
||||||
|
const loginRes = await got({
|
||||||
|
method: 'post',
|
||||||
|
followRedirect: false,
|
||||||
|
url: reqRes.headers.location,
|
||||||
|
headers: {
|
||||||
|
cookie: authCookie,
|
||||||
|
referer: reqRes.headers.location,
|
||||||
|
},
|
||||||
|
form: true,
|
||||||
|
data: {
|
||||||
|
username: config.bupt.username,
|
||||||
|
password: config.bupt.password,
|
||||||
|
lt: authPage('[name=lt]').attr('value'),
|
||||||
|
execution: authPage('[name=execution]').attr('value'),
|
||||||
|
_eventId: authPage('[name=_eventId]').attr('value'),
|
||||||
|
rmShown: 1,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (loginRes.headers['set-cookie'] === undefined) {
|
||||||
|
authCookie = null;
|
||||||
|
castgc = null;
|
||||||
|
throw 'Can not obtain castgc';
|
||||||
|
}
|
||||||
|
castgc = loginRes.headers['set-cookie'].toString().match(/CASTGC=.{85}/)[0];
|
||||||
|
|
||||||
|
await got({
|
||||||
|
method: 'get',
|
||||||
|
followRedirect: false,
|
||||||
|
url: loginRes.headers.location,
|
||||||
|
headers: {
|
||||||
|
cookie: portalCookie,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else if (authRes.statusCode === 302) {
|
||||||
|
await got({
|
||||||
|
method: 'get',
|
||||||
|
followRedirect: false,
|
||||||
|
url: authRes.headers.location,
|
||||||
|
headers: {
|
||||||
|
cookie: portalCookie,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
throw 'BUPT auth login failed';
|
||||||
|
}
|
||||||
|
|
||||||
|
reqRes = await got({
|
||||||
|
method: 'get',
|
||||||
|
followRedirect: false,
|
||||||
|
url: reqUrl,
|
||||||
|
headers: {
|
||||||
|
cookie: portalCookie,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const $ = cheerio.load(reqRes.data);
|
||||||
|
const list = $('.newslist li').get();
|
||||||
|
const out = await Promise.all(
|
||||||
|
list.map(async (i) => {
|
||||||
|
const item = $(i);
|
||||||
|
const itemUrl = url.resolve(
|
||||||
|
base,
|
||||||
|
$(item)
|
||||||
|
.find('a')
|
||||||
|
.attr('href')
|
||||||
|
);
|
||||||
|
const cache = await ctx.cache.get(itemUrl);
|
||||||
|
if (cache) {
|
||||||
|
return Promise.resolve(JSON.parse(cache));
|
||||||
|
}
|
||||||
|
|
||||||
|
const title = $(item)
|
||||||
|
.find('a')
|
||||||
|
.text();
|
||||||
|
const author = $(item)
|
||||||
|
.find('.author')
|
||||||
|
.text();
|
||||||
|
const time = getPubDate(
|
||||||
|
$(item)
|
||||||
|
.find('.time')
|
||||||
|
.text()
|
||||||
|
);
|
||||||
|
time.setTime(time.getTime() + (sourceTimezoneOffset - time.getTimezoneOffset() / 60) * 60 * 60 * 1000);
|
||||||
|
|
||||||
|
const itemResponse = await got({
|
||||||
|
method: 'get',
|
||||||
|
url: itemUrl,
|
||||||
|
headers: {
|
||||||
|
cookie: portalCookie,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const itemElement = cheerio.load(itemResponse.data);
|
||||||
|
// Remove useless print button
|
||||||
|
itemElement('table.Noprint').remove();
|
||||||
|
const description = itemElement('.singleexpert').html();
|
||||||
|
|
||||||
|
const single = {
|
||||||
|
title: title,
|
||||||
|
author: author,
|
||||||
|
description: description,
|
||||||
|
pubDate: time.toUTCString(),
|
||||||
|
link: itemUrl,
|
||||||
|
guid: itemUrl,
|
||||||
|
};
|
||||||
|
|
||||||
|
ctx.cache.set(itemUrl, JSON.stringify(single));
|
||||||
|
return Promise.resolve(single);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
ctx.state.data = {
|
||||||
|
title: '北京邮电大学信息门户',
|
||||||
|
link: reqUrl,
|
||||||
|
item: out,
|
||||||
|
};
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user