Python爬虫使用实例-mdrama

news2024/11/30 18:56:18

一个Python爬虫使用实例:主要用于下载指定的剧集音频。分别从网页和json文件中获取剧集的title和剧集中所存在音频的id,调用you-get,最后自动重命名下载文件夹为剧集名title。

目标网址:

https://www.missevan.com/mdrama/×××××

其中×××××为drama的id,例如28021

  • 从getdrama的json文件中获取drama列表中的id和name
  • 用you-get获取音乐1.使用pyautogui调用you-get ,2. 使用 os.system() 直接调用 you-get 命令行工具】
  • drama文件夹自动重命名为剧集名
  • 下载多个drama

一、获取资源

在这里插入图片描述
首先明确需求,需要获取音频的id和name分别作为data和title,查看源码,发现看不到:
在这里插入图片描述

可以从getdrama的json文件中获取id和name(不,用you-get的话只需要id)。
在这里插入图片描述
以28021为例,0-276,共277个music
在这里插入图片描述
小细节:听剧的时候一般是不会出现drama的,他一般是出现sound/player,点大标题可以跳转到drama,或者去源码查看(关于url)
在这里插入图片描述

二、发送请求

获取json文件

json_url = f'https://www.missevan.com/dramaapi/getdrama?drama_id={drama_id}'
# 将获取的 JSON 数据写入文件
with open('getdrama.json', 'w', encoding='utf-8') as f:
    f.write(response.text)

读取json文件

# 读取 getdrama.json 文件
with open('getdrama.json', 'r', encoding='utf-8') as f:
    content = f.read()

因为用的是you-get,需要提前切换到西文状态下,而文件夹名可能含有中文字符,所以在download之后才重命名为title。

# 下载音频文件
download_dir = 'D:/drama1/'
if not os.path.exists(download_dir):
    os.mkdir(download_dir)
    
(省略部分代码....)

download()
os.rename(download_dir, f'D:/{title}/')

三、数据解析

获取drama的id

drama_id = re.search(r'/mdrama/(\d+)', url).group(1)  # 提取 drama_id

获取drama的名称:

title = selector.css('.title-content::text').get().replace(' ','').replace('\n','')

获取drama中音频的id

# 匹配包含 "id" 和 "sound_id" 的 JSON 对象
pattern = r'\{"id":.*?\}'  # 正则表达式匹配模式
matches = re.findall(pattern, content)

# 提取匹配的 JSON 对象中的所需字段
results = []

for match in matches:
    try:
        data_dict = json.loads(match)
        sound_id = data_dict.get("sound_id")
        if sound_id:
            results.append({"name": data_dict.get("name"), "sound_id": sound_id})
    except json.JSONDecodeError:
        continue  # 忽略 JSON 解码错误

# 将结果列表转换为 DataFrame
df = pd.DataFrame(results)

四、保存数据

you-get -o {download_dir} {url}

五、代码实现

1/ 单个剧集

单个drama可以自动改文件名 ,drama列表暂时不能

# 单个剧集mdrama 下载后自动改文件名
import os
import re
import json
import time
import requests
import parsel
import pyautogui
import pyperclip
import pandas as pd

url ='https://www.missevan.com/mdrama/23468'
headers = {'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.139 Safari/537.36'}
drama_id = re.search(r'/mdrama/(\d+)', url).group(1)  # 提取 drama_id
json_url = f'https://www.missevan.com/dramaapi/getdrama?drama_id={drama_id}'
response = requests.get(json_url)
response1 = requests.get(url=url,headers=headers)
selector = parsel.Selector(response1.text)
title = selector.css('.title-content::text').get().replace(' ','').replace('\n','')
invalid_chars_pattern = r'[\/:*?"<>|]' # 定义需要替换的非法字符
title = re.sub(invalid_chars_pattern, '|', title) # 将非法字符替换为空格
print(title)
# 将获取的 JSON 数据写入文件
with open('getdrama.json', 'w', encoding='utf-8') as f:
    f.write(response.text)

# 读取 getdrama.json 文件
with open('getdrama.json', 'r', encoding='utf-8') as f:
    content = f.read()

