diff --git a/catalog/book/models.py b/catalog/book/models.py index 3741c3a7..f777aed9 100644 --- a/catalog/book/models.py +++ b/catalog/book/models.py @@ -235,6 +235,7 @@ def lookup_id_type_choices(cls): IdType.DoubanBook, IdType.Goodreads, IdType.GoogleBooks, + IdType.Qidian, ] return [(i.value, i.label) for i in id_types] diff --git a/catalog/book/tests.py b/catalog/book/tests.py index 8f00d7ed..667bf8d3 100644 --- a/catalog/book/tests.py +++ b/catalog/book/tests.py @@ -363,6 +363,52 @@ def test_work(self): self.assertEqual(editions[1].display_title, "黄金时代") +class QidianTestCase(TestCase): + databases = "__all__" + + def test_parse(self): + t_type = IdType.Qidian + t_id = "1010868264" + t_url = "https://www.qidian.com/book/1010868264/" + t_url2 = "https://book.qidian.com/info/1010868264/" + p1 = SiteManager.get_site_by_url(t_url) + p2 = SiteManager.get_site_by_url(t_url2) + self.assertEqual(p1.url, t_url2) + self.assertEqual(p1.ID_TYPE, t_type) + self.assertEqual(p1.id_value, t_id) + self.assertEqual(p2.url, t_url2) + + @use_local_response + def test_scrape(self): + t_url = "https://book.qidian.com/info/1010868264/" + site = SiteManager.get_site_by_url(t_url) + self.assertEqual(site.ready, False) + site.get_resource_ready() + self.assertEqual(site.ready, True) + self.assertEqual(site.resource.site_name, SiteName.Qidian) + self.assertEqual(site.resource.id_type, IdType.Qidian) + self.assertEqual(site.resource.id_value, "1010868264") + self.assertEqual(site.resource.item.display_title, "诡秘之主") + self.assertEqual(site.resource.item.author[0], "爱潜水的乌贼") + + +class YpshuoTestCase(TestCase): + databases = "__all__" + + @use_local_response + def test_scrape(self): + t_url = "https://www.ypshuo.com/novel/1.html" + site = SiteManager.get_site_by_url(t_url) + self.assertEqual(site.ready, False) + site.get_resource_ready() + self.assertEqual(site.ready, True) + self.assertEqual(site.resource.site_name, SiteName.Ypshuo) + self.assertEqual(site.resource.id_type, IdType.Ypshuo) + self.assertEqual(site.resource.id_value, "1") + self.assertEqual(site.resource.item.display_title, "诡秘之主") + self.assertEqual(site.resource.item.author[0], "爱潜水的乌贼") + + class MultiBookSitesTestCase(TestCase): databases = "__all__" diff --git a/catalog/common/models.py b/catalog/common/models.py index b623b6b0..b2d894d5 100644 --- a/catalog/common/models.py +++ b/catalog/common/models.py @@ -57,6 +57,8 @@ class SiteName(models.TextChoices): Discogs = "discogs", _("Discogs") # type:ignore[reportCallIssue] AppleMusic = "apple_music", _("Apple Music") # type:ignore[reportCallIssue] Fediverse = "fedi", _("Fediverse") # type:ignore[reportCallIssue] + Qidian = "qidian", _("Qidian") # type:ignore[reportCallIssue] + Ypshuo = "ypshuo", _("Ypshuo") # type:ignore[reportCallIssue] class IdType(models.TextChoices): @@ -118,6 +120,8 @@ class IdType(models.TextChoices): ApplePodcast = "apple_podcast", _("Apple Podcast") # type:ignore[reportCallIssue] AppleMusic = "apple_music", _("Apple Music") # type:ignore[reportCallIssue] Fediverse = "fedi", _("Fediverse") # type:ignore[reportCallIssue] + Qidian = "qidian", _("Qidian") # type:ignore[reportCallIssue] + Ypshuo = "ypshuo", _("Ypshuo") # type:ignore[reportCallIssue] IdealIdTypes = [ diff --git a/catalog/sites/__init__.py b/catalog/sites/__init__.py index 71c75948..1e84cf65 100644 --- a/catalog/sites/__init__.py +++ b/catalog/sites/__init__.py @@ -15,9 +15,11 @@ from .google_books import GoogleBooks from .igdb import IGDB from .imdb import IMDB +from .qidian import Qidian from .rss import RSS from .spotify import Spotify from .steam import Steam from .tmdb import TMDB_Movie +from .ypshuo import Ypshuo # from .apple_podcast import ApplePodcast diff --git a/catalog/sites/qidian.py b/catalog/sites/qidian.py new file mode 100644 index 00000000..4e9f2962 --- /dev/null +++ b/catalog/sites/qidian.py @@ -0,0 +1,54 @@ +import logging + +from catalog.common import * +from catalog.models import * + + +@SiteManager.register +class Qidian(AbstractSite): + SITE_NAME = SiteName.Qidian + ID_TYPE = IdType.Qidian + URL_PATTERNS = [ + r"https://www\.qidian\.com/book/(\d+)", + r"https://book\.qidian\.com/info/(\d+)", + ] + WIKI_PROPERTY_ID = "" + DEFAULT_MODEL = Edition + + @classmethod + def id_to_url(cls, id_value): + return f"https://book.qidian.com/info/{id_value}/" + + def scrape(self): + content = ProxiedDownloader(self.url).download().html() + title_elem = content.xpath('//*[@id="bookName"]/text()') + title = ( + title_elem[0].strip() # type:ignore + if title_elem + else f"Unknown Title {self.id_value}" + ) + + brief_elem = content.xpath( + "/html/body/div[1]/div[5]/div[3]/div[1]/div/div[1]/div[1]/p/text()" + ) + brief = ( + "\n".join(p.strip() for p in brief_elem) # type:ignore + if brief_elem + else None + ) + + img_url = f"https://bookcover.yuewen.com/qdbimg/349573/{self.id_value}" + + author_elem = content.xpath( + "/html/body/div[1]/div[5]/div[1]/div[2]/h1/span[1]/a/text()" + ) + authors = [author_elem[0].strip()] if author_elem else None # type:ignore + + return ResourceContent( + metadata={ + "localized_title": [{"lang": "zh-cn", "text": title}], + "author": authors, + "localized_description": [{"lang": "zh-cn", "text": brief}], + "cover_image_url": img_url, + } + ) diff --git a/catalog/sites/ypshuo.py b/catalog/sites/ypshuo.py new file mode 100644 index 00000000..7ddaaf19 --- /dev/null +++ b/catalog/sites/ypshuo.py @@ -0,0 +1,39 @@ +import json + +from catalog.common import * +from catalog.models import * + + +@SiteManager.register +class Ypshuo(AbstractSite): + SITE_NAME = SiteName.Ypshuo + ID_TYPE = IdType.Ypshuo + URL_PATTERNS = [ + r"https://www\.ypshuo\.com/novel/(\d+)\.html", + ] + WIKI_PROPERTY_ID = "" + DEFAULT_MODEL = Edition + + @classmethod + def id_to_url(cls, id_value): + return f"https://www.ypshuo.com/novel/{id_value}.html" + + def scrape(self): + api_url = f"https://www.ypshuo.com/api/novel/getInfo?novelId={self.id_value}" + o = BasicDownloader(api_url).download().json() + source = json.loads(o["data"]["source"]) + lookup_ids = {} + for site in source: + if site["siteName"] == "起点中文网": + lookup_ids[IdType.Qidian] = site["bookId"] + return ResourceContent( + metadata={ + "localized_title": [{"lang": "zh-cn", "text": o["data"]["novel_name"]}], + "author": [o["data"]["author_name"]], + "localized_description": [ + {"lang": "zh-cn", "text": o["data"]["synopsis"]} + ], + "cover_image_url": o["data"]["novel_img"], + }, + lookup_ids=lookup_ids, + ) diff --git a/common/static/scss/_sitelabel.scss b/common/static/scss/_sitelabel.scss index 989293af..4f310d17 100644 --- a/common/static/scss/_sitelabel.scss +++ b/common/static/scss/_sitelabel.scss @@ -18,6 +18,12 @@ white-space: nowrap; } + .qidian { + border: none; + color: white; + background-color: #9e252b; + } + .douban { border: none; color: white; diff --git a/test_data/https___book_qidian_com_info_1010868264_ b/test_data/https___book_qidian_com_info_1010868264_ new file mode 100644 index 00000000..6f0fae0c --- /dev/null +++ b/test_data/https___book_qidian_com_info_1010868264_ @@ -0,0 +1,1920 @@ + + 诡秘之主(爱潜水的乌贼)全本在线阅读-起点中文网官方正版
首页 玄幻频道 异世大陆
诡秘之主在线阅读

