diff --git a/docs/university.md b/docs/university.md
index bdcf3e95b4..7769049117 100644
--- a/docs/university.md
+++ b/docs/university.md
@@ -2313,6 +2313,48 @@ type 列表:
+## 西南石油大学
+
+### 办公网
+
+
+
+| 栏目 | 重要通知公告 | 部门通知公告 | 本周活动 | 学术报告 |
+| ---- | ------------ | ------------ | -------- | -------- |
+| 代码 | zytzgg | bmtzgg | bzhd | xsbg |
+
+
+
+### 教务处
+
+
+
+| 栏目 | 通知公告 | 新闻报道 | 视点声音 |
+| ---- | -------- | -------- | -------- |
+| 代码 | tzgg | xwbd | sdsy |
+
+
+
+### 计算机科学学院
+
+
+
+| 栏目 | 通知公告 | 新闻速递 |
+| ---- | -------- | -------- |
+| 代码 | tzgg | xwsd |
+
+
+
+### 电气信息学院
+
+
+
+| 栏目 | 学院新闻 | 学院通知 |
+| ---- | -------- | -------- |
+| 代码 | 1122 | 1156 |
+
+
+
## 信阳师范学院
### 高等教育自学考试办公室
diff --git a/lib/v2/swpu/bgw.js b/lib/v2/swpu/bgw.js
new file mode 100644
index 0000000000..fcf8876d88
--- /dev/null
+++ b/lib/v2/swpu/bgw.js
@@ -0,0 +1,58 @@
+const { joinUrl } = require('./utils');
+const { parseDate } = require('@/utils/parse-date');
+const cheerio = require('cheerio');
+const got = require('@/utils/got');
+const timezone = require('@/utils/timezone');
+
+module.exports = async (ctx) => {
+ const url = `https://www.swpu.edu.cn/bgw2/${ctx.params.code}.htm`;
+
+ const res = await got.get(url);
+ const $ = cheerio.load(res.data);
+
+ const title = $('.title').text();
+
+ // 获取标题、时间及链接
+ const items = [];
+ $('.notice > ul > li > a').each((i, elem) => {
+ items.push({
+ title: $(elem.children[0]).text(),
+ pubDate: timezone(parseDate($(elem.children[1]).text()), +8),
+ link: joinUrl('https://www.swpu.edu.cn', $(elem).attr('href')), // 实际获得连接 "../info/1312/17891.htm"
+ });
+ });
+
+ // 请求全文
+ const out = await Promise.all(
+ items.map(async (item) => {
+ const $ = await ctx.cache.tryGet(item.link, async () => {
+ const res = await got.get(item.link);
+ return cheerio.load(res.data);
+ });
+
+ if ($('title').text().startsWith('系统提示')) {
+ item.author = '系统';
+ item.description = '无权访问';
+ } else {
+ item.author = '办公网';
+ item.description = $('.v_news_content').html();
+ for (const elem of $('.v_news_content p')) {
+ if ($(elem).css('text-align') === 'right') {
+ item.author = $(elem).text();
+ break;
+ }
+ }
+ }
+
+ return item;
+ })
+ );
+
+ ctx.state.data = {
+ title: `西南石油大学办公网 ${title}`,
+ link: url,
+ description: `西南石油大学办公网 ${title} 列表`,
+ language: 'zh-CN',
+ item: out,
+ };
+};
diff --git a/lib/v2/swpu/dean.js b/lib/v2/swpu/dean.js
new file mode 100644
index 0000000000..369d90b620
--- /dev/null
+++ b/lib/v2/swpu/dean.js
@@ -0,0 +1,58 @@
+const { joinUrl } = require('./utils');
+const { parseDate } = require('@/utils/parse-date');
+const cheerio = require('cheerio');
+const got = require('@/utils/got');
+const timezone = require('@/utils/timezone');
+
+module.exports = async (ctx) => {
+ const url = `https://www.swpu.edu.cn/dean/${ctx.params.code}.htm`;
+
+ const res = await got.get(url);
+ const $ = cheerio.load(res.data);
+
+ const title = $('.r_list > h3').text();
+
+ // 获取标题、时间及链接
+ const items = [];
+ $('.r_list > ul > li').each((i, elem) => {
+ items.push({
+ title: $('label:eq(0)', elem).text().trim(),
+ link: joinUrl('https://www.swpu.edu.cn/dean/', $('a', elem).attr('href')),
+ });
+ });
+
+ // 请求全文
+ const out = await Promise.all(
+ items.map(async (item) => {
+ const $ = await ctx.cache.tryGet(item.link, async () => {
+ const res = await got.get(item.link);
+ return cheerio.load(res.data);
+ });
+
+ if ($('title').text().startsWith('系统提示')) {
+ item.author = '系统';
+ item.description = '无权访问';
+ } else {
+ item.author = '教务处';
+ item.description = $('.v_news_content').html();
+ item.pubDate = timezone(parseDate($('#lbDate').text(), '更新时间:YYYY年MM月DD日'), +8);
+ for (const elem of $('.v_news_content p')) {
+ if ($(elem).css('text-align') === 'right') {
+ item.author = $(elem).text();
+ break;
+ }
+ }
+ }
+
+ return item;
+ })
+ );
+
+ ctx.state.data = {
+ title: `西南石油大学教务处 ${title}`,
+ link: url,
+ description: `西南石油大学教务处 ${title}`,
+ language: 'zh-CN',
+ item: out,
+ };
+};
diff --git a/lib/v2/swpu/dxy.js b/lib/v2/swpu/dxy.js
new file mode 100644
index 0000000000..f95fe77099
--- /dev/null
+++ b/lib/v2/swpu/dxy.js
@@ -0,0 +1,61 @@
+const { joinUrl } = require('./utils');
+const { parseDate } = require('@/utils/parse-date');
+const cheerio = require('cheerio');
+const got = require('@/utils/got');
+const timezone = require('@/utils/timezone');
+
+module.exports = async (ctx) => {
+ // 移除 urltype=tree.TreeTempUrl 虽然也能顺利访问页面,
+ // 但标题会缺失,而且在其他地方定位提取标题也比较麻烦。
+ const url = `https://www.swpu.edu.cn/dxy/list1.jsp?urltype=tree.TreeTempUrl&wbtreeid=${ctx.params.code}`;
+
+ const res = await got.get(url);
+ const $ = cheerio.load(res.data);
+
+ let title = $('title').text();
+ title = title.substring(0, title.indexOf('-'));
+
+ // 获取标题、时间及链接
+ const items = [];
+ $('tr[height="20"]').each((i, elem) => {
+ items.push({
+ title: $('a[title]', elem).text().trim(),
+ pubDate: timezone(parseDate($('td:eq(1)', elem).text(), 'YYYY年MM月DD日'), +8),
+ link: joinUrl('https://www.swpu.edu.cn/dxy/', $('a[title]', elem).attr('href')),
+ });
+ });
+
+ // 请求全文
+ const out = await Promise.all(
+ items.map(async (item) => {
+ const $ = await ctx.cache.tryGet(item.link, async () => {
+ const res = await got.get(item.link);
+ return cheerio.load(res.data);
+ });
+
+ if ($('title').text().startsWith('系统提示')) {
+ item.author = '系统';
+ item.description = '无权访问';
+ } else {
+ item.author = '电气信息学院';
+ item.description = $('.v_news_content').html();
+ for (const elem of $('.v_news_content p')) {
+ if ($(elem).css('text-align') === 'right') {
+ item.author = $(elem).text();
+ break;
+ }
+ }
+ }
+
+ return item;
+ })
+ );
+
+ ctx.state.data = {
+ title: `西南石油大学电气信息学院 ${title}`,
+ link: url,
+ description: `西南石油大学电气信息学院 ${title}`,
+ language: 'zh-CN',
+ item: out,
+ };
+};
diff --git a/lib/v2/swpu/maintainer.js b/lib/v2/swpu/maintainer.js
new file mode 100644
index 0000000000..3ce9c2e4bb
--- /dev/null
+++ b/lib/v2/swpu/maintainer.js
@@ -0,0 +1,6 @@
+module.exports = {
+ '/bgw/:code': ['CYTMWIA'],
+ '/dean/:code': ['CYTMWIA'],
+ '/dxy/:code': ['CYTMWIA'],
+ '/scs/:code': ['CYTMWIA'],
+};
diff --git a/lib/v2/swpu/radar.js b/lib/v2/swpu/radar.js
new file mode 100644
index 0000000000..00b13ea650
--- /dev/null
+++ b/lib/v2/swpu/radar.js
@@ -0,0 +1,31 @@
+module.exports = {
+ 'swpu.edu.cn': {
+ _name: '西南石油大学',
+ '.': [
+ {
+ title: '办公网',
+ docs: 'https://docs.rsshub.app/university.html#xi-nan-shi-you-da-xue',
+ source: ['/'],
+ target: '',
+ },
+ {
+ title: '教务处',
+ docs: 'https://docs.rsshub.app/university.html#xi-nan-shi-you-da-xue',
+ source: ['/'],
+ target: '',
+ },
+ {
+ title: '计算机科学学院',
+ docs: 'https://docs.rsshub.app/university.html#xi-nan-shi-you-da-xue',
+ source: ['/'],
+ target: '',
+ },
+ {
+ title: '电气信息学院',
+ docs: 'https://docs.rsshub.app/university.html#xi-nan-shi-you-da-xue',
+ source: ['/'],
+ target: '',
+ },
+ ],
+ },
+};
diff --git a/lib/v2/swpu/router.js b/lib/v2/swpu/router.js
new file mode 100644
index 0000000000..c548310ca9
--- /dev/null
+++ b/lib/v2/swpu/router.js
@@ -0,0 +1,6 @@
+module.exports = function (router) {
+ router.get('/bgw/:code', require('./bgw'));
+ router.get('/dean/:code', require('./dean'));
+ router.get('/dxy/:code', require('./dxy'));
+ router.get('/scs/:code', require('./scs'));
+};
diff --git a/lib/v2/swpu/scs.js b/lib/v2/swpu/scs.js
new file mode 100644
index 0000000000..c16fb2df73
--- /dev/null
+++ b/lib/v2/swpu/scs.js
@@ -0,0 +1,58 @@
+const { joinUrl } = require('./utils');
+const { parseDate } = require('@/utils/parse-date');
+const cheerio = require('cheerio');
+const got = require('@/utils/got');
+const timezone = require('@/utils/timezone');
+
+module.exports = async (ctx) => {
+ const url = `https://www.swpu.edu.cn/scs/index/${ctx.params.code}.htm`;
+
+ const res = await got.get(url);
+ const $ = cheerio.load(res.data);
+
+ const title = $('.r_list > h3').text();
+
+ // 获取标题、时间及链接
+ const items = [];
+ $('.main_conRCb > ul > li').each((i, elem) => {
+ items.push({
+ title: $('em', elem).text().trim(),
+ pubDate: timezone(parseDate($('span', elem).text()), +8),
+ link: joinUrl('https://www.swpu.edu.cn/scs/index/', $('a', elem).attr('href')),
+ });
+ });
+
+ // 请求全文
+ const out = await Promise.all(
+ items.map(async (item) => {
+ const $ = await ctx.cache.tryGet(item.link, async () => {
+ const res = await got.get(item.link);
+ return cheerio.load(res.data);
+ });
+
+ if ($('title').text().startsWith('系统提示')) {
+ item.author = '系统';
+ item.description = '无权访问';
+ } else {
+ item.author = '计算机科学学院';
+ item.description = $('.v_news_content').html();
+ for (const elem of $('.v_news_content p')) {
+ if ($(elem).css('text-align') === 'right') {
+ item.author = $(elem).text();
+ break;
+ }
+ }
+ }
+
+ return item;
+ })
+ );
+
+ ctx.state.data = {
+ title: `西南石油大学计算机科学学院 ${title}`,
+ link: url,
+ description: `西南石油大学计算机科学学院 ${title}`,
+ language: 'zh-CN',
+ item: out,
+ };
+};
diff --git a/lib/v2/swpu/utils.js b/lib/v2/swpu/utils.js
new file mode 100644
index 0000000000..a4111e58fd
--- /dev/null
+++ b/lib/v2/swpu/utils.js
@@ -0,0 +1,22 @@
+function isCompleteUrl(url) {
+ return /^\w+?:\/\/.*?\//.test(url);
+}
+
+function joinUrl(url1, url2) {
+ if (isCompleteUrl(url2)) {
+ return url2;
+ }
+
+ if (!url1.endsWith('/')) {
+ url1 = url1 + '/';
+ }
+ if (url2.startsWith('/')) {
+ url2 = url2.substr(1);
+ }
+
+ return url1 + url2;
+}
+
+module.exports = {
+ joinUrl,
+};