# 匹配包含 "id" 和 "sound_id" 的 JSON 对象
pattern = r'\{"id":.*?\}'  # 正则表达式匹配模式
matches = re.findall(pattern, content)

# 提取匹配的 JSON 对象中的所需字段
results = []
for match in matches:
    try:
        data_dict = json.loads(match)
        sound_id = data_dict.get("sound_id")
        if sound_id:
            results.append({"name": data_dict.get("name"), "sound_id": sound_id})
    except json.JSONDecodeError:
        continue  # 忽略 JSON 解码错误

# 将结果列表转换为 DataFrame
df = pd.DataFrame(results)

# 下载音频文件
download_dir = 'D:/drama1/'
if not os.path.exists(download_dir):
    os.mkdir(download_dir)

# 打开命令提示符
pyautogui.hotkey("win", "r")
pyautogui.typewrite('cmd')
time.sleep(3)
pyautogui.press('enter')
time.sleep(3)

def download():
    for sound_id in df['sound_id']:
        url = f"https://www.missevan.com/sound/player?id={sound_id}"
        pyautogui.typewrite(f'you-get -o {download_dir} {url}')
        # pyperclip.copy(url)
        # pyautogui.hotkey("ctrl", "v")
        pyautogui.press("enter")

download()
os.rename(download_dir, f'D:/{title}/')

2/ 剧集列表

url是列表:

import os
import re
import json
import time
import requests
import parsel
import pyautogui
import pyperclip
import pandas as pd

