豆瓣电影元数据提取

精准提取所有核心字段(含又名、滴答格式)

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

// ==UserScript==
// @name           豆瓣电影元数据提取
// @description    精准提取所有核心字段(含又名、滴答格式)
// @author         bai
// @version        1.8
// @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;
            margin-right: 8px;
        }
        .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) {
        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() {
        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();
        }

        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 copyToDida() {
        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.title.trim()) throw new Error('标题提取失败');

            // 按照滴答格式拼接内容,可根据实际需求调整字段
            const didaText = `[《${data.title}》](${data.url}) 🎬:${data.director} ⭐:${data.rating} 🗺️:${data.country} 🗓️:${data.releaseDate}`;
            await navigator.clipboard.writeText(didaText);
            
            $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);
        }
    }

    // 原复制逻辑(带数据校验)
    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" id="copyFull">复制元数据</button>'),
        $('<button class="copy-btn" id="copyDida">复制→滴答</button>'),
        $('<span class="status"> </span>')
    ).prependTo('.aside');

    // 绑定事件
    $('#copyFull').on('click', copyMetadata);
    $('#copyDida').on('click', copyToDida);
});

QingJ © 2025

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