诡秘之主爱潜水的乌贼 更新时间 2022-11-25 16:27:26

完本 签约 VIP 玄幻 异世大陆 轻小说

心潮澎湃,无限幻想,迎风挥击千层浪,少年不败热血!

446.52万字| 3415.62万总推荐|1195周推荐

免费试读 加入书架 投票互动 手机扫码读本书 支持多音色听书

  蒸汽与机械的浪潮中,谁能触及非凡?历史和黑暗的迷雾里,又是谁在耳语?我从诡秘中醒来,睁眼看见这个世界:
  枪械,大炮,巨舰,飞空艇,差分机;魔药,占卜,诅咒,倒吊人,封印物……光明依旧照耀,神秘从未远离,这是一段“愚者”的传说。

书友互动

月票| 推荐票

本月票数

7442

排名52·还差 161 票追上前一名

投月票

1张月票=100点粉丝值

打赏

本周打赏人数

53

今日53人打赏

打赏

100起点币=100点粉丝值

我的书友等级

本书书友动态

异世大陆小说推荐 更多

这个御兽师明明不强却过分勇敢在线阅读
这是一个御兽的世界。 + + 御兽师做医生,可生死人肉白骨;空间类宠兽送快递,瞬间即达;高考有御兽科,大学有御兽专业,御兽比赛遍地开花! + + 风雷灵猫、金刚暴猿、赤焰火龙、冰雪精灵、熔岩巨人、裂海龙鲸…… + + 遗迹、保护区、古战场、绝地、蛮荒…… + + 神话和科技共存,文明和野蛮并立! + + 陆阳穿越而来,获得职业面板,开始了紧张刺激的冒险。 + + 见习级时摸统领级母老虎的屁股;青铜级时干君王级恶鬼;白银级时,与神兽较量…… + + 徘徊在生与死的边缘,游走于危险的夹缝。 + + 陆阳的口号是,生命不息,搞事不止! + + …… + + 御兽流、系统流小说,求关注!!
沉默的水羊
异世大陆
日更千字
被召唤到异界的丧尸在线阅读
我是一个丧尸,一个会思考的丧尸。  作为一个丧尸,我只需要每天丧丧的混日子就可以了。  因为我很弱,抢食都抢不过那些大佬,饥饿得每天只能浑浑噩噩的过日子,就脑子都快转不动了。  抢饭抢不过,除了丧丧的,躺着混日子还能干什么呢。  因为已经死过一次了,所以就算是想要等死都难。  直到有一天,我被一个亡灵法师给召唤到了异世界,他似乎对我下达了什么命令,不过我听不懂他在说什么,反手就把他给做了。  通过吞食亡灵法师的脑子,我获得了大陆通用语,基础魔法知识,亡灵召唤……
茶少行
异世大陆
日更千字
巫师:我能解析万物在线阅读
卢克穿越到巫师世界,利用具有探测和分析功能的生物辅助芯片,踏上追逐真理的巫师之旅。 +———— +实力低微,冥想速度太慢? +解析意志符文,优化巫师冥想法,加快冥想速度! +法术模型太过复杂,难以掌握? +解析法术模型,快速掌握零级法术,甚至是巫术! +缺少魔石,没有巫师修炼资源? +解析巫术符文卷轴,成为符文大师,炼制大量巫术卷轴出售,赚取巨额魔石! +———— +万物皆可解析,我能解析万物! +卢克凭借生物辅助芯片,踏上巫师之旅,一步步成长为永恒神祇!
皮县花椒酱
异世大陆
日更千字

