diff --git a/docs/new-media.md b/docs/new-media.md
index 5fbedd2556..3665b69d5e 100644
--- a/docs/new-media.md
+++ b/docs/new-media.md
@@ -1406,6 +1406,26 @@ area 分区选项
+## 电獭少女
+
+### 分类
+
+
+
+| App 评测 | 手机开箱 | 笔电开箱 | 3C 周边 | 教学小技巧 | 科技情报 |
+| -------- | -------- | -------- | ----------- | ---------- | -------- |
+| app | phone | computer | accessories | tutorial | techlife |
+
+
+
+### 精选主题
+
+
+
+### 当前精选主题列表
+
+
+
## 丁香园
### 新冠疫苗实时动态
diff --git a/lib/v2/agirls/index.js b/lib/v2/agirls/index.js
new file mode 100644
index 0000000000..3122cb4257
--- /dev/null
+++ b/lib/v2/agirls/index.js
@@ -0,0 +1,71 @@
+const got = require('@/utils/got');
+const cheerio = require('cheerio');
+const { parseDate } = require('@/utils/parse-date');
+const timezone = require('@/utils/timezone');
+const path = require('path');
+const { art } = require('@/utils/render');
+
+module.exports = async (ctx) => {
+ const baseUrl = 'https://agirls.aotter.net';
+ const category = ctx.params.category ?? '';
+
+ const response = await got({
+ url: baseUrl + '/posts' + (category ? `/${category}` : ''),
+ header: {
+ Referer: baseUrl,
+ },
+ });
+
+ const $ = cheerio.load(response.data);
+
+ let items = $('div a.flex.flex-col')
+ .map((_, item) => {
+ item = $(item);
+ return {
+ title: item.find('h2').text().trim(),
+ link: baseUrl + item.attr('href'),
+ };
+ })
+ .get();
+
+ items = await Promise.all(
+ items.map((item) =>
+ ctx.cache.tryGet(item.link, async () => {
+ const detailResponse = await got({
+ url: item.link,
+ header: {
+ Referer: baseUrl + '/posts/' + (category ? `/${category}` : ''),
+ },
+ });
+ const content = cheerio.load(detailResponse.data);
+
+ item.category = content('a.mr-2.bg-neutral-lightest.px-2.py-1.text-sm.text-neutral-light')
+ .toArray()
+ .map((e) => content(e).text().trim().replace('#', ''));
+ item.description = art(path.join(__dirname, 'templates/description.art'), {
+ desc: content('div.post-content').html(),
+ });
+ item.pubDate = timezone(parseDate(content('time').text().trim()), +8);
+ item.author = content('a.mr-1.text-primary').text().trim();
+
+ return item;
+ })
+ )
+ );
+
+ ctx.state.data = {
+ title: $('head title').text().trim(),
+ link: baseUrl + '/' + category,
+ description: $('head meta[name=description]').attr('content'),
+ item: items,
+ language: $('html').attr('lang'),
+ };
+
+ ctx.state.json = {
+ title: $('head title').text().trim(),
+ link: baseUrl + '/' + category,
+ description: $('head meta[name=description]').attr('content'),
+ item: items,
+ language: $('html').attr('lang'),
+ };
+};
diff --git a/lib/v2/agirls/maintainer.js b/lib/v2/agirls/maintainer.js
new file mode 100644
index 0000000000..cd511d9839
--- /dev/null
+++ b/lib/v2/agirls/maintainer.js
@@ -0,0 +1,5 @@
+module.exports = {
+ '/topic/:topic': ['TonyRL'],
+ '/topic_list': ['TonyRL'],
+ '/:category?': ['TonyRL'],
+};
diff --git a/lib/v2/agirls/radar.js b/lib/v2/agirls/radar.js
new file mode 100644
index 0000000000..1637c87b5e
--- /dev/null
+++ b/lib/v2/agirls/radar.js
@@ -0,0 +1,25 @@
+module.exports = {
+ 'aotter.net': {
+ _name: '電獺少女',
+ agirls: [
+ {
+ title: '分類',
+ docs: 'https://docs.rsshub.app/new-media.html##dian-ta-shao-nu',
+ source: ['/posts/:category'],
+ target: '/agirls/:category',
+ },
+ {
+ title: '精選主題列表',
+ docs: 'https://docs.rsshub.app/new-media.html##dian-ta-shao-nu',
+ source: ['/', '/topic'],
+ target: '/agirls/topic_list',
+ },
+ {
+ title: '精选主题',
+ docs: 'https://docs.rsshub.app/new-media.html##dian-ta-shao-nu',
+ source: ['/topic/:topic'],
+ target: '/agirls/topic/:topic',
+ },
+ ],
+ },
+};
diff --git a/lib/v2/agirls/router.js b/lib/v2/agirls/router.js
new file mode 100644
index 0000000000..33d4d86f1c
--- /dev/null
+++ b/lib/v2/agirls/router.js
@@ -0,0 +1,5 @@
+module.exports = function (router) {
+ router.get('/topic/:topic', require('./topic'));
+ router.get('/topic_list', require('./topic_list'));
+ router.get('/:category?', require('./index'));
+};
diff --git a/lib/v2/agirls/templates/description.art b/lib/v2/agirls/templates/description.art
new file mode 100644
index 0000000000..7755ee9f6b
--- /dev/null
+++ b/lib/v2/agirls/templates/description.art
@@ -0,0 +1 @@
+{{@ desc }}
diff --git a/lib/v2/agirls/topic.js b/lib/v2/agirls/topic.js
new file mode 100644
index 0000000000..b18d230e85
--- /dev/null
+++ b/lib/v2/agirls/topic.js
@@ -0,0 +1,71 @@
+const got = require('@/utils/got');
+const cheerio = require('cheerio');
+const { parseDate } = require('@/utils/parse-date');
+const timezone = require('@/utils/timezone');
+const path = require('path');
+const { art } = require('@/utils/render');
+
+module.exports = async (ctx) => {
+ const baseUrl = 'https://agirls.aotter.net';
+ const topic = ctx.params.topic;
+
+ const response = await got({
+ url: baseUrl + '/topic/' + topic,
+ header: {
+ Referer: baseUrl,
+ },
+ });
+
+ const $ = cheerio.load(response.data);
+
+ let items = $('div.col-12 div.row a')
+ .map((_, item) => {
+ item = $(item);
+ return {
+ title: item.find('h3').text().trim(),
+ link: baseUrl + item.attr('href'),
+ };
+ })
+ .get();
+
+ items = await Promise.all(
+ items.map((item) =>
+ ctx.cache.tryGet(item.link, async () => {
+ const detailResponse = await got({
+ url: item.link,
+ header: {
+ Referer: baseUrl + '/topic/' + topic,
+ },
+ });
+ const content = cheerio.load(detailResponse.data);
+
+ item.category = content('a.mr-2.bg-neutral-lightest.px-2.py-1.text-sm.text-neutral-light')
+ .toArray()
+ .map((e) => content(e).text().trim().replace('#', ''));
+ item.description = art(path.join(__dirname, 'templates/description.art'), {
+ desc: content('div.post-content').html(),
+ });
+ item.pubDate = timezone(parseDate(content('time').text().trim()), +8);
+ item.author = content('a.mr-1.text-primary').text().trim();
+
+ return item;
+ })
+ )
+ );
+
+ ctx.state.data = {
+ title: $('head title').text().trim(),
+ link: baseUrl + '/' + topic,
+ description: $('head meta[name=description]').attr('content'),
+ item: items,
+ language: $('html').attr('lang'),
+ };
+
+ ctx.state.json = {
+ title: $('head title').text().trim(),
+ link: baseUrl + '/' + topic,
+ description: $('head meta[name=description]').attr('content'),
+ item: items,
+ language: $('html').attr('lang'),
+ };
+};
diff --git a/lib/v2/agirls/topic_list.js b/lib/v2/agirls/topic_list.js
new file mode 100644
index 0000000000..3602823e93
--- /dev/null
+++ b/lib/v2/agirls/topic_list.js
@@ -0,0 +1,44 @@
+const got = require('@/utils/got');
+const cheerio = require('cheerio');
+
+module.exports = async (ctx) => {
+ const baseUrl = 'https://agirls.aotter.net';
+ const category = 'topic';
+
+ const response = await got({
+ url: baseUrl + '/' + category,
+ header: {
+ Referer: baseUrl,
+ },
+ });
+
+ const $ = cheerio.load(response.data);
+
+ const items = $('div div.border-b.border-neutral-lighter')
+ .map((_, item) => {
+ item = $(item);
+ const link = baseUrl + item.find('a').attr('href');
+ return ctx.cache.tryGet(link, () => ({
+ title: item.find('h2').text().trim(),
+ description: item.find('a').attr('href').replace('/topic/', ''),
+ link,
+ }));
+ })
+ .get();
+
+ ctx.state.data = {
+ title: $('head title').text().trim(),
+ link: baseUrl + '/' + category,
+ description: $('head meta[name=description]').attr('content'),
+ item: items,
+ language: $('html').attr('lang'),
+ };
+
+ ctx.state.json = {
+ title: $('head title').text().trim(),
+ link: baseUrl + '/' + category,
+ description: $('head meta[name=description]').attr('content'),
+ item: items,
+ language: $('html').attr('lang'),
+ };
+};