Greasy Fork

来自缓存

Greasy Fork is available in English.

抓点亚马逊和速卖通的搜索数据

抓取亚马逊和速卖通商品数据并导出到Excel,支持多页抓取和自定义页面范围

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         抓点亚马逊和速卖通的搜索数据
// @namespace    http://tampermonkey.net/
// @version      1.0.2
// @description  抓取亚马逊和速卖通商品数据并导出到Excel,支持多页抓取和自定义页面范围
// @author       Meng
// @license      MIT
// @homepage     https://github.com/yourusername/amazon-ali-scraper
// @supportURL   https://github.com/yourusername/amazon-ali-scraper/issues
// @match        https://www.amazon.com/s*
// @match        https://www.aliexpress.com/*
// @grant        GM_xmlhttpRequest
// @grant        GM_download
// @require      https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js
// @icon         https://www.google.com/s2/favicons?domain=amazon.com
// ==/UserScript==

/*
 * 使用说明:
 * 1. 安装要求:
 *    - 安装Tampermonkey浏览器扩展
 *    - 支持Chrome、Firefox、Edge等主流浏览器
 * 
 * 2. 功能特点:
 *    - 支持亚马逊和速卖通商品数据抓取
 *    - 可自定义抓取页面范围
 *    - 自动导出Excel文件
 *    - 支持多页连续抓取
 * 
 * 3. 使用方法:
 *    - 在亚马逊或速卖通搜索页面运行脚本
 *    - 输入要抓取的起始页码和结束页码
 *    - 点击对应的导出按钮
 *    - 等待抓取完成,自动下载Excel文件
 * 
 * 4. 注意事项:
 *    - 请合理设置抓取间隔,避免对网站造成压力
 *    - 建议每次抓取不超过50页
 *    - 如遇到问题,请查看浏览器控制台日志
 * 
 * 5. 更新日志:
 *    v1.0.0 (2024-03-31)
 *    - 首次发布
 *    - 支持亚马逊和速卖通数据抓取
 *    - 支持自定义页面范围
 *    - 自动导出Excel文件
 */