最后的机武神在线阅读
“曾经,这片土地叫做江松,是洋人最多的城市,茶楼、跑马场、武术馆到处都是,.......那时候这个国家才刚开始迎接时代的新风,帝国舰队装载了炁金属引擎和船炮的新式战舰一路打到近海,遥望京城......”  他是最后的机武神,环顾残骸与血的战场,神色寂寥。  他目睹了人类的疯狂、科技的暴走,以及末路的清冷。  他名叫吴钩。  他重生了。 +国术+蒸汽朋克,不是机甲文。
素羽墨月
异世大陆
日更千字
我能掌控万物大小在线阅读
穿越乱世,各种天灾人祸不断。 + 叶新努力活着,意外发现自己掌握了掌控万物大小的能力。 + 练武资源量少且小,给我“大”。 + 武技威力不足,给我“大” + 死敌太过强大,打不赢,给我“小”。 + 修炼关卡太难,给我“小” + …… + 就这样,叶新一路经历了各种“大”“小”。 + 某日,空中多了九颗赤阳星,一时间天下大旱,大火肆虐,土地皲裂。 + 叶新看着空中十颗赤阳星,抬起右手对准了其中一颗。 + 小! + 无数挣扎求存的人忽然诧异的发现,空中那争相辉映的十颗赤阳星少了一颗。 + 熊熊烈焰中,叶新看着右手中那颗乒乓球大小的金色珠子,其间一尊三足神鸟浮沉。 + 仰头,抬手。 + 叶新一口闷了那颗金色珠子,功力瞬间大涨。 + 好补品!
淘花
异世大陆
日更千字
黑暗主宰在线阅读
公元2333年,一颗微型白洞降临地球……  PS:新书《超神制卡师》已经发布,欢迎收藏。  PS:已完本《超神建模师》、《诛天图》,高订破两万,品质保证,敬请期待。
零下九十度
异世大陆
日更千字

