feat(route): add 苏州市发展和改革委员会 (#14214)

* feat(route): add 苏州市发展和改革委员会

* docs: remove duplicated heading

* refactor: migrate to v2

* fix: suzhou docs

* fix: news

---------
This commit is contained in:
Ethan Shen 2024-01-15 01:25:20 +08:00 committed by GitHub
parent 1a49f937d8
commit 7a94c42e94
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 267 additions and 205 deletions

View File

@ -487,8 +487,8 @@ router.get('/gov/shuju/:caty/:item', lazyloadRouteHandler('./routes/gov/shuju'))
router.get('/gov/xinwen/tujie/:caty', lazyloadRouteHandler('./routes/gov/xinwen/tujie'));
// 苏州
router.get('/gov/suzhou/news/:uid', lazyloadRouteHandler('./routes/gov/suzhou/news'));
router.get('/gov/suzhou/doc', lazyloadRouteHandler('./routes/gov/suzhou/doc'));
// router.get('/gov/suzhou/news/:uid', lazyloadRouteHandler('./routes/gov/suzhou/news'));
// router.get('/gov/suzhou/doc', lazyloadRouteHandler('./routes/gov/suzhou/doc'));
// 山西
router.get('/gov/shanxi/rst/:category', lazyloadRouteHandler('./routes/gov/shanxi/rst'));

View File

@ -1,39 +0,0 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
const util = require('./utils');
module.exports = async (ctx) => {
const link = 'https://www.suzhou.gov.cn/szxxgk/front/xxgk_right.jsp';
const response = await got.get(link);
const data = response.data;
const $ = cheerio.load(data);
const list = $('.tr_main_value_odd');
ctx.state.data = {
title: '苏州市政府 - 政策公开文件',
link,
item: await Promise.all(
list
.slice(0, 12)
.map(async (index, item) => {
item = $(item);
// 获取全文
const contentUrl = 'https://www.suzhou.gov.cn' + item.find('a').attr('href');
const arr = await ctx.cache.tryGet(contentUrl, async () => {
const fullText = await got.get(contentUrl);
const fullTextData = cheerio.load(fullText.data);
const content = util.content(fullText.data);
const title = fullTextData('h1').text().replace(/\s*/g, '');
return new Array(title, content);
});
return {
title: arr[0],
description: arr[1],
pubDate: item.find('td:nth-child(4)').text(),
link: contentUrl,
};
})
.get()
),
};
};

View File

@ -1,142 +0,0 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
const logger = require('@/utils/logger');
const liburl = require('url');
const util = require('./utils');
const root_url = 'https://www.suzhou.gov.cn/';
module.exports = async (ctx) => {
const uid = ctx.params.uid;
let url = '';
let title = '';
let urljs = '';
switch (uid) {
case 'szyw':
case 'news':
urljs = 'https://www.suzhou.gov.cn/szinf/info/getInfoCommon/?pagesize=15&currpage=1&channelid=5057aeffb1a84a7e8aeded87728da48c';
url = 'https://www.suzhou.gov.cn/szsrmzf/szyw/nav_list.shtml';
title = '苏州市政府 - 苏州要闻';
break;
case 'qxkx':
case 'district':
urljs = 'https://www.suzhou.gov.cn/szinf/info/getInfoCommon/?pagesize=15&currpage=1&channelid=75c636ea0efb487ea7e479e3cc0ff3e5';
url = 'https://www.suzhou.gov.cn/szsrmzf/qxkx/nav_list.shtml';
title = '苏州市政府 - 区县快讯';
break;
case 'bmdt':
urljs = 'https://www.suzhou.gov.cn/szinf/info/getInfoCommon/?pagesize=15&currpage=1&channelid=b3d097e3eb79421f88439ea381ce33c3';
url = 'https://www.suzhou.gov.cn/szsrmzf/bmdt/nav_list.shtml';
title = '苏州市政府 - 部门动态';
break;
case 'xwsp':
urljs = 'https://www.suzhou.gov.cn/szinf/info/getInfoCommon/?pagesize=15&currpage=1&channelid=507980d214c943ebb0a70853ec94b12e';
url = 'https://www.suzhou.gov.cn/szsrmzf/xwsp/nav_list.shtml';
title = '苏州市政府 - 新闻视频';
break;
case 'rdzt':
url = 'https://www.suzhou.gov.cn/szsrmzf/rdzt/nav_list.shtml';
title = '苏州市政府 - 热点专题';
break;
case 'sbjzt':
url = 'https://www.suzhou.gov.cn/szsrmzf/sbjzt/nav_list.shtml';
title = '苏州市政府 - 市本级专题';
break;
case 'zxrdzt':
url = 'https://www.suzhou.gov.cn/szsrmzf/zxrdzt/nav_list.shtml';
title = '苏州市政府 - 最新热点专题';
break;
case 'wqzt':
url = 'https://www.suzhou.gov.cn/szsrmzf/wqzt/nav_list.shtml';
title = '苏州市政府 - 往期专题';
break;
case 'qxzt':
url = 'https://www.suzhou.gov.cn/szsrmzf/qxzt/nav_list.shtml';
title = '苏州市政府 - 区县专题';
break;
case 'zwgg':
urljs = 'https://www.suzhou.gov.cn/szinf/info/getInfoCommon/?pagesize=15&currpage=1&channelid=260915178a1f4c4fac44c4bf6378c9b0';
url = 'https://www.suzhou.gov.cn/szsrmzf/zwgg/nav_list.shtml';
title = '苏州市政府 - 政务公告';
break;
case 'mszx':
urljs = 'https://www.suzhou.gov.cn/szinf/info/getInfoCommon/?pagesize=15&currpage=1&channelid=dc60acecb0be46b89d42272dcb8bd32b';
url = 'https://www.suzhou.gov.cn/szsrmzf/mszx/nav_list.shtml';
title = '苏州市政府 - 便民公告';
break;
case 'bmzx':
urljs = 'https://www.suzhou.gov.cn/szinf/info/getInfoCommon/?pagesize=15&currpage=1&channelid=b015bfa5e5514cc9a26cd9f956ef8e69';
url = 'https://www.suzhou.gov.cn/szsrmzf/bmzx/bmzx_list.shtml';
title = '苏州市政府 - 民生资讯';
break;
default:
logger.error('pattern not matched');
}
if (urljs) {
const responsejs = await got({
method: 'get',
url: urljs,
Host: 'www.suzhou.gov.cn',
});
const jsdata = responsejs.data.infolist;
ctx.state.data = {
title,
link: url,
item: await Promise.all(
jsdata.slice(0, 10).map(async (item) => {
// 获取全文
const link = item.link.indexOf('http') === -1 ? liburl.resolve(root_url, item.link) : item.link;
const description = await ctx.cache.tryGet(link, async () => {
let responsehtml;
try {
responsehtml = await got({
method: 'get',
url: link,
});
const content = util.content(responsehtml.data);
return content;
} catch (error) {
return '';
}
});
return {
title: item.title,
description,
link,
pubDate: item.pubtime,
};
})
),
};
}
if (!urljs) {
const response = await got({
method: 'get',
url,
});
const $ = cheerio.load(response.data);
const list = $('div.pageList li');
ctx.state.data = {
title,
link: url,
item: await Promise.all(
list
.slice(0, 10)
.map((_, item) => {
item = $(item);
const a = item.find('a');
const link = liburl.resolve(root_url, a.attr('href'));
return {
title: a.attr('title'),
link,
pubDate: new Date(item.find('.time').text()).toUTCString(),
};
})
.get()
),
};
}
};

View File

@ -1,20 +0,0 @@
const cheerio = require('cheerio');
const content = (response) => {
const e = cheerio.load(response);
e('.article-extended').remove();
e('#shareNode').remove();
e('.article-auxiliary').remove();
const content = e('.contentShow').html()
? e('.contentShow').html()
: e('div.detail')
.html()
.replace(/<.?ucaptitle>/g, '')
.replace(/<.?ucapcontent>/g, '')
.replace(/"\/szsrmzf/g, '"https://www.suzhou.gov.cn/szsrmzf')
.replace('publishtime', 'span');
return content;
};
module.exports = {
content,
};

View File

@ -101,6 +101,9 @@ module.exports = {
'/shenzhen/zzb/:caty/:page?': ['zlasd'],
'/sichuan/deyang/govpublicinfo/:countyName/:infoType?': ['zytomorrow'],
'/sichuan/deyang/mztoday/:infoType?': ['zytomorrow'],
'/suzhou/doc': ['EsuRt'],
'/suzhou/fg/:category?': ['nczitzk'],
'/suzhou/news/:uid': ['EsuRt', 'luyuhuang'],
'/taiyuan/rsj/:caty/:page?': ['2PoL'],
'/wuhan/sy/whyw': ['nczitzk'],
'/xinyi/:path+': ['ShuiHuo'],

View File

@ -2287,6 +2287,31 @@ module.exports = {
},
],
},
'suzhou.gov.cn': {
_name: '苏州市人民政府',
fg: [
{
title: '苏州市发展和改革委员会',
docs: 'https://docs.rsshub.app/routes/government#su-zhou-shi-ren-min-zheng-fu-su-zhou-shi-fa-zhan-he-gai-ge-wei-yuan-hui',
source: ['/:category*'],
target: (params) => `/gov/suzhou/fg/${params.replace(/\.shtml/, '')}`,
},
],
www: [
{
title: '政府信息公开文件',
docs: 'https://docs.rsshub.app/routes/government#su-zhou-shi-ren-min-zheng-fu',
source: ['/szxxgk/front/xxgk_right.jsp', '/'],
target: '/gov/suzhou/doc',
},
{
title: '政府新闻',
docs: 'https://docs.rsshub.app/routes/government#su-zhou-shi-ren-min-zheng-fu',
source: ['/szsrmzf/:uid/nav_list.shtml'],
target: '/gov/suzhou/news/:uid',
},
],
},
'sz.gov.cn': {
_name: '深圳政府在线移动门户',
hrss: [

View File

@ -93,6 +93,9 @@ module.exports = function (router) {
router.get('/shenzhen/zzb/:caty/:page?', require('./shenzhen/zzb/index'));
router.get('/sichuan/deyang/govpublicinfo/:countyName/:infoType?', require('./sichuan/deyang/govpublicinfo'));
router.get('/sichuan/deyang/mztoday/:infoType?', require('./sichuan/deyang/mztoday'));
router.get('/suzhou/doc', require('./suzhou/doc'));
router.get('/suzhou/fg/:category*', require('./suzhou/fg'));
router.get('/suzhou/news/:uid', require('./suzhou/news'));
router.get('/taiyuan/rsj/:caty/:page?', require('./taiyuan/rsj'));
router.get('/wuhan/sy/whyw', require('./wuhan/whyw'));
router.get(/xinyi(\/[\w/-]+)?/, require('./xinyi/xinyi'));

46
lib/v2/gov/suzhou/doc.js Normal file
View File

@ -0,0 +1,46 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
const { parseDate } = require('@/utils/parse-date');
const timezone = require('@/utils/timezone');
module.exports = async (ctx) => {
const link = 'https://www.suzhou.gov.cn/szxxgk/front/xxgk_right.jsp';
const { data: response } = await got(link);
const $ = cheerio.load(response);
const list = $('.tr_main_value_odd')
.toArray()
.map((item) => {
item = $(item);
const title = item.find('a');
return {
title: title.attr('title'),
link: `https://www.suzhou.gov.cn${title.attr('href')}`,
pubDate: timezone(parseDate(item.find('td:nth-child(3)').text().trim()), 8),
};
});
const items = await Promise.all(
list.map((item) =>
ctx.cache.tryGet(item.link, async () => {
const { data: response } = await got(item.link);
const $ = cheerio.load(response);
item.description = $('.article-content').html();
item.author = $('dd.addWidth:nth-child(3) div').text().trim();
item.pubDate = $('meta[name="PubDate"]').length ? timezone(parseDate($('meta[name="PubDate"]').attr('content'), 'YYYY-MM-DD HH:mm:ss'), 8) : item.pubDate;
item.category = $('.OwnerDept font')
.toArray()
.map((item) => $(item).text().trim());
return item;
})
)
);
ctx.state.data = {
title: '苏州市政府 - 政策公开文件',
link,
item: items,
};
};

62
lib/v2/gov/suzhou/fg.js Normal file
View File

@ -0,0 +1,62 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
const timezone = require('@/utils/timezone');
const { parseDate } = require('@/utils/parse-date');
module.exports = async (ctx) => {
const { category = 'szfgw/ggl/nav_list' } = ctx.params;
const limit = ctx.query.limit ? parseInt(ctx.query.limit, 10) : 30;
const rootUrl = 'https://fg.suzhou.gov.cn';
const currentUrl = new URL(`${category}.shtml`, rootUrl).href;
const { data: response } = await got(currentUrl);
const $ = cheerio.load(response);
let items = $('h4 a[title]')
.slice(0, limit)
.toArray()
.map((item) => {
item = $(item);
return {
title: item.prop('title') || item.text(),
link: new URL(item.prop('href'), rootUrl).href,
author: item.find('.author').text(),
pubDate: parseDate(item.parent().find('span.time').text().trim()),
};
});
items = await Promise.all(
items.map((item) =>
ctx.cache.tryGet(item.link, async () => {
const { data: detailResponse } = await got(item.link);
const content = cheerio.load(detailResponse);
item.title = content('ucaptitle').text().trim();
item.description = content('ucapcontent').html();
item.author = content('span.ly b').text().trim();
item.pubDate = timezone(parseDate(content('meta[name="PubDate"]').prop('content')), +8);
return item;
})
)
);
const author = $('meta[name="SiteName"]').prop('content');
const subtitle = $('meta[name="ColumnName"]').prop('content');
const image = new URL($('div.logo img').prop('src'), rootUrl).href;
ctx.state.data = {
item: items,
title: `${author} - ${subtitle}`,
link: currentUrl,
description: $('meta[name="ColumnDescription"]').prop('content'),
language: $('html').prop('lang'),
image,
subtitle,
author,
};
};

116
lib/v2/gov/suzhou/news.js Normal file
View File

@ -0,0 +1,116 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
const { parseDate } = require('@/utils/parse-date');
const timezone = require('@/utils/timezone');
module.exports = async (ctx) => {
const rootUrl = 'https://www.suzhou.gov.cn';
const uid = ctx.params.uid;
let url = '';
let title = '';
let apiUrl = '';
let items = [];
switch (uid) {
case 'szyw':
case 'news':
apiUrl = `${rootUrl}/szinf/info/getInfoCommon/?pagesize=15&currpage=1&channelid=5057aeffb1a84a7e8aeded87728da48c`;
url = `${rootUrl}/szsrmzf/szyw/nav_list.shtml`;
title = '苏州市政府 - 苏州要闻';
break;
case 'qxkx':
case 'district':
apiUrl = `${rootUrl}/szinf/info/getInfoCommon/?pagesize=15&currpage=1&channelid=75c636ea0efb487ea7e479e3cc0ff3e5`;
url = `${rootUrl}/szsrmzf/qxkx/nav_list.shtml`;
title = '苏州市政府 - 区县快讯';
break;
case 'bmdt':
apiUrl = `${rootUrl}/szinf/info/getInfoCommon/?pagesize=15&currpage=1&channelid=b3d097e3eb79421f88439ea381ce33c3`;
url = `${rootUrl}/szsrmzf/bmdt/nav_list.shtml`;
title = '苏州市政府 - 部门动态';
break;
case 'xwsp':
apiUrl = `${rootUrl}/szinf/info/getInfoCommon/?pagesize=15&currpage=1&channelid=507980d214c943ebb0a70853ec94b12e`;
url = `${rootUrl}/szsrmzf/xwsp/nav_list.shtml`;
title = '苏州市政府 - 新闻视频';
break;
case 'rdzt':
url = `${rootUrl}/szsrmzf/rdzt/nav_list.shtml`;
title = '苏州市政府 - 热点专题';
break;
case 'sbjzt':
url = `${rootUrl}/szsrmzf/sbjzt/nav_list.shtml`;
title = '苏州市政府 - 市本级专题';
break;
case 'zxrdzt':
url = `${rootUrl}/szsrmzf/zxrdzt/nav_list.shtml`;
title = '苏州市政府 - 最新热点专题';
break;
case 'wqzt':
url = `${rootUrl}/szsrmzf/wqzt/nav_list.shtml`;
title = '苏州市政府 - 往期专题';
break;
case 'qxzt':
url = `${rootUrl}/szsrmzf/qxzt/nav_list.shtml`;
title = '苏州市政府 - 区县专题';
break;
case 'zwgg':
apiUrl = `${rootUrl}/szinf/info/getInfoCommon/?pagesize=15&currpage=1&channelid=260915178a1f4c4fac44c4bf6378c9b0`;
url = `${rootUrl}/szsrmzf/zwgg/nav_list.shtml`;
title = '苏州市政府 - 政务公告';
break;
case 'mszx':
apiUrl = `${rootUrl}/szinf/info/getInfoCommon/?pagesize=15&currpage=1&channelid=dc60acecb0be46b89d42272dcb8bd32b`;
url = `${rootUrl}/szsrmzf/mszx/nav_list.shtml`;
title = '苏州市政府 - 便民公告';
break;
case 'bmzx':
apiUrl = `${rootUrl}/szinf/info/getInfoCommon/?pagesize=15&currpage=1&channelid=b015bfa5e5514cc9a26cd9f956ef8e69`;
url = `${rootUrl}/szsrmzf/bmzx/bmzx_list.shtml`;
title = '苏州市政府 - 民生资讯';
break;
default:
throw 'pattern not matched';
}
if (apiUrl) {
const response = await got(apiUrl);
const infoList = response.data.infolist.map((item) => ({
title: item.title,
link: item.link.startsWith('http') ? item.link : new URL(item.link, rootUrl).href,
pubDate: timezone(parseDate(item.pubtime, 'YYYY-MM-DD HH:mm:ss'), 8),
}));
items = await Promise.all(
infoList.map((item) =>
// 获取全文
ctx.cache.tryGet(item.link, async () => {
const response = await got(item.link);
const $ = cheerio.load(response.data);
item.description = $('ucapcontent').html();
return item;
})
)
);
} else {
const response = await got(url);
const $ = cheerio.load(response.data);
items = $('ul.infolist li')
.toArray()
.map((item) => {
item = $(item);
const a = item.find('a');
return {
title: a.attr('title'),
link: new URL(a.attr('href'), rootUrl).href,
pubDate: timezone(parseDate(item.find('.time').text(), 'YYYY-MM-DD'), 8),
};
});
}
ctx.state.data = {
title,
link: url,
item: items,
};
};

View File

@ -1080,7 +1080,7 @@
### 政府新闻 {#su-zhou-shi-ren-min-zheng-fu-zheng-fu-xin-wen}
<Route author="EsuRt luyuhuang" example="/gov/suzhou/news/news" path="/gov/suzhou/news/:uid" paramsDesc={['栏目名']} notOperational="1">
<Route author="EsuRt luyuhuang" example="/gov/suzhou/news/news" path="/gov/suzhou/news/:uid" paramsDesc={['栏目名']} radar="1">
| 新闻栏目名 | :uid |
| :--------: | :--------------: |
| 苏州要闻 | news 或 szyw |
@ -1110,7 +1110,15 @@
### 政府信息公开文件 {#su-zhou-shi-ren-min-zheng-fu-zheng-fu-xin-xi-gong-kai-wen-jian}
<Route author="EsuRt" example="/gov/suzhou/doc" path="/gov/suzhou/doc" notOperational="1" />
<Route author="EsuRt" example="/gov/suzhou/doc" path="/gov/suzhou/doc" radar="1" />
### 苏州市发展和改革委员会 {#su-zhou-shi-ren-min-zheng-fu-su-zhou-shi-fa-zhan-he-gai-ge-wei-yuan-hui}
<Route author="nczitzk" example="/gov/suzhou/fg/szfgw/ggl/nav_list" path="/gov/suzhou/fg/:category?" paramsDesc={['分类,见下表,默认为通知公告']} radar="1">
| 通知公告 | 发改要闻 |
| ------------------- | -------------------- |
| szfgw/ggl/nav\_list | szfgw/gzdt/nav\_list |
</Route>
## 台湾行政院消费者保护会 {#tai-wan-xing-zheng-yuan-xiao-fei-zhe-bao-hu-hui}