豆瓣电影元数据提取

精准提取所有核心字段(含又名)

目前為 2025-08-26 提交的版本,檢視 最新版本

// ==UserScript==
// @name           豆瓣电影元数据提取
// @description    精准提取所有核心字段(含又名)
// @author         bai
// @version        1.7
// @icon           https://movie.douban.com/favicon.ico
// @grant          GM_addStyle
// @require        https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js
// @include        https://movie.douban.com/subject/*
// @run-at         document-end
// @license        Apache-2.0
// @namespace https://gf.qytechs.cn/users/967749
// ==/UserScript==

$(function () {
    // 样式优化
    GM_addStyle(`
        .movie-utils {
            margin: 15px 0;
            padding: 12px;
            background: #f8f5f3;
            border-radius: 8px;
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
        }
        .copy-btn {
            padding: 8px 16px;
            border: none;
            border-radius: 4px;
            background: #e4d2cc;
            color: #6b5f59;
            cursor: pointer;
            transition: all 0.3s;
        }
        .copy-btn:hover {
            background: #d1bcb2;
            transform: translateY(-1px);
        }
        .status {
            margin-left: 10px;
            font-size: 14px;
            color: #6b5f59;
        }
    `);

    // 核心:精准提取引擎(重点解决分段问题)
    function extractMovieData() {
        return {
            title: extractTitle(),
            director: extractField('导演'),
            cast: extractCast(),
            country: extractField('制片国家/地区'),
            language: extractField('语言'),
            genre: extractGenre(),
            releaseDate: extractReleaseDate(), // 单独处理上映日期,适配复杂结构
            runtime: extractField('片长'),
            rating: extractRating(),
            intro: extractIntroWithBreaks(), // 分段核心函数
            alias: extractAlias(), // 新增:提取又名字段
            url: window.location.href
        };
    }

    // 1. 标题提取(含别名)
    function extractTitle() {
        const mainTitle = $('h1 span[property="v:itemreviewed"]').text().trim();
        // 别名后续单独提取,这里仅返回主标题
        return mainTitle || '未知标题';
    }

    // 新增:提取又名字段
    function extractAlias() {
        const $info = $('span.pl:contains("又名:")').closest('#info');
        if (!$info.length) return '无别名';

        const match = $info.text().match(new RegExp(`又名:\\s*(.*?)(?=\\n|$)`));
        return match? match[1].trim().replace(/\s*\/\s*/g, ' / ') : '无别名';
    }

    // 2. 通用字段提取(导演/国家/语言等,除上映日期)
    function extractField(fieldName) {
        // 找到包含字段名的 .pl 容器,再找父级 #info 里的文本
        const $info = $(`span.pl:contains("${fieldName}")`).closest('#info');
        if (!$info.length) return `未知${fieldName}`;

        // 匹配字段名 + 内容(正则:忽略前后空白,提取“字段名: 内容”)
        const match = $info.text().match(new RegExp(`${fieldName}\\s*[::]\\s*(.*?)(?=\\n|$)`));
        return match? match[1].trim().replace(/^["\s]+|["\s]+$/g, '') : `未知${fieldName}`;
    }

    // 3. 主演提取(严格去除“更多...”)
    function extractCast() {
        const rawCast = $(`span.pl:contains("主演")`).next().text().trim();
        return rawCast.replace(/\s*更多\.{2,}$/i, '').trim() || '未知主演';
    }

    // 4. 类型提取(多标签拼接)
    function extractGenre() {
        const genres = $('#info span[property="v:genre"]').map(function () {
            return $(this).text().trim();
        }).get();
        return genres.join(' / ') || '未知类型';
    }

    // 5. 评分提取
    function extractRating() {
        return $('.rating_num').text().trim() || '暂无评分';
    }

    // 6. 剧情简介提取(逐节点遍历,保留原始分段)
    function extractIntroWithBreaks() {
        // 优先处理展开的完整简介(.all.hidden)
        const $fullIntro = $('.all.hidden');
        if ($fullIntro.length) {
            return $fullIntro.contents().map(function () {
                if (this.nodeType === 3) { // 文本节点
                    return this.textContent.trim();
                }
                if (this.tagName === 'BR') { // 换行标签
                    return '\n';
                }
                return ''; // 其他标签过滤
            }).get().join('').replace(/\n+/g, '\n').trim();
        }

        // 处理短简介(.short)
        const $shortIntro = $('span[property="v:summary"]');
        if ($shortIntro.length) {
            return $shortIntro.text().trim().replace(/\s+/g, ' ') || '无剧情简介';
        }

        return '无剧情简介';
    }

    // 7. 单独处理上映日期,适配多个日期的 DOM 结构
    function extractReleaseDate() {
        const $target = $(`span.pl:contains("上映日期")`).nextAll('span[property="v:initialReleaseDate"]');
        const dates = $target.map(function () {
            return $(this).text().trim().replace(/^["\s]+|["\s]+$/g, '');
        }).get();
        return dates.join(' / ') || '未知上映日期';
    }

    // 复制逻辑(带数据校验)
    async function copyMetadata() {
        const $btn = $(this);
        const $status = $btn.siblings('.status');
        $btn.text('复制中...').prop('disabled', true);
        $status.text('处理中').removeClass('success error').addClass('loading');

        try {
            const data = extractMovieData();
            // 核心校验:简介必须非空
            if (!data.intro.trim()) throw new Error('剧情简介提取失败');

            const copyText = formatMetadata(data);
            await navigator.clipboard.writeText(copyText);

            $status.text('复制成功').removeClass('loading error').addClass('success');
            $btn.text('已复制');
            setTimeout(() => {
                $status.text('');
                $btn.text('复制元数据');
            }, 2000);
        } catch (err) {
            $status.text(`失败:${err.message}`).removeClass('loading success').addClass('error');
            $btn.text('重试').prop('disabled', false);
            console.error('提取失败:', err);
        }
    }

    // 格式化函数(完美保留分段,新增别名展示)
    function formatMetadata(data) {
        return `电影名:《${data.title}》
别名:${data.alias}
导演:${data.director}
主演:${data.cast}
类型:${data.genre}
制片国家/地区:${data.country}
语言:${data.language}
上映日期:${data.releaseDate}
片长:${data.runtime}
豆瓣评分:${data.rating}
剧情简介:
${data.intro}
页面链接:${data.url}
`;
    }

    // 初始化界面
    const $utils = $('<div class="movie-utils">').append(
        $('<button class="copy-btn">复制元数据</button>'),
        $('<span class="status"> </span>')
    ).prependTo('.aside');

    // 绑定事件
    $utils.on('click', '.copy-btn', copyMetadata);
});

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址