我!清理员!在线阅读
“拿好,这是你这周的薪水。”  抬手递了个小袋子过来后,桌后面翘着二郎腿的女人随手在小本子上勾了一下,随即头也不抬地挥手撵人道:  “记得自己去报一下税……下一个!”  “等等!”  把小袋子里的钱币倒出来后,看着掌心八枚大的一枚小的,总共九枚脏兮兮的硬币,李昂不由得震惊地瞪大了双眼,恨不能当场扑过去和她决一死战。  “该死的!我这周二才刚击退了妄图侵蚀世界的邪神!你个混蛋居然连救世主的工资也要扣?”
鱼狱圄
异世大陆
日更千字
诡异星巫在线阅读
(新书《巫师:从法师塔盲盒开始》已发布,求新老书友支持~) +当第一束月光照耀在大地上,从昏暗的月光里站起来十二使徒。 +巫师,言灵,银蛇,巨人,瘟媒,活尸,骑士,炼金师,德鲁伊,邪神,血族,狼人。 +漫漫长夜里,谁是猎人,谁是祭品,谁是主宰,谁又是仆从? +狼人的爪牙,如此锋利,多么适合做我的巫器手套。 +血族的蝠翼,遮蔽街道,多么适合做我的巫器风衣。 +邪神的权杖,浸满鲜血,多么适合做我的巫器手杖。 +··· +星巫师鲁道夫,悄然行走在月夜中,他的手指划过名单,一项项搜集着他心爱的使徒遗物。
白银黑铁
异世大陆
日更千字
斗罗阿蒙:我在龙王当天尊在线阅读
南福生只是在家里刷着电视剧和小说,就莫名其妙的穿越到了斗罗大陆。 +所幸他还有自己的外挂,来自诡秘世界的源堡外加唯一性,从此…… +…… +路法(南福生分身):星罗大陆的人听着,虽然我打了你们的小公主,现在更是要打你们的大陆,但是,请你们相信我,我是一个好人。 +…… +海神湖相亲大会上 +万人瞩目,擎天斗罗的弟子,内院中的龙枪女神。 +娜儿:“佛尔思,我喜欢你。” +佛尔思·沃尔(南福生分身):“啊?可我是一个女孩子啊!” +唐舞麟:“娜儿,你……” +众人:“……” +…… +史莱克学院毁灭后。 +云冥(南福生分身):我要重建新的史莱克学院。 +暗凤斗罗冷雨莱:别说话,给我舔。 +雅莉:给我放开冥。 +天凤斗罗冷遥茱:雅莉给我滚,云冥失忆了,那正好大家公平竞争。 +(前面因为作者是萌新,所以写的有点一般,可跳到五十章来看) +作者群:957899143
鸽子成精s
异世大陆
日更千字
白金

