diff --git a/docs/en/traditional-media.md b/docs/en/traditional-media.md
index d6a5db49e3..406a3ef2d3 100644
--- a/docs/en/traditional-media.md
+++ b/docs/en/traditional-media.md
@@ -60,6 +60,10 @@ Support major channels, refer to [BBC RSS feeds](https://www.bbc.co.uk/news/1062
+## Google News
+
+
+
## NHK
### News Web Easy
@@ -128,12 +132,12 @@ Provides a better reading experience (full text articles) over the official one.
`Region`
| Hong Kong | Taiwan | US |
-| -- | -- | -- |
+| --------- | ------ | --- |
| hk | tw | en |
`Category`
| All | World | Business | Entertainment | Sports | Health |
-| -- | -- | -- | -- | -- | -- |
+| ------- | ----- | -------- | ------------- | ------ | ------ |
| (Empty) | world | business | entertainment | sports | health |
diff --git a/docs/traditional-media.md b/docs/traditional-media.md
index 77b2b439cc..ae16764d19 100644
--- a/docs/traditional-media.md
+++ b/docs/traditional-media.md
@@ -104,12 +104,12 @@ Solidot 提供的 feed:
`地区`
| 香港 | 台灣 | 美國 |
-| -- | -- | -- |
+| ---- | ---- | ---- |
| hk | tw | en |
`类別`
| 新聞總集 | 兩岸國際 | 財經 | 娛樂 | 體育 | 健康 |
-| -- | -- | -- | -- | -- | -- |
+| -------- | -------- | -------- | ------------- | ------ | ------ |
| (空) | world | business | entertainment | sports | health |
@@ -188,6 +188,10 @@ Category 列表:
+## 谷歌新闻
+
+
+
## 华尔街见闻
### 华尔街见闻
diff --git a/lib/router.js b/lib/router.js
index 3d1b9d2565..64a4b3eca9 100644
--- a/lib/router.js
+++ b/lib/router.js
@@ -2228,4 +2228,7 @@ router.get('/cowlevel/element/:id', require('./routes/cowlevel/element'));
// 2048
router.get('/2048/bbs/:fid', require('./routes/2048/bbs'));
+// Google News
+router.get('/google/news/:category/:locale', require('./routes/google/news'));
+
module.exports = router;
diff --git a/lib/routes/google/news.js b/lib/routes/google/news.js
new file mode 100644
index 0000000000..085143a669
--- /dev/null
+++ b/lib/routes/google/news.js
@@ -0,0 +1,107 @@
+const got = require('@/utils/got');
+const cheerio = require('cheerio');
+const url = require('url');
+
+module.exports = async (ctx) => {
+ const category = ctx.params.category;
+ const locale = ctx.params.locale;
+
+ const category_url = await ctx.cache.tryGet([locale, category], async () => {
+ const front_page = await got({
+ method: 'get',
+ url: `https://news.google.com/?${locale}`,
+ });
+
+ const front_data = front_page.data;
+
+ const $ = cheerio.load(front_data);
+ const category_list = $('a.wmzpFf.yETrXb');
+
+ const category_text = [];
+ category_list.each((index, item) => {
+ category_text.push($(item).text());
+ });
+
+ return url.resolve('https://news.google.com', category_list.eq(category_text.indexOf(category)).attr('href'));
+ });
+
+ const response = await got({
+ method: 'get',
+ url: category_url,
+ });
+
+ const data = response.data;
+ const $ = cheerio.load(data);
+ const list = $('div.xrnccd');
+
+ let itemPicUrl;
+ let meta;
+ let description;
+ let link;
+
+ ctx.state.data = {
+ title: $('title').text(),
+ link: category_url,
+ item:
+ list &&
+ list
+ .map((index, item) => {
+ item = $(item);
+ itemPicUrl = item.find('img').attr('src');
+
+ meta = item.find('div.SVJrMe').first();
+
+ description = item
+ .find('h4.ipQwMb')
+ .removeAttr('class')
+ .each((index, item) => {
+ $(item)
+ .children()
+ .removeAttr('class')
+ .attr(
+ 'href',
+ url.resolve(
+ 'https://news.google.com',
+ $(item)
+ .children()
+ .attr('href')
+ )
+ );
+ })
+ .toString();
+
+ link = url.resolve(
+ 'https://news.google.com',
+ item
+ .find('a.VDXfz')
+ .first()
+ .attr('href')
+ );
+
+ if (itemPicUrl !== undefined) {
+ description = `${description}
`;
+ }
+ if (description === null) {
+ description = link;
+ }
+
+ return {
+ title: item
+ .find('h3')
+ .children()
+ .text(),
+ description: description,
+ pubDate: meta
+ .find('time')
+ .first()
+ .attr('datetime'),
+ author: meta
+ .find('a.wEwyrc')
+ .first()
+ .text(),
+ link: link,
+ };
+ })
+ .get(),
+ };
+};