# 设置多个剧集的 URL 列表
urls = [
    'https://www.missevan.com/mdrama/23468',
    'https://www.missevan.com/mdrama/1003',  # 添加更多剧集的 URL
    # 可以继续添加其他 URL
]
# 遍历每个 URL 进行处理
for url in urls:
    headers = {
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.139 Safari/537.36'}
    drama_id = re.search(r'/mdrama/(\d+)', url).group(1)  # 提取 drama_id
    json_url = f'https://www.missevan.com/dramaapi/getdrama?drama_id={drama_id}'
    response = requests.get(json_url)
    response1 = requests.get(url=url, headers=headers)
    selector = parsel.Selector(response1.text)
    title = selector.css('.title-content::text').get().replace(' ', '').replace('\n', '')
    invalid_chars_pattern = r'[\/:*?"<>|]'  # 定义需要替换的非法字符
    title = re.sub(invalid_chars_pattern, '|', title)  # 将非法字符替换为空格
    print(title)
    # 将获取的 JSON 数据写入文件
    with open('getdrama.json', 'w', encoding='utf-8') as f:
        f.write(response.text)

    # 读取 getdrama.json 文件
    with open('getdrama.json', 'r', encoding='utf-8') as f:
        content = f.read()

    # 匹配包含 "id" 和 "sound_id" 的 JSON 对象
    pattern = r'\{"id":.*?\}'  # 正则表达式匹配模式
    matches = re.findall(pattern, content)

    # 提取匹配的 JSON 对象中的所需字段
    results = []
    for match in matches:
        try:
            data_dict = json.loads(match)
            sound_id = data_dict.get("sound_id")
            if sound_id:
                results.append({"name": data_dict.get("name"), "sound_id": sound_id})
        except json.JSONDecodeError:
            continue  # 忽略 JSON 解码错误

    # 将结果列表转换为 DataFrame
    df = pd.DataFrame(results)

    # 下载音频文件
    download_dir = f'D:/drama_{drama_id}/' # download_dir = 'D:/drama1/'
    if not os.path.exists(download_dir):
        os.mkdir(download_dir)

    # 打开命令提示符
    pyautogui.hotkey("win", "r")
    pyautogui.typewrite('cmd')
    time.sleep(3)
    pyautogui.press('enter')
    time.sleep(3)


    def download():
        for sound_id in df['sound_id']:
            url = f"https://www.missevan.com/sound/player?id={sound_id}"
            pyautogui.typewrite(f'you-get -o {download_dir} {url}')
            # pyperclip.copy(url)
            # pyautogui.hotkey("ctrl", "v")
            pyautogui.press("enter")

    download()

3/ 继续优化

优化代码:

  1. 删除 pyautogui 部分:使用 os.system() 直接调用 you-get 命令行工具,这消除了对图形界面的依赖并提高了代码的效率与稳定性。(原来使用的是pyautogui打开cmd命令提示符来使用you-get)
    在这里插入图片描述

  2. 批量重命名:在所有下载完成后,再统一进行批量重命名,添加了 download_directories 列表,用于存储每个 download_dir 和对应的 title。
    在这里插入图片描述
    出现了一个可能导致文件夹重命名失败的问题。title 变量在for循环中要在循环体内获取,每次URL处理时应动态产生,而不是在群体内静态不变。调整代码:
    在这里插入图片描述

4/ 最新代码

# 配合urls.txt使用
import os
import re
import json
import time
import parsel
import requests

# 读取 URL 列表
url_file = 'urls.txt'  # 假设 URL 列表存储在这个文本文件中
with open(url_file, 'r', encoding='utf-8') as f:
    urls = [line.strip() for line in f if line.strip()]  # 逐行读取并去除空行

headers = {
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.139 Safari/537.36'
}

# 整体结果列表
total_results = []
download_directories = []  # 用于存储下载目录和标题的对应关系

# 遍历每个 URL
for url in urls:
    drama_id = re.search(r'/mdrama/(\d+)', url).group(1)  # 提取 drama_id
    json_url = f'https://www.missevan.com/dramaapi/getdrama?drama_id={drama_id}'

    response = requests.get(json_url)

    # 从响应获取标题
    response_text = response.text
    #pattern_title = r'"title":"(.*?)"'  # 假设标题在 JSON 中
    #title_match = re.search(pattern_title, response_text)
    #title = title_match.group(1).replace(' ', '').replace('\n', '') if title_match else f'drama_{drama_id}'

    selector = parsel.Selector(requests.get(url, headers=headers).text)
    title = selector.css('.title-content::text').get().replace(' ', '').replace('\n', '')
    invalid_chars_pattern = r'[\/:*?"<>|]'  # 定义需要替换的非法字符
    title = re.sub(invalid_chars_pattern, '|', title)  # 将非法字符替换为空格
    print(title)

    # 将获取的 JSON 数据写入文件
    json_filename = f'{drama_id}_getdrama.json'
    with open(json_filename, 'w', encoding='utf-8') as f:
        f.write(response_text)

    # 读取 JSON 文件
    with open(json_filename, 'r', encoding='utf-8') as f:
        content = f.read()

    # 匹配包含 "id" 和 "sound_id" 的 JSON 对象
    pattern = r'\{"id":.*?\}'  # 正则表达式匹配模式
    matches = re.findall(pattern, content)

    # 提取匹配的 JSON 对象中的所需字段
    results = []

    for match in matches:
        try:
            data_dict = json.loads(match)
            sound_id = data_dict.get("sound_id")
            if sound_id:
                results.append({"name": data_dict.get("name"), "sound_id": sound_id})
        except json.JSONDecodeError:
            continue  # 忽略 JSON 解码错误

    # 将结果添加到总结果列表
    total_results.extend(results)

    # 下载音频文件
    download_dir = f'D:/drama_{drama_id}/'
    download_directories.append((download_dir, title))  # 保存目录和标题

    if not os.path.exists(download_dir):
        os.makedirs(download_dir)

    # 下载音频文件(使用 you-get 命令行工具)
    for sound in results:
        sound_id = sound['sound_id']
        download_url = f"https://www.missevan.com/sound/player?id={sound_id}"
        os.system(f'you-get -o "{download_dir}" {download_url}')
        time.sleep(2)  # 添加延时,避免命令太快

# 所有下载完成后,批量重命名文件夹
for download_dir, title in download_directories:
    target_dir = f'D:/{title}/'
    if not os.path.exists(target_dir):  # 检查重命名目标文件夹是否存在
        os.rename(download_dir, target_dir)
        print(f"文件夹 '{download_dir}' 已重命名为 '{target_dir}'")
    else:
        print(f"目标文件夹 '{target_dir}' 已存在,跳过重命名。")

运行结果:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2191545.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【C++】关键字+命名空间

大家好&#xff0c;我是苏貝&#xff0c;本篇博客带大家了解C的命名空间&#xff0c;如果你觉得我写的还不错的话&#xff0c;可以给我一个赞&#x1f44d;吗&#xff0c;感谢❤️ 目录 一. 关键字二. 命名空间2.1 命名空间的定义2.2 命名空间的使用a. 命名空间名称作用域限定…

R包的安装、加载以及如何查看帮助文档

0x01 如何安装R包 一、通过R 内置函数安装&#xff08;常用&#xff09; 1.安装CRAN的R包 install.packages()是一个用于安装 R 包的重要函数。 语法&#xff1a;install.packages(pkgs, repos getOption("repos"),...) 其中&#xff1a; pkgs&#xff1a;要安…

SpringCloud Alibaba - Eureka注册中心,Nacos配置中心

Eureka 1、创建服务端 server:port: 8761 # eureka 默认端口spring:application:name: eureka-server # 应用名称&#xff08;微服务中建议必须定义应用名称&#xff09; SpringBootApplication EnableEurekaServer // 开启eureka注册中心功能 public class EurekaServerAppli…

二分查找一>山脉数组的峰顶索引

1.题目&#xff1a; 2.解析&#xff1a; 代码&#xff1a; public int peakIndexInMountainArray(int[] arr) {int left 1, right arr.length-2;while(left < right) {int mid left (right-left1) / 2;if(arr[mid] > arr[mid-1]) left mid;else right mid-1;}ret…

【记录】Excel|Excel 打印成 PDF 页数太多怎么办

【记录】Excel&#xff5c;解决 Excel 打印成 PDF 页数过多的问题 文章目录 【记录】Excel&#xff5c;解决 Excel 打印成 PDF 页数过多的问题方法一&#xff1a;调整页边距WPS OfficeMicrosoft Excel 方法二&#xff1a;优化页面布局调整列宽和行高使用“页面布局”视图合并单…

Markdown实用语法汇总

说明&#xff1a; 本来只展示本人常用的、markdown特有优势的一些语法。表格输入markdown的弱项&#xff0c;不作介绍&#xff0c;借助软件创建即可。引用图片、音频、视频等&#xff0c;虽然很方便&#xff0c;但是内容集成度不高&#xff0c;需要上传发布的时候很不方便&…

[单master节点k8s部署]29.Istio流量管理(五)

测试istio熔断管理。 采用httpbin镜像和fortio镜像&#xff0c;其中httpbin作为服务端&#xff0c;fortio是请求端。这两个的配置yaml文件都在istio的samples/httpbin目录下&#xff0c;fortio的配置文件在samples-client目录下。 [rootmaster httpbin]# ls gateway-api ht…

七、Drf版本组件

七、版本组件 7.1基于GET请求 #url.py urlpatterns [ path(home/,views.HomeView.as_view(),namehome), ]#setting.py REST_FRAMEWORK {#定义版本号的名称&#xff0c;默认为versionVERSION_PARAM:version, #允许的版本号值&#xff0c;如果前端传递过来的版本号的值不在…

工具使用总结之(三) SecureCRT 设置日志自动保存

SecureCRT工具设置日志自动保存方法 1、双击打开SecureCRT工具 2、打开依次打开选项-》会话选项-》日志文件 3、按照如下截图方法进行配置&#xff0c;然后确定保存即可 [%Y%M%D_%h:%m:%s] [%Y%M%D_%h:%m:%s] [%h:%m:%s.%t]

统一 SASE 架构中的网络和安全融合

网络威胁情报技术的进步 传统的网络边界一片混乱&#xff0c;剩下的只是无人管理的设备、分散在私有云和公共云中的资产、无法读取的应用程序流量泛滥&#xff0c;混合工作结构正在给现有网络的功能带来压力。 更重要的是&#xff0c;这些问题早在生成式人工智能和大型语言模…

Nginx的核心架构和设计原理

Nginx 是一个免费的、开源的、高性能 Http 服务器和反向代理。Nginx 的架构设计是为了提供高性能、稳定性和可扩展性。 Nginx 的主要架构组件和工作原理&#xff1a; 1、Master 进程&#xff1a;Nginx 的运行始于一个 master 进程&#xff0c;它负责管理所有的工作进程。mast…

【C++差分数组】1526. 形成目标数组的子数组最少增加次数|1872

本文涉及知识点 C差分数组 LeetCode1526. 形成目标数组的子数组最少增加次数 给你一个整数数组 target 和一个数组 initial &#xff0c;initial 数组与 target 数组有同样的维度&#xff0c;且一开始全部为 0 。 请你返回从 initial 得到 target 的最少操作次数&#xff0c…

WSL2Linux 子系统(十二)

wsl 子系统安装 cuda 环境 《WSL2Linux 子系统(十一)》讲述 WSL 网络转为桥接模式的两种方法&#xff0c;WSL 网络桥接模式无论是静态 IP 还是动态分配 IP 均支持。本篇文章则是简单讲述 WSL 安装 cuda 环境。 作者&#xff1a;炭烤毛蛋 &#xff0c;点击博主了解更多。 提示…

3种框架助你绘制完美技术路线图,导师一眼就认可

我是娜姐 迪娜学姐 &#xff0c;一个SCI医学期刊编辑&#xff0c;探索用AI工具提效论文写作和发表。 一份好的技术路线图&#xff0c;不仅能让导师和评委一目了然地了解你的研究计划&#xff0c;还能为你的整个研究过程提供清晰的指导。但是&#xff0c;不少学生在制作时往往摸…

MFC多媒体定时器实例(源码下载)

用MFC多媒体定时器做一个每1秒钟加一次的计时器&#xff0c;点开始计时按钮开始计时&#xff0c;点关闭计时按钮关闭计时。 1、在库文件Med_timeDlg.h文件中添加代码 class CMed_timeDlg : public CDialog { // Construction public:CMed_timeDlg(CWnd* pParent NULL); // st…

展锐平台WIFI国家码信道总结

展锐平台WIFI国家码信道总结 1.下载wireless-regdb wireless-regdb是一个开源的工程,编译它会生成regulatory.bin文件,这实际上是一个加密后的数据库,它记录各个国家可用的无线频段。 可从下面的网站上下载最新的regdb库: https://git.kernel.org/pub/scm/linux/kernel…

在3damax重创建了一个材质,然后在场景中也没有应用这个材质,将材质编辑器窗口重置,如何找回创建的材质(如何找回创建但是没有应用的材质(大概率找不回啦))

在3damax重创建了一个材质&#xff0c;然后在场景中也没有应用这个材质&#xff0c;将材质编辑器窗口重置&#xff0c;如何找回创建的材质&#xff08;如何找回创建但是没有应用的材质&#xff09; 检查场景文件&#xff1a; 如果你在保存场景文件的时候&#xff0c;那个材质也…

计算机的错误计算(一百一十四)

摘要 回复读者提问&#xff0c;就计算机的错误计算&#xff08;六&#xff09;中案例&#xff0c;讨论其另外一种形式&#xff1a; 的错误计算问题。 一读者来信说&#xff0c;在计算机的错误计算&#xff08;六&#xff09;中&#xff0c;使用了两种计算方法。实际上&#xf…

unity 2d 近战攻击判定的三种方式

1. 给攻击帧添加碰撞盒 优点&#xff1a;配置直观&#xff0c;无需事件触发 缺点&#xff1a;无法定制&#xff0c;效率低 检测放在子物体&#xff0c;可以控制旋转 添加触发器事件 注意OnTriggerEnter2D只会在挂载了collider的组件上触发 protected virtual void OnTrigge…

介绍一款开源的 Modern GUI PySide6 / PyQt6的使用

首先附上大神的开源地址&#xff08;自行克隆吧&#xff09;&#xff1a; https://github.com/Wanderson-Magalhaes/Modern_GUI_PyDracula_PySide6_or_PyQt6 步骤一&#xff1a;安装PySide6库 pip install PySide6 步骤二&#xff1a;运行main文件 python main.py 就得…