seo.js 6.18 KB
'use strict';

const api = global.yoho.API;
const rp = require('request-promise');
const serviceApi = global.yoho.ServiceAPI;
const Promise = require('bluebird');
const co = Promise.coroutine;
const _ = require('lodash');
const logger = global.yoho.logger;
const helper = global.yoho.helpers;
const moment = require('moment');
const config = require('../config/config');
const staticUrl = require('../config/staticUrls');
const fs = require('fs');
const schedule = require('node-schedule');
const qs = require('querystring');
const baiduUrls = {
    urls: 'http://data.zz.baidu.com/urls',
    update: 'http://data.zz.baidu.com/update',
    del: 'http://data.zz.baidu.com/del'
};

const siteUrls = {
    pcProduct: {
        site: 'https://item.yohobuy.com',
        url: []
    },
    pcGuang: {
        site: 'https://guang.yohobuy.com',
        url: []
    },
    mProduct: {
        site: 'https://m.yohobuy.com',
        url: []
    },
    mGuang: {
        site: 'https://guang.m.yohobuy.com',
        url: [],
        type: 'mip'
    }

};


/**
 * 获取最新1000条商品详情链接和逛详情链接
 */
const getUrls = () => {
    let apiArr = [api.get('', {method: 'web.product.bdPromotion'}),
        serviceApi.get('/guang/api/v2/article/getLastArticleList', {limit: 100})];

    return api.all(apiArr).spread((productData, articleData) => {

        _.forEach(_.get(productData, 'data', {}), value => {
            siteUrls.pcProduct.url.push('https:' + helper.urlFormat(`/p${value.erpProductId}.html`, null, 'item'));
            siteUrls.mProduct.url.push('https:' + helper.urlFormat(`/product/${value.id}.html`, null, 'm'));
        });

        _.forEach(_.get(articleData, 'data.artList', {}), value => {
            siteUrls.pcGuang.url.push('https:' + helper.urlFormat(`/${value.articleId}.html`, null, 'guang'));
            siteUrls.mGuang.url.push('https:' + helper.urlFormat(`/mip/guang/info/${value.articleId}.html`
, null, 'guang.m'));
        });

        return siteUrls;
    });
};

/**
 * 将链接推送到百度站长
 * @param site string 站点
 * @param urls object {site: 'https://www.yohobuy.com', type: 'mip'} 默认不需要type
 */
const sendUrlsToBaidu = (params, urls) => {
    let paramsDef = {
        token: config.baiduToken
    };

    // 过滤无效的参数
    _.forEach(params, (val, key) => {
        if (!val) {
            delete params[key];
        }
    });

    qs.escape = (str) => {
        return str;
    };

    let options = {
        url: `${baiduUrls.urls}?${qs.stringify(Object.assign(paramsDef, params), null, null, {})}`,
        headers: {
            'Content-Type': 'text/plain'
        },
        method: 'post',
        form: urls.join('\n'),
        json: true,
        timeout: 10000,
        gzip: true
    };

    return rp(options).then(result => {
        logger.info(result);
    });
};

/**
 * 获取最新商品详情1000条和逛详情100条推送到相应的站点域名(pc和wap)
 */
const sendUrls = (req, res) => {

    co(function*() {
        // 获取pc/wap的商品详情和逛的链接
        let sendArr = [],
            urls = yield getUrls();

        _.forEach(urls, value => {
            sendArr.push(sendUrlsToBaidu({site: value.site, type: value.type}, value.url));
        });

        // 推送url
        api.all(sendArr);
    })();

    res.end();
};


const getXmlUrl = (maps) => {
    let xmlUrl = '';

    _.forEach(_.get(maps, 'loc'), (url) => {
        if (url) {
            xmlUrl += `
            <url>
                <loc>${url}</loc>
                <lastmod>${maps.lastmod}</lastmod>
                <changefreq>${maps.changefreq}</changefreq>
                <priority>${maps.priority}</priority>
            </url>`;
        }
    });
    return xmlUrl;
};

const generateSitemapXml = (site, maps, sitemapPath) => {
    sitemapPath = sitemapPath || config.sitemapPath;

    let content = '<?xml version="1.0" encoding="utf-8"?><urlset><url></url></urlset>';
    let fileName = `${sitemapPath}/${site}_sitemap.xml`;
    let urls = '';

    if (maps.hasOwnProperty('loc')) {
        urls += getXmlUrl(maps);
    } else {
        _.forEach(maps, (val)=>{
            urls += getXmlUrl(val);
        });
    }
    if (urls.length === 0) {
        return;
    }

    content = content.replace('<url></url>', urls);
    fs.open(fileName, 'r+', ()=>{
        fs.writeFile(fileName, content, function(err) {
            if (err) {
                logger.error(err);
            } else {
                let now = moment().format('YMD H:mm:ss');

                logger.info(`${now} ${fileName} completed`);
            }
        });
    });

};

/**
 * sitemap
 */
const sitemap = (req, res) => {

    co(function*() {
        // 获取pc/wap的商品详情和逛的链接
        let urls = yield getUrls();

        staticUrl.item.loc = _.concat(staticUrl.item.loc, urls.pcProduct.url);
        staticUrl.guang.loc = _.concat(staticUrl.guang.loc, urls.pcGuang.url);
        staticUrl.m.item.loc = _.concat(staticUrl.m.item.loc, urls.mProduct.url);
        staticUrl['guang.m'].loc = _.concat(staticUrl['guang.m'].loc, urls.mGuang.url);

        _.forEach(staticUrl, (val, key) => {
            generateSitemapXml(key, val);
        });
    })();
    res.end();
};

/**
 * 定时每天1点推送最新商品和文章,更新站点sitemap
 */
const start = () => {
    schedule.scheduleJob('1 * * *', function() {
        sendUrls();
        //sitemap();
    });
};

// 获取guang的mip链接
const getArticleList = () => {
    return serviceApi.get('/guang/api/v2/article/getLastArticleList', {limit: 10000}).then(result => {
        let urls = [];

        _.forEach(_.get(result, 'data.artList'), (value) => {

            urls.push('https:' + helper.urlFormat(`/mip/guang/info/${value.articleId}.html`
, null, 'm'));
        });

        return urls;
    });
};

// 一次推送逛的10000条
const guangMip = (req, res) => {
    co(function*() {
        // 获取逛的mip链接
        let urls = yield getArticleList();
        let urlsRow = _.chunk(urls, 2000);

        _.forEach(urlsRow, val => {
            sendUrlsToBaidu({site: 'https://m.yohobuy.com', type: 'mip'}, val);
        });
    })();
    res.end();
};

module.exports = {
    sendUrls,
    sitemap,
    guangMip,
    start
};