(function() {
    'use strict';

    // 添加导出按钮
    function addExportButton() {
        const buttonContainer = document.createElement('div');
        buttonContainer.style.cssText = `
            position: fixed;
            top: 20px;
            right: 20px;
            z-index: 9999;
            display: flex;
            flex-direction: column;
            gap: 10px;
            background-color: white;
            padding: 15px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
        `;

        // 添加页面范围输入框
        const inputContainer = document.createElement('div');
        inputContainer.style.cssText = `
            display: flex;
            flex-direction: row;
            gap: 5px;
            margin-bottom: 10px;
        `;

        const startPageInput = document.createElement('input');
        startPageInput.type = 'number';
        startPageInput.placeholder = '起始页码';
        startPageInput.min = '1';
        startPageInput.value = '1';
        startPageInput.style.cssText = `
            padding: 5px;
            border: 1px solid #ccc;
            border-radius: 4px;
            width: 100px;
        `;

        const endPageInput = document.createElement('input');
        endPageInput.type = 'number';
        endPageInput.placeholder = '结束页码';
        endPageInput.min = '1';
        endPageInput.style.cssText = `
            padding: 5px;
            border: 1px solid #ccc;
            border-radius: 4px;
            width: 100px;
        `;

        inputContainer.appendChild(startPageInput);
        inputContainer.appendChild(endPageInput);
        buttonContainer.appendChild(inputContainer);

        // 判断当前网站
        const isAmazon = window.location.hostname.includes('amazon');
        const isAliExpress = window.location.hostname.includes('aliexpress');

        if (isAmazon) {
            // Amazon按钮
            const amazonButton = document.createElement('button');
            amazonButton.innerHTML = '导出Amazon商品数据';
            amazonButton.style.cssText = `
                padding: 10px 20px;
                background-color: #FF9900;
                color: white;
                border: none;
                border-radius: 4px;
                cursor: pointer;
                font-size: 14px;
            `;
            amazonButton.onclick = () => {
                const startPage = parseInt(startPageInput.value) || 1;
                const endPage = parseInt(endPageInput.value);
                if (endPage && endPage < startPage) {
                    alert('结束页码不能小于起始页码!');
                    return;
                }
                scrapeAndExport(startPage, endPage);
            };
            buttonContainer.appendChild(amazonButton);
        }

        if (isAliExpress) {
            // AliExpress按钮
            const aliButton = document.createElement('button');
            aliButton.innerHTML = '导出AliExpress商品数据';
            aliButton.style.cssText = `
                padding: 10px 20px;
                background-color: #E62E04;
                color: white;
                border: none;
                border-radius: 4px;
                cursor: pointer;
                font-size: 14px;
            `;
            aliButton.onclick = () => {
                const startPage = parseInt(startPageInput.value) || 1;
                const endPage = parseInt(endPageInput.value);
                if (endPage && endPage < startPage) {
                    alert('结束页码不能小于起始页码!');
                    return;
                }
                scrapeAliExpress(startPage, endPage);
            };
            buttonContainer.appendChild(aliButton);
        }

        document.body.appendChild(buttonContainer);
    }

    // 添加加载提示
    function showLoading(message) {
        let loadingDiv = document.getElementById('amazon-scraper-loading');
        if (!loadingDiv) {
            loadingDiv = document.createElement('div');
            loadingDiv.id = 'amazon-scraper-loading';
            loadingDiv.style.cssText = `
                position: fixed;
                top: 50%;
                left: 50%;
                transform: translate(-50%, -50%);
                background-color: rgba(0, 0, 0, 0.8);
                color: white;
                padding: 20px;
                border-radius: 8px;
                z-index: 10000;
                text-align: center;
            `;
            document.body.appendChild(loadingDiv);
        }
        loadingDiv.innerHTML = message;
    }

    // 隐藏加载提示
    function hideLoading() {
        const loadingDiv = document.getElementById('amazon-scraper-loading');
        if (loadingDiv) {
            loadingDiv.remove();
        }
    }

    // 获取商品数据
    async function getProductData(startPage = 1, endPage = null) {
        const products = [];
        let currentPage = startPage;
        let hasNextPage = true;

        // 如果当前不在起始页,需要先跳转到起始页
        if (currentPage > 1) {
            showLoading(`正在跳转到第 ${currentPage} 页...`);
            // 构建URL跳转到指定页面
            const currentUrl = new URL(window.location.href);
            currentUrl.searchParams.set('page', currentPage);
            window.location.href = currentUrl.toString();
            return products; // 页面会刷新,所以这里直接返回
        }
        
        while (hasNextPage) {
            showLoading(`正在抓取第 ${currentPage} 页数据...`);
            
            const productElements = Array.from(document.querySelectorAll('div[data-asin][data-component-type="s-search-result"]'));
            console.log(`当前页面找到 ${productElements.length} 个商品`);
            
            for (const product of productElements) {
                const asin = product.getAttribute('data-asin');
                if (!asin) continue;

                // 获取标题
                let title = '';
                try {
                    const h2WithAriaLabel = product.querySelector('h2[aria-label]');
                    if (h2WithAriaLabel) {
                        title = h2WithAriaLabel.getAttribute('aria-label');
                    } else {
                        title = product.querySelector('h2 span').textContent.trim();
                    }
                } catch (e) {
                    title = '无标题';
                }

                // 获取价格
                let price = '';
                try {
                    const priceElement = product.querySelector('.a-price .a-offscreen');
                    if (priceElement) {
                        price = priceElement.textContent.trim();
                    } else {
                        const listPriceElement = product.querySelector('.a-text-price .a-offscreen');
                        if (listPriceElement) {
                            price = listPriceElement.textContent.trim();
                        }
                    }
                } catch (e) {
                    price = '无价格';
                }

                products.push({
                    title: title,
                    price: price
                });
            }

            // 检查是否达到结束页
            if (endPage && currentPage >= endPage) {
                console.log(`已达到指定的结束页 ${endPage},停止抓取`);
                break;
            }

            // 检查是否有下一页
            const nextButton = document.querySelector('a.s-pagination-next:not(.s-pagination-disabled)');
            if (nextButton) {
                console.log('找到下一页按钮,准备翻页');
                nextButton.click();
                await new Promise(resolve => setTimeout(resolve, 3000));
                currentPage++;
            } else {
                console.log('没有找到下一页按钮,停止抓取');
                hasNextPage = false;
            }
        }

        console.log(`总共抓取了 ${products.length} 条数据`);
        return products;
    }

    // 导出到Excel
    function exportToExcel(products, startPage, endPage) {
        // 创建工作簿
        const wb = XLSX.utils.book_new();
        
        // 准备数据
        const data = [
            ['标题', '价格'] // 表头
        ];
        
        // 添加商品数据
        products.forEach(product => {
            data.push([
                product.title,
                product.price
            ]);
        });

        // 创建工作表
        const ws = XLSX.utils.aoa_to_sheet(data);
        
        // 将工作表添加到工作簿
        XLSX.utils.book_append_sheet(wb, ws, '商品信息');

        // 生成Excel文件
        const wbout = XLSX.write(wb, { bookType: 'xlsx', type: 'binary' });

        // 转换二进制数据为Blob
        const blob = new Blob([s2ab(wbout)], { type: 'application/octet-stream' });

        // 下载文件
        const url = URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        a.download = `amazon_products_${startPage}-${endPage || 'end'}.xlsx`;
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
        URL.revokeObjectURL(url);
    }

    // 辅助函数:字符串转ArrayBuffer
    function s2ab(s) {
        const buf = new ArrayBuffer(s.length);
        const view = new Uint8Array(buf);
        for (let i = 0; i < s.length; i++) {
            view[i] = s.charCodeAt(i) & 0xFF;
        }
        return buf;
    }

    // 主函数:抓取数据并导出
    async function scrapeAndExport(startPage = 1, endPage = null) {
        try {
            showLoading('开始导出数据...');
            const products = await getProductData(startPage, endPage);
            showLoading(`共抓取 ${products.length} 条数据,正在生成Excel文件...`);
            exportToExcel(products, startPage, endPage);
            hideLoading();
            alert(`数据导出完成!共导出 ${products.length} 条数据`);
        } catch (error) {
            console.error('导出失败:', error);
            alert('导出失败,请查看控制台获取详细信息');
            hideLoading();
        }
    }

    // 获取速卖通商品数据
    async function getAliExpressData(startPage = 1, endPage = null) {
        const products = [];
        let currentPage = startPage;
        let hasNextPage = true;
        
        // 如果当前不在起始页,需要先跳转到起始页
        if (currentPage > 1) {
            showLoading(`正在跳转到第 ${currentPage} 页...`);
            // 这里需要实现跳转到指定页面的逻辑
            // 由于速卖通可能没有直接的页面跳转,我们可能需要多次点击下一页
            for (let i = 1; i < currentPage; i++) {
                const nextButton = findNextButton();
                if (nextButton) {
                    nextButton.click();
                    await new Promise(resolve => setTimeout(resolve, 3000));
                } else {
                    alert(`无法跳转到第 ${currentPage} 页,请确保页面存在!`);
                    return products;
                }
            }
        }
        
        while (hasNextPage) {
            showLoading(`正在抓取第 ${currentPage} 页数据...`);
            
            // 获取当前页面的商品
            const productElements = document.querySelectorAll('div.lj_z');
            console.log(`当前页面找到 ${productElements.length} 个商品`);
            
            for (const product of productElements) {
                // 获取标题
                let title = '';
                try {
                    const titleElement = product.querySelector('h3.lj_jz');
                    if (titleElement) {
                        title = titleElement.textContent.trim();
                    }
                } catch (e) {
                    title = '无标题';
                }

                // 获取价格
                let price = '';
                try {
                    const priceElement = product.querySelector('div.lj_k1');
                    if (priceElement) {
                        price = priceElement.textContent.trim();
                    }
                } catch (e) {
                    price = '无价格';
                }

                products.push({
                    title: title,
                    price: price
                });
            }

            // 检查是否达到结束页
            if (endPage && currentPage >= endPage) {
                console.log(`已达到指定的结束页 ${endPage},停止抓取`);
                break;
            }

            // 检查是否有下一页
            const nextButton = findNextButton();
            if (nextButton) {
                console.log('找到下一页按钮,准备翻页');
                nextButton.click();
                await new Promise(resolve => setTimeout(resolve, 3000));
                currentPage++;
            } else {
                console.log('没有找到下一页按钮,停止抓取');
                hasNextPage = false;
            }
        }

        console.log(`总共抓取了 ${products.length} 条数据`);
        return products;
    }

    // 查找下一页按钮
    function findNextButton() {
        const nextButtonSelectors = [
            'button.comet-pagination-item-link[aria-label="Next"]',
            'button.comet-pagination-item-link:not([disabled])',
            'button.comet-pagination-item-link',
            'a.comet-pagination-item-link',
            'a[aria-label="Next"]',
            'a[rel="next"]'
        ];

        for (const selector of nextButtonSelectors) {
            const button = document.querySelector(selector);
            if (button && !button.disabled) {
                return button;
            }
        }
        return null;
    }

    // 导出速卖通数据
    async function scrapeAliExpress(startPage = 1, endPage = null) {
        try {
            showLoading('开始导出速卖通数据...');
            const products = await getAliExpressData(startPage, endPage);
            showLoading(`共抓取 ${products.length} 条数据,正在生成Excel文件...`);
            
            // 创建工作簿
            const wb = XLSX.utils.book_new();
            
            // 准备数据
            const data = [
                ['标题', '价格'] // 表头
            ];
            
            // 添加商品数据
            products.forEach(product => {
                data.push([
                    product.title,
                    product.price
                ]);
            });

            // 创建工作表
            const ws = XLSX.utils.aoa_to_sheet(data);
            
            // 将工作表添加到工作簿
            XLSX.utils.book_append_sheet(wb, ws, '速卖通商品信息');

            // 生成Excel文件
            const wbout = XLSX.write(wb, { bookType: 'xlsx', type: 'binary' });

            // 转换二进制数据为Blob
            const blob = new Blob([s2ab(wbout)], { type: 'application/octet-stream' });

            // 下载文件
            const url = URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url;
            a.download = `aliexpress_products_${startPage}-${endPage || 'end'}.xlsx`;
            document.body.appendChild(a);
            a.click();
            document.body.removeChild(a);
            URL.revokeObjectURL(url);
            
            hideLoading();
            alert(`速卖通数据导出完成!共导出 ${products.length} 条数据`);
        } catch (error) {
            console.error('导出失败:', error);
            alert('导出失败,请查看控制台获取详细信息');
            hideLoading();
        }
    }

    // 页面加载完成后添加导出按钮
    window.addEventListener('load', () => {
        addExportButton();
    });
})();