爱潜水的乌贼

阅文集团白金作家,网络文学著名作家,2019中国原创文学风云榜总榜排名第一,中国作家协会会员。

  • 作品总数

    7
  • 累计字数

    2357.65万
  • 创作天数

    3866

更多其他作品

  • 武道宗师

    玄幻·8.9分

      在这里,武道不再是虚无缥缈的传说,而是切切实实的传承,经过与科技的对抗后,彻底融入了社会,有了各种各样的武道比赛,文无第一,武无第二!  楼成得到武道一大流派断绝的传承后,向着最初的梦想,向着心里的荣耀,一步一步前进,都市之中仍有豪侠,当今时代依存英雄!

    加入书架
  • 灭运图录

    仙侠·9.1分

      修真,去假存真,照见本性。能达到这点的,则被称为“真人”,他们成就元神,超脱生死。  灭运图录,灭运道种?  一个偶得上古仙法的穿越客在这诸天万界、亿兆大千世界的修炼故事。  群号:  一群:二一三九三三零四八(已满)  二群:一四零零三三九六零

    加入书架
  • 奥术神座

    玄幻·9.2分

      “知识就等于力量。”  “所谓神,不过是强大一点的奥术师。”  带着一大堆知识的夏风穿越而来了。  

    加入书架
  • 宿命之环

    玄幻

      诡秘世界第二部。  1368之年,七月之末,深红将从天而降。

    加入书架
  • 长夜余火

    玄幻

      灰土上所有人都相信,埋葬在危险和饥荒中的某个遗迹深处,有通往新世界的道路,只要能找到一把独特的钥匙,打开那扇门,就能进入新世界。  在那里,大地是丰饶的,就像流淌着奶与蜜,阳光是灿烂的,似乎能洗去寒冷和阴晦。人们不用再面对荒芜、怪物、感染、畸变和各种危险的事物。  在那里,孩子是快乐的,成人是幸福的,一切都是美好的。  灰土上每一个古物学者、遗迹猎人和历史研究员都知道,这里就是新世界。

    加入书架
  • 一世之尊

    玄幻·9.2分

      我这一生,不问前尘,不求来世,只轰轰烈烈,快意恩仇,败尽各族英杰,傲笑六道神魔!  万年之后,大劫再启,如来金身,元始道体,孰强孰弱,如来神掌,截天七式,谁领风骚?  轮回之中,孟奇自少林寺开始了自己“纵横一生,谁能相抗”的历程。

    加入书架
\ No newline at end of file diff --git a/test_data/https___www_ypshuo_com_api_novel_getInfo_novelId_1 b/test_data/https___www_ypshuo_com_api_novel_getInfo_novelId_1 new file mode 100644 index 00000000..1cfbb9ce --- /dev/null +++ b/test_data/https___www_ypshuo_com_api_novel_getInfo_novelId_1 @@ -0,0 +1 @@ +{"code":"00","data":{"id":1,"novel_name":"诡秘之主","category_id":1,"novel_img":"https://qidian.qpic.cn/qdbimg/349573/1010868264/300","author_name":"爱潜水的乌贼","synopsis":"蒸汽与机械的浪潮中,谁能触及非凡?历史和黑暗的迷雾里,又是谁在耳语?我从诡秘中醒来,睁眼看见这个世界:枪械,大炮,巨舰,飞空艇,差分机;魔药,占卜,诅咒,倒吊人,封印物……光明依旧照耀,神秘从未远离,这是一段“愚者”的传说。","word_number":4465200,"update_status":1,"update_explain":null,"status":2,"source":"[{\"bookId\":\"1010868264\",\"siteName\":\"起点中文网\",\"bookPage\":\"http://book.qidian.com/info/1010868264\"},{\"bookId\":\"20868264\",\"siteName\":\"创世中文网\",\"bookPage\":\"http://chuangshi.qq.com/bk/ly/20868264.html\"}]","power":"0","point":328,"score":8.7,"scorer":120,"score_1":8,"scorer_1":2,"score_2":10,"scorer_2":1,"score_3":8.7,"scorer_3":117,"create_time":1605427200,"update_time":1605427200,"novel_tags":[{"tag_name":"异世大陆"}],"novel_category":{"cate_name":"玄幻"}}} \ No newline at end of file