吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2648|回复: 53
收起左侧

[Python 原创] python版的一个有声小说抓取批量下载工具

  [复制链接]
最新的 发表于 2024-1-7 17:33
本帖最后由 最新的 于 2024-1-20 21:55 编辑

原文贴基础上从PHP修改为Python版本,增加如下README所述功能,也征得原作者同意进行发帖

原贴地址:https://www.52pojie.cn/thread-1877570-1-1.html

如有不妥之处将及时修改!侵则删!

PixPin_2024-01-07_17-07-10.png

[Python] 纯文本查看 复制代码
# **************************************************
# **************************************************
# 免责声明:
# 本代码仅供学习和研究使用,严禁用于任何商业用途。
# 作者不对使用本代码导致的任何后果负责。
# 在使用本代码时,请遵守相关法律法规和网站的使用规定。
# **************************************************

import os
import tkinter as tk
from tkinter import simpledialog
import requests
import re
import json

# ANSI转义码
class Colors:
    RED = '\033[91m'
    YELLOW = '\033[93m'
    GREEN = '\033[92m'
    ENDC = '\033[0m'

def clean_filename(filename):
    # 移除非法字符
    return re.sub(r'[\/:*?"<>|]', '', filename)

def download_novel(id, page_num, start_page):
    current_page_file = f"pageid_{id}.txt"

    base_url = "https://www.ysts.cc/tingshu"
    session = requests.Session()

    for current_page in range(start_page, page_num + 1):
        url = "{}/{}/?p={}".format(base_url, id, current_page)
        headers = {
            'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
            'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6,ja;q=0.5,zh-TW;q=0.4',
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0',
            'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
            'Origin': 'http://www.ysts.cc',
            'Referer': '{}/{}/41440.html'.format(base_url, id),
        }

        try:
            response = download_file(session, url, headers)
            a_rule = fr'<a href="/tingshu/{id}/(\d+)\.html" target="_blank" title="([^"]+)">'
            match_a = re.findall(a_rule, response.text, re.S)

            if not match_a:
                print(Colors.RED + "未获取到数据,请检查输入参数是否正确!" + Colors.ENDC)
                return

            # 创建整个音频的保存路径
            folder_path = os.path.join("Novel audio", f"ID_{id}")
            os.makedirs(folder_path, exist_ok=True)

            for match in match_a:
                mid = match[0]
                name = match[1]
                name_cleaned = clean_filename(name)
                url = "{}/{}/{}.html".format(base_url, id, mid)
                response = download_file(session, url, headers)
                c_rule = r'<meta name="_c" content="([^"]+)" />'
                match_b = re.findall(c_rule, response.text, re.S)

                if not match_b:
                    print(Colors.RED + "未获取SC" + Colors.ENDC)
                    return

                sc = match_b[0]
                play_url = "https://www.ysts.cc/api/act/play"
                headers_play = headers.copy()
                headers_play["sc"] = sc
                print(f"{name}...")

                params_play = {'nid': id, 'cid': mid}
                response_play = session.post(play_url, headers=headers_play, data=params_play, timeout=60)
                response_play.raise_for_status()

                # Check if the response is JSON
                if 'application/json' in response_play.headers['content-type']:
                    try:
                        result_play = response_play.json()
                    except json.JSONDecodeError:
                        print(Colors.RED + "未能正确解析JSON响应" + Colors.ENDC)
                        return
                else:
                    print(Colors.RED + "未获取正确的播放数据" + Colors.ENDC)
                    return

                novel_title_rule = r'<title>(.*?)</title>'
                novel_title_match = re.search(novel_title_rule, response.text)

                if novel_title_match:
                    novel_title = clean_filename(novel_title_match.group(1).strip())
                else:
                    print(Colors.RED + "未获取小说标题" + Colors.ENDC)
                    return

                # 检查文件是否已存在
                audio_file_path = os.path.join(folder_path, f"{name_cleaned}.m4a")
                if os.path.exists(audio_file_path):
                    print(Colors.YELLOW + f"此音频文件已存在,跳过下载!" + Colors.ENDC)
                else:
                    # 保存音频文件
                    with open(audio_file_path, "wb") as file:
                        file.write(download_file(session, result_play['url'], headers_play, timeout=60).content)
                    print(Colors.GREEN + "此音频下载完成!\n" + Colors.ENDC)

            # 将当前页数写入文件
            with open(current_page_file, "w") as file:
                file.write(str(current_page))
                
            print(Colors.GREEN + "全部下载完成" + Colors.ENDC)
        except KeyboardInterrupt:
            print(Colors.YELLOW + "下载已被用户中断!" + Colors.ENDC)
            break
        except Exception as e:
            print(Colors.RED + f'下载失败:{str(e)}' + Colors.ENDC)
            break

