├── requirements.txt ├── version_info.json ├── README.md ├── .github └── workflows │ └── ci.yml ├── get_tip.py ├── get_version.py ├── tips.json ├── main.py └── LICENSE /requirements.txt: -------------------------------------------------------------------------------- 1 | pandas 2 | bs4 3 | requests -------------------------------------------------------------------------------- /version_info.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "3.18.0", 3 | "date": { 4 | "year": 2025, 5 | "month": 11, 6 | "day": 21 7 | }, 8 | "log": "" 9 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Phigros 2 | 3 | ## 版本 4 | 5 | **由于萌娘百科服务器周期性爆炸,本仓库可能不是最新。** 6 | 7 | 本仓库 Phigros 版本: `3.18.0` 8 | 9 | 更新时间: 2025.11.21 10 | 11 | 更新日志 / 官方动态: 12 | 13 | 14 | 15 | 16 | ## 介绍 17 | 18 | 自动生成萌娘百科 [Phigros/谱面信息](https://mzh.moegirl.org.cn/Phigros/谱面信息) json 数据。 19 | 通过 Github Actions 每日构建。 20 | 21 | ## 使用 22 | 23 | [`Phigros.json`](https://sakimidare.github.io/Phigros/Phigros.json) 为谱面信息; 24 | [`version_info.json`](https://sakimidare.github.io/Phigros/version_info.json) 为版本号和更新日志信息; 25 | [`tips.json`](https://sakimidare.github.io/Phigros/tips.json) 为 Phigros tips 信息。 26 | 27 | ## 开源 28 | 萌娘百科中爬取的所有内容均按照[知识共享 署名-非商业性使用-相同方式共享 3.0 (CC BY-NC-SA 3.0) 许可协议](https://creativecommons.org/licenses/by-nc-sa/3.0/cn/)开源。详情参阅[萌娘百科:著作权信息](https://mzh.moegirl.org.cn/%E8%90%8C%E5%A8%98%E7%99%BE%E7%A7%91:%E8%91%97%E4%BD%9C%E6%9D%83%E4%BF%A1%E6%81%AF)。 29 | 30 | 其他文件(包括但不限于程序源代码)按照 Apache 2.0 开源。 31 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | on: 3 | schedule: 4 | - cron: '0 22 * * *' 5 | watch: 6 | types: [started] 7 | workflow_dispatch: 8 | jobs: 9 | deploy: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v2 13 | - uses: actions/setup-python@v2 14 | with: 15 | python-version: 3.x 16 | - run: pip3 install -r requirements.txt 17 | - run: python3 main.py 18 | - run: python3 get_version.py 19 | - run: python3 get_tip.py 20 | # - run: mkdocs gh-deploy --force 21 | - name: commit 22 | env: 23 | TZ: 'CST-8' 24 | emails: ${{ secrets.GITHUB_EMAIL }} 25 | run: | 26 | sudo timedatectl set-timezone Asia/Shanghai 27 | git config --global user.email emails 28 | git config --global user.name GithubActionBot 29 | datime=$(date "+%Y年%m月%d日 %H:%M") 30 | echo "git commit: push something, $datime" 31 | if [ -n "$(git status -s)" ];then 32 | git add . 33 | git commit -m "make:action push $datime" -a 34 | fi 35 | - name: Push changes 36 | uses: ad-m/github-push-action@master 37 | with: 38 | github_token: ${{ secrets.GITHUB_TOKEN }} 39 | -------------------------------------------------------------------------------- /get_tip.py: -------------------------------------------------------------------------------- 1 | import re 2 | import requests 3 | from bs4 import BeautifulSoup, NavigableString, TemplateString 4 | import json 5 | 6 | header = { 7 | 'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:46.0) Gecko/20100101 Firefox/46.0', 8 | 'Content-Type': 'application/x-www-form-urlencoded', 9 | 'Connection': 'Keep-Alive', 10 | 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' 11 | } 12 | 13 | raw_tip_html = requests.get('https://mzh.moegirl.org.cn/Phigros',headers=header).text 14 | 15 | 16 | tip_table = BeautifulSoup( 17 | raw_tip_html, 'html.parser' 18 | ).find( 19 | attrs={'class':"mw-collapsible mw-collapsed wikitable"} 20 | ) 21 | ol_list = tip_table.find_all('ol') 22 | 23 | tip_info = {} 24 | for x in ol_list: 25 | if not ('class' in x.attrs.keys() and x.attrs['class'] == ['references']): # 可能会出错 26 | group_name = re.sub(r'\[(.*?)\]','',x.find_previous('b').get_text(types=(NavigableString, TemplateString))).strip() 27 | tips = [] 28 | for y in x: 29 | if y.name == 'li': 30 | single_tip = y.get_text(types=(NavigableString, TemplateString)).strip() 31 | single_tip = re.sub(r'引用错误:没有找到(.*)标签','',single_tip) 32 | single_tip = re.sub(r'\[(.*?)\]','',single_tip) 33 | tips.append(single_tip) 34 | tip_info[group_name]=tips 35 | 36 | with open('tips.json','w',encoding='utf-8') as f: 37 | f.write(json.dumps(tip_info,indent=4,ensure_ascii=False)) 38 | -------------------------------------------------------------------------------- /get_version.py: -------------------------------------------------------------------------------- 1 | import re 2 | import requests 3 | from bs4 import BeautifulSoup, NavigableString, TemplateString 4 | import json 5 | def str_quoted(s:str) -> str: 6 | str_list = [] 7 | for x in s.splitlines(): 8 | str_list.append('> '+x+' ') 9 | return '\n'.join(str_list) 10 | header = { 11 | 'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:46.0) Gecko/20100101 Firefox/46.0', 12 | 'Content-Type': 'application/x-www-form-urlencoded', 13 | 'Connection': 'Keep-Alive', 14 | 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' 15 | } 16 | 17 | raw_version_html = requests.get('https://mzh.moegirl.org.cn/Phigros/%E8%B0%B1%E9%9D%A2%E4%BF%A1%E6%81%AF',headers=header).text 18 | raw_log_html = requests.get('https://mzh.moegirl.org.cn/Phigros/更新记录',headers=header).text 19 | 20 | ver_text = re.search(r'本页面现已更新至(?P\d+)年(?P\d+)月(?P\d+)日更新的(?P.*)版本。',raw_version_html) 21 | 22 | ver_log_beautifulsoup = BeautifulSoup( 23 | raw_log_html, 'html.parser' 24 | ) 25 | 26 | ver_log = "" 27 | title = ver_log_beautifulsoup.find('h2') 28 | for sibling in title.next_siblings: 29 | if sibling.name == 'h2': 30 | break 31 | ver_log += sibling.get_text(types=(NavigableString, TemplateString)) 32 | 33 | ver_log = re.sub(r'\[\d+\]?','',ver_log).strip() 34 | #print('Phi 当前版本:',ver_text.group('version')) 35 | #print('Phi 更新日期:',ver_text.group('year')) 36 | year = int(ver_text.group('year')) 37 | month = int(ver_text.group('month')) 38 | day = int(ver_text.group('day')) 39 | date = { 40 | 'year':year, 41 | 'month':month, 42 | 'day':day 43 | } 44 | info = { 45 | 'version':ver_text.group('version'), 46 | 'date':date, 47 | 'log':ver_log 48 | } 49 | with open('version_info.json','w',encoding='utf-8') as f: 50 | f.write(json.dumps(info,indent=4,ensure_ascii=False)) 51 | 52 | readme = open('README.md', encoding='utf-8').read() 53 | readme = re.sub(r'(.*)',' `{}` '.format(ver_text.group('version')),readme) 54 | readme = re.sub(r'(.*)','\n{}\n'.format(str_quoted(ver_log)).replace('\\','\\\\'),readme,flags=16) 55 | readme = re.sub(r'(.*)',r' {}.{}.{} '.format(year,month,day),readme) 56 | with open('README.md','w',encoding='utf-8') as f: 57 | f.write(readme) 58 | -------------------------------------------------------------------------------- /tips.json: -------------------------------------------------------------------------------- 1 | { 2 | "提示": [ 3 | "等一下!请检查设备周围是否有水杯,要是碰到的话…嘶——", 4 | "长时间打歌会有引发腱鞘炎的风险哦,注意休息。", 5 | "玩久了,一定要记得闭上眼睛休息一会哦~", 6 | "如果打歌感到不舒畅,起身走走,然后回来,会好很多。", 7 | "如果不想被打断,那就开启手机的免打扰吧!", 8 | "不知道如何解锁一些特定歌曲?可以从收集品中寻找一下线索哦!", 9 | "戴上耳机以获取最佳体验", 10 | "上下滑动可以切换歌曲,点击曲绘可以开始游戏,左下的难度指示器点击对应难度即可切换难度……已经是老生常谈了吧?", 11 | "按键大小不舒服?在设置中可以调整大小!", 12 | "多多游玩Phigros有助于放松手指以及锻炼大脑协调能力哦!", 13 | "听说完成主线后,小鸽子们的Phigros都发生了不小的变化……", 14 | "Full Combo就是打中所有note咕!", 15 | "想要提升rks的话,尝试把困难的谱面打得更准咕!", 16 | "主线章节一~四已整理进Legacy章节", 17 | "快睡觉吧,熬夜对身体不好", 18 | "进入设置后可以更换头像与名片背景", 19 | "今天的随机歌曲是……?", 20 | "如果没法决定玩哪首歌,何不试试随机曲目功能呢~", 21 | "物量不等于难度哦咕咕!", 22 | "歌曲可以用标题、难度、分数的分类顺序或逆序排序咕!", 23 | "设备性能不足的小鸽子们可以使用设置中的低分辨率模式来获得更流畅的体验。", 24 | "WOW 虫眼!", 25 | "在遇到游戏音频出现异常的时候,试试拉高下设置>其他>音频问题疑难解答中的值哦!", 26 | ":-):手法.exe未响应,如果继续推进会导致推分失败。是否继续?【休息一下/强行推进】", 27 | "音游关卡就像海洋,只有意志坚强的人才能到达φ的彼岸" 28 | ], 29 | "咕!咕!咕!": [ 30 | "咕咕咕~如果你正开心,希望Phigros能让你笑颜常开哦!", 31 | "咕咕咕~如果你正糟心,希望Phigros能带你扬眉吐气哦!", 32 | "咕咕咕!请不要在任何无关场合提及Phigros哦!谢谢配合!咕咕咕!", 33 | "来唱歌!咕!咕!咕咕咕!", 34 | "帅鸽的话,只要像这样,dong~dong~dong~,就可以快速收歌哦,来,试试看!", 35 | "我们的口号是?咕咕咕!", 36 | "饿啊!咕咕咕咕", 37 | "前排出售美味鸽粮咕~", 38 | "(·▽·)咕咕~", 39 | "我变成鸽子了!!!" 40 | ], 41 | "鸽游": [ 42 | "新版本请多多关照!发现bug请拨打:contact@pigeongames.cn", 43 | "欢迎在B站@Phigros官方关注我们!", 44 | "鸠和基诺会一直陪伴着你。。只要你不卸载Phigros的话!", 45 | "希望phigros能陪伴你们到天长地久,抱抱", 46 | "3.0啦,大家都长大啦ww", 47 | "鸽游的小鸽子们每天都在熬夜开发3.0版本,都快熬秃了头,生发水什么的可以来点吗……?", 48 | "我觉得生发剂不一定有用,得植发", 49 | "诶…防脱洗发水用完了…", 50 | "鸽游的烧烤摊包含了驴肉、欧芹、油条、完全熟不透的牛角等等,唯独就是没有烤翅……", 51 | "不要烤翅……", 52 | "聚是一团鸽,散作满天鸽", 53 | "急招美工", 54 | "鸠:“我可以成为偶像吗?”", 55 | "请给我们的pv组捐点硬盘吧!!非常感谢!", 56 | "你们熟知的PV组已经正式更名为Pigeon Animation Team了哦(怎么这么长)", 57 | "不要的显卡统统可以拿到Pigeon Animation Team换不锈钢脸盆", 58 | "你知道吗?鸽游于2019年2月8号成立,8月31日则是Phigros的生日哦", 59 | "在B站@Phigros官方 关注我们以获取最新的更新预告咕!", 60 | "众所周知,鸽游一年有377天", 61 | "这里是鸽游!", 62 | "感谢各位小鸽子们陪伴我们走过了五个年头", 63 | "打击头部不会使更新速度加快", 64 | "你喜欢上面的这张曲绘么?" 65 | ], 66 | "谱面与打歌相关": [ 67 | "歌终有一收,而有些需要一点小小的帮助(指旋转设备", 68 | "谱面难度各有千秋,因人而异,因地力制宜(?", 69 | "看到了比较怪异而难以下手的配置?谱面之中往往存在提示,睁大眼睛仔细观察吧。", 70 | "尝试获得更高的acc比获得更高的分数更能够提升自己的水平。", 71 | "为防误触,暂停键需要点两次才可以暂停。", 72 | "如果觉得推分乏力,容易反复失误的话,可以试试谱面镜像功能哦~", 73 | "面对满屏幕的按键感到不知所措?可以多多尝试以发现其中的规律。", 74 | "开启多押提示可以更好地帮助你找准歌曲节奏", 75 | "为什么有些难度没有解锁啊! -因为你的前一难度的成绩还没达到S哦,请多多努力吧!", 76 | "有时判定线也会提示你音符接下来会下落的位置,注意观察吧!", 77 | "有时候Note本身也可以充当判定线的替身哦", 78 | "有些音符会跟随音高排列哦,用心感受音乐的律动吧~", 79 | "我们在EZ、HD谱面上也下了很多功夫咕~", 80 | "听说有时候次难度也会整大活,赶紧来试试吧!", 81 | "活用垂直判定可以打出很多炫酷的打法!", 82 | "我的转板不会输!", 83 | "如果你想打的更精准一些,可以尝试使用节拍器(?)", 84 | "愿大家都能板子不吃音打出好成绩" 85 | ], 86 | "note相关": [ 87 | "给多押note镀层金,我就是这个谱面里最靓的仔", 88 | "如何游玩粉键? ↑←↙→↗↓↖↗↓↑→↙←……", 89 | "这个才是真的note哦~(miss)", 90 | "看,那里有一个“note”", 91 | "落到判定线上的note竟然不是这根判定线的…!", 92 | "这里为什么会有note啦!" 93 | ], 94 | "判定线": [ 95 | "这日子是越来越有判头了(指判定线", 96 | "假如,我是说假如,判定线能够自由地动起来…" 97 | ], 98 | "课题模式": [ 99 | "如果想要挑战自己,可以试一试课题模式?", 100 | "愿小鸽子们都能在课题中达到“此地有金三百万”", 101 | "完成主线后,课题模式就会解锁哦!", 102 | "课题模式会更难拿到All Perfect……好难……", 103 | "彩~虹~课~题~模~式~" 104 | ], 105 | "Tips": [ 106 | "猜猜你要重新加载多少次才能再看到这条tip ̄︶ ̄", 107 | "这是一条属于3.0版本的Tips!;", 108 | "print(\"Hello tips3.0\");", 109 | "来猜猜看这边有几个有用的信息呢~", 110 | "你知道吗?其实tips全都是废话(确信", 111 | "啊!要给你看什么Tip好呢…(翻", 112 | "突然来了一条消息!          哦这里是tips啊,那没事了", 113 | "有没有数过这是你第几次看到这条tips呢?", 114 | "这是一条属于1.0版本的Tips!(错乱)", 115 | "我们通过大数据分析您的喜好查找能获得更高浏览量的tips。", 116 | "Tip:Tip:Tip:Tip:Tip:Tip:Tip:Tip:Tip:", 117 | "", 118 | "提问!你还记得上一条tip是什么吗?" 119 | ], 120 | "心灵鸡汤": [ 121 | "我相信你。", 122 | "不要在意他人对你说什么,你独一无二,你是你自己的光", 123 | "当你在三次觉得诸事不顺的时候,看看现在的打歌成绩,比起刚入坑的时候,是不是提高了很多?现在也是哦,你一直都在成长", 124 | "下次的成绩一定会更好!" 125 | ], 126 | "江源速报": [ 127 | "江源速报:拟态系统PhigrOS,将于8月31号正式上线", 128 | "江源速报:PhigrOS内测开放新节点,完全复原冰封后地表实录", 129 | "江源速报:PHI集团负责人失踪三日,警方仍在调查中", 130 | "江源速报:PHI集团负责人回归,自杀传言不攻而破", 131 | "江源速报:名人自杀现象异常扩散,知名作家留下诡异遗书", 132 | "江源速报:知名歌手何琼语于昨夜凌晨意外死亡,凶手仍在追查中", 133 | "江源速报:警方发表惊人结果,何琼语原系自杀身亡", 134 | "江源速报:天后横死案新进展,凶手恐为桥民流浪汉", 135 | "江源速报:三大基地全面开放通行,冰封纪元即将结束?", 136 | "江源速报:专家呼吁复兴AI产业,以应对劳动力紧缺问题", 137 | "江源速报:政府出台就业新策,望促进失业人员再就业", 138 | "江源速报:多地出现无故昏厥人员,卫生部呼吁民众注意饮食健康", 139 | "江源速报:全球年均温再度上升,重返地表签名破千万", 140 | "江源速报:群体性臆症爆发,多人自称蜂巢C区存在巨塔", 141 | "江源速报:巨塔效应急剧化,神秘群体林泊浮出水面", 142 | "江源速报:上半年人口增长率再创新低,新型受精技术受挫", 143 | "我被困在林泊百科里了!救命!", 144 | "像素塔真的存在吗。", 145 | "Saturn新闻报道:插播一条紧急播报,请不要看向晚上的天空或月亮。", 146 | "现在!快看向外面的月亮!", 147 | "啊!PhigrOS又崩溃了……" 148 | ], 149 | "曲目相关": [ 150 | "对不起,你所拨打的电话号码是空号-Sorry, the number you dialed does not exist", 151 | "72788433374733678633778263464", 152 | "Let's! Get! Higher!!!", 153 | "One! Two! Three! Fire!!!", 154 | "Hit me with the HARDCORE!!!", 155 | "E! S! M! Power!", 156 | "NO ONE YES PIGEONS", 157 | "Yooooooooooooooooooo", 158 | "噔噔噔 噔噔 噔噔 噔噔噔噔噔噔", 159 | "INTeRneT ENERGY -Overdose- ", 160 | "WHAT DO YOU KNOW WHAT DO YOU PLAY WHAT DO YOU REMEMBER WHAT DO YOU LOVE", 161 | "This is the story for one character of misery", 162 | "Funding for this program was made possible by viewers like you", 163 | "不要喝奇怪的品红色药水!", 164 | "Tell Me Your Secret", 165 | "小鸽子们不要挑食哦,不管是烤鸭还是欧芹都要吃~", 166 | "(Not) Sound Only", 167 | "Redemption.", 168 | "小心翼翼千万别被发现", 169 | "与普遍的看法相反,opia不是一首关于眼病的歌", 170 | "See You Next Time", 171 | "♪Wish upon a satellite…", 172 | "♪别忘记今天好好享受毋庸置疑,明天是明天仍有期待心情~", 173 | "♪Play like you never did before~", 174 | "啊~啊~啊咦↑啊咦↑啊→啊↑啊↓啊~啊~", 175 | "Compute It With Some…什么来着?", 176 | "CONDITIO SINE QUA NON", 177 | "选中《Random》的时候长按随机按钮有惊喜", 178 | "勇敢之路" 179 | ], 180 | "其他与玩梗": [ 181 | "φ?拿来吧你!", 182 | "有一个人前来打歌", 183 | "阿鸠你又在反复看Tips了哦", 184 | "手持两把锟斤拷,口中疾呼烫烫烫", 185 | "热知识:这是一条…烫烫烫烫烫!的热知识。", 186 | "冷知识:这是一条…啊嚏!…冷知识!", 187 | "时间滴滴答答在走,这首歌你φ了没有?", 188 | "上次看到这条Tip还是在上次", 189 | "你AP了,就一定AP了吧!", 190 | "扉格晚五点,周五准时更新!", 191 | "高三党,现在,立刻,去给我学习!!!", 192 | "你先别急!!这不有云存档嘛", 193 | "自从使用了同步存档,手也不酸了,头也不痛了,推分也来劲了!", 194 | "当你在看这行字的时候 我就知道 你肯定在看这行字", 195 | "!!", 196 | "我超,劲爆", 197 | "AT的意思并不是Anti-Thumb(", 198 | "EZ是指摁着而非Easy,HD是高清而非Hard,IN是里面而非Insane,AT是位于而非Another,等会我是不是说反了?", 199 | "分数我所欲也,acc亦我所欲也,若二者不可得兼,多练也。", 200 | "声音传播需要介质", 201 | "你打一首歌的时间,鸠已经发现 NaN 个问题了", 202 | "sudo 板子自己打歌", 203 | "rks是RankingScore,不是热开水!(认真脸)", 204 | "如何做到毫无创作瓶颈?答案是有瓶颈的时候不创作", 205 | "今日打歌对决强者谱面,恐怖配置猛如鬼神,拼尽全力战胜它!", 206 | "《五年课题,三年单曲》", 207 | "←To Be Continued…", 208 | "我确信我发现了一个能百分百拿到φ的绝妙手法,可惜Tips的长度太短了,写不下", 209 | "不是,鸽们", 210 | "如何玩好Phigros:第一步:玩Phigros!", 211 | "别慌!这只是个鸽子陷阱而已啦~", 212 | "欢迎回到Phigros!", 213 | "赛博鸽子会梦到Phigros吗(", 214 | "兄弟,鸽子不错,摸摸", 215 | "附近5米内,有一只鸽子,正在靠近……", 216 | "你看这个巨型鸽子,它已经吃了2147483647个note了……嗯怎么突然消失了!", 217 | "你看这个巨型鸽子,他已经吃了-1个note了……?", 218 | "兄弟!你好强!", 219 | "堂 堂 联 动", 220 | "小鸽子们也要多多支持其他音乐游戏呦~", 221 | "想要5000TB Data", 222 | "top10我最喜欢的鸽子——top1:鸠!", 223 | "这张谱看起来好可怕……" 224 | ] 225 | } -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | import json 2 | import re 3 | import requests 4 | from bs4 import BeautifulSoup, NavigableString, TemplateString 5 | 6 | def go(st): 7 | if st is None: 8 | return "" 9 | else: 10 | if st: 11 | return str(st).strip() 12 | else: 13 | return "undefined" 14 | 15 | def get_stripped_strings(stripped_strings): 16 | for x in stripped_strings: 17 | return x 18 | header = { 19 | 'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:46.0) Gecko/20100101 Firefox/46.0', 20 | 'Content-Type': 'application/x-www-form-urlencoded', 21 | 'Connection': 'Keep-Alive', 22 | 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' 23 | } 24 | mew = requests.get('https://mzh.moegirl.org.cn/Phigros/%E8%B0%B1%E9%9D%A2%E4%BF%A1%E6%81%AF', headers=header) 25 | soup = BeautifulSoup(mew.text,'html.parser') 26 | ul_data = soup.find_all('table', class_='wikitable') 27 | items = (ul_data[0].find_all("td")) 28 | data_list = {} 29 | for idx, item in enumerate(ul_data): 30 | # print(idx) 31 | # print(item) 32 | if idx+1: 33 | tds = item.find_all('td') 34 | song = re.sub(r'\[\d+\]','',item.th.get_text(types=(NavigableString, TemplateString))) 35 | print(song) 36 | try: 37 | illustration = tds[0].a.img.get('src') 38 | except: 39 | illustration = 'undefined' 40 | illustration_big = illustration.replace('thumb/','').rsplit('/',1)[0] 41 | chapter = item.find('td', text="所属章节").find_next("td").get_text(types=(NavigableString, TemplateString)) 42 | bpm = item.find('td', text="BPM").find_next("td").get_text(types=(NavigableString, TemplateString)) 43 | composer = re.sub(r'\[\d+\]','',item.find('td', text="曲师").find_next("td").get_text(types=(NavigableString, TemplateString))) 44 | get_len = item.find('td', text="时长") or item.find('td', text="长度") 45 | length = get_len.find_next("td").get_text(types=(NavigableString, TemplateString)) 46 | illustrator = re.sub(r'\[\d+\]','',item.find('td', text="画师").find_next("td").get_text(types=(NavigableString, TemplateString))) 47 | chart = {} 48 | if not item.find('td', text="EZ") is None: 49 | current = item.find('td', text="EZ").find_next('td') 50 | ez_level = current.get_text(types=(NavigableString, TemplateString)) 51 | current = current.find_next("td") 52 | ez_difficulty = current.get_text(types=(NavigableString, TemplateString)) 53 | current = current.find_next("td") 54 | ez_combo = current.get_text(types=(NavigableString, TemplateString)) 55 | current = current.find_next("td") 56 | ez_charter = re.sub(r'\[\d+\]','',current.get_text(types=(NavigableString, TemplateString))) 57 | # raise ValueError 58 | chart["EZ"] = { 59 | "level": go(ez_level), 60 | "difficulty": go(ez_difficulty), 61 | "combo": go(ez_combo), 62 | "charter": go(ez_charter) 63 | } 64 | #print(chart["EZ"]) 65 | else: 66 | ez_level = 0 67 | ez_difficulty = 0 68 | ez_combo = 0 69 | ez_charter = 0 70 | 71 | if not item.find('td', text="HD") is None: 72 | current = item.find('td', text="HD").find_next('td') 73 | hd_level = current.get_text(types=(NavigableString, TemplateString)) 74 | current = current.find_next("td") 75 | hd_difficulty = current.get_text(types=(NavigableString, TemplateString)) 76 | current = current.find_next("td") 77 | hd_combo = current.get_text(types=(NavigableString, TemplateString)) 78 | current = current.find_next("td") 79 | hd_charter = re.sub(r'\[\d+\]','',current.get_text(types=(NavigableString, TemplateString))) 80 | 81 | chart["HD"] = { 82 | "level": go(hd_level), 83 | "difficulty": go(hd_difficulty), 84 | "combo": go(hd_combo), 85 | "charter": go(hd_charter) 86 | } 87 | else: 88 | hd_level = 0 89 | hd_difficulty = 0 90 | hd_combo = 0 91 | hd_charter = 0 92 | 93 | if not item.find('td', text="IN") is None: 94 | current = item.find('td', text="IN").find_next('td') 95 | in_level = current.get_text(types=(NavigableString, TemplateString)) 96 | current = current.find_next("td") 97 | in_difficulty = current.get_text(types=(NavigableString, TemplateString)) 98 | current = current.find_next("td") 99 | in_combo = current.get_text(types=(NavigableString, TemplateString)) 100 | current = current.find_next("td") 101 | in_charter = re.sub(r'\[\d+\]','',current.get_text(types=(NavigableString, TemplateString))) 102 | 103 | chart["IN"] = { 104 | "level": go(in_level), 105 | "difficulty": go(in_difficulty), 106 | "combo": go(in_combo), 107 | "charter": go(in_charter), 108 | } 109 | 110 | else: 111 | in_level = 0 112 | in_difficulty = 0 113 | in_combo = 0 114 | in_charter = 0 115 | 116 | if not item.find('td', text="Legacy") is None: 117 | current = item.find('td', text="Legacy").find_next('td') 118 | lc_level = current.get_text(types=(NavigableString, TemplateString)) 119 | current = current.find_next("td") 120 | lc_difficulty = current.get_text(types=(NavigableString, TemplateString)) 121 | current = current.find_next("td") 122 | lc_combo = current.get_text(types=(NavigableString, TemplateString)) 123 | current = current.find_next("td") 124 | lc_charter = re.sub(r'\[\d+\]','',current.get_text(types=(NavigableString, TemplateString))) 125 | chart["Legacy"] = { 126 | "level": go(lc_level), 127 | "difficulty": go(lc_difficulty), 128 | "combo": go(lc_combo), 129 | "charter": go(lc_charter), 130 | } 131 | 132 | else: 133 | lc_level = 0 134 | lc_difficulty = 0 135 | lc_combo = 0 136 | lc_charter = 0 137 | if not item.find('td', text="AT") is None: 138 | current = item.find('td', text="AT").find_next('td') 139 | at_level = current.get_text(types=(NavigableString, TemplateString)) 140 | current = current.find_next("td") 141 | at_difficulty = current.get_text(types=(NavigableString, TemplateString)) 142 | current = current.find_next("td") 143 | at_combo = current.get_text(types=(NavigableString, TemplateString)) 144 | current = current.find_next("td") 145 | at_charter = re.sub(r'\[\d+\]','',current.get_text(types=(NavigableString, TemplateString))) 146 | 147 | chart["AT"] = { 148 | "level": go(at_level), 149 | "difficulty": go(at_difficulty), 150 | "combo": go(at_combo), 151 | "charter": go(at_charter) 152 | } 153 | else: 154 | at_level = 0 155 | at_difficulty = 0 156 | at_combo = 0 157 | at_charter = 0 158 | 159 | if go(song) == "Another Me": 160 | if go(composer) == "Neutral Moon": 161 | song = "Another Me (Rising Sun Traxx)" 162 | else: 163 | song = "Another Me (KALPA)" 164 | if go(song) == "The Mountain Eater from MUSYNC": 165 | song = "The Mountain Eater" 166 | if go(song).find('Cipher') != -1: 167 | song = 'Cipher: /2&//<|0' 168 | data_list[go(song)] = { 169 | "song": go(song), 170 | "illustration": go(illustration), 171 | "illustration_big": go(illustration_big), 172 | "chapter": go(chapter), 173 | "bpm": go(bpm), 174 | "composer": go(composer), 175 | "length": go(length), 176 | "illustrator": go(illustrator), 177 | "chart": chart 178 | } 179 | data = json.dumps(data_list, indent=4, ensure_ascii=False) 180 | 181 | with open("Phigros.json", 'w+', encoding='utf-8') as f: # 如果filename不存在会自动创建, 'w'表示写数据,写之前会清空文件中的原有数据! 182 | f.write(data) 183 | 184 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | --------------------------------------------------------------------------------