def download_file(session, url, headers, params=None, method='GET', timeout=30):
    response = session.request(method, url, headers=headers, params=params, timeout=timeout)
    response.raise_for_status()
    return response

def main():
    root = tk.Tk()
    root.withdraw()  # 不显示 tkinter 窗口

    try:
        album_id = simpledialog.askinteger("输入", "请输入专辑ID:")
        page_num = simpledialog.askinteger("输入", "请输入总下载页数:")
        start_page = simpledialog.askinteger("输入", "请输入从第几页开始下载:")
        download_novel(album_id, page_num, start_page)

        
    except KeyboardInterrupt:
        print(Colors.YELLOW + "下载已被用户中断!" + Colors.ENDC)
    except Exception as e:
        print(Colors.RED + f'下载失败:{str(e)}' + Colors.ENDC)


if __name__ == "__main__":
    main()


使用方法

  1. 运行脚本时,输入专辑 ID 和下载页数。
  2. 脚本会自动下载指定专辑的音频,并保存到名为 "Novel audio" 的文件夹下的专辑ID子文件夹 "ID_XXXXX" 。
  3. 在下载过程中,可以通过键盘中断(Ctrl+C)来停止下载。

主要特点

  • 交互式输入: 使用 Tkinter 提供的简单对话框,用户可以轻松输入专辑 ID 和下载页数。
  • 下载续传: 脚本支持从指定页数继续下载,避免重复下载已有音频。
  • 下载进度提示: 在下载过程中,脚本会输出当前下载的音频信息,包括音频标题和下载状态。
  • 文件存在检查: 在下载前会检查音频文件是否已存在,避免重复下载相同的音频。
  • 异常处理: 对可能的异常情况进行了处理,包括网络请求失败、JSON 解析错误等。
  • 输出着色: 使用 ANSI 转义码实现输出文字的着色,以区分不同类型的输出信息。例如,错误信息为红色,警示信息为黄色,成功信息为绿色。
  • 用户中断处理: 用户可以通过 Ctrl+C 中断下载,并会有相应的提示。

修复BUG

  • 下载逻辑问题:原始代码存在一个逻辑问题,用户在输入总页数和起始页数后,调用 download_novel 函数时只会下载一次页面而不进行循环下载,导致下载过程在完成一个页面后就停止。

注意事项

  • 请确保使用脚本的行为符合相关网站的使用协议。
  • 下载过程中可能会因网络原因导致下载失败,可以重新运行脚本进行续传。

希望这个脚本能够方便你获取喜欢的小说音频,祝你使用愉快!

免费评分

参与人数 12吾爱币 +19 热心值 +11 收起 理由
mixting + 1 + 1 可以更新个 ting13.com 额么?
天空宫阙 + 2 + 1 用心讨论,共获提升!
fyypll + 1 + 1 谢谢@Thanks!
wapjsx + 1 + 1 谢谢@Thanks!
DouhiroKwok + 1 + 1 我很赞同!
Ace803 + 1 + 1 我很赞同!
yzmb8456 + 1 + 1 谢谢@Thanks!
soughing + 1 + 1 我很赞同!
苏紫方璇 + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
2070468250 + 1 + 1 鼓励转贴优秀软件安全工具和文档!
hc3w + 1 + 1 用心讨论,共获提升!
pod2023 + 1 谢谢@Thanks!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

52soft 发表于 2024-1-7 18:13
这个技术很牛
mixting 发表于 2024-3-5 10:29
本帖最后由 mixting 于 2024-4-19 19:40 编辑

可以修改个,ting13 的吗? 或者ttoow.com 也行。 好像是同一套程序,只是网址规则不一样
topweal 发表于 2024-1-7 17:46
Wapj_Wolf 发表于 2024-1-7 17:48
PY源码可以学习,小说还是喜欢看。
CQGaxm 发表于 2024-1-7 17:58
感谢分享,可以试一下
小六耳 发表于 2024-1-7 18:32
看起来不错啊,试试看咯
urdarling 发表于 2024-1-7 18:46
这个抓取的是哪个网站的
非常帅气的青年 发表于 2024-1-7 18:47
感谢大佬分享
WJayden 发表于 2024-1-7 18:49
感谢大佬分享
w261514701 发表于 2024-1-7 18:57
感谢分享
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-5-9 03:47

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表