Authored by 周少峰

keywords url

@@ -6,7 +6,7 @@ const yohoLib = require('yoho-node-lib'); @@ -6,7 +6,7 @@ const yohoLib = require('yoho-node-lib');
6 6
7 // 全局注册library 7 // 全局注册library
8 yohoLib.global(config); 8 yohoLib.global(config);
9 - 9 +global.yoho.redis = require('./libs/redis');
10 const logger = global.yoho.logger; 10 const logger = global.yoho.logger;
11 const app = express(); 11 const app = express();
12 const seo = require('./apps/seo'); 12 const seo = require('./apps/seo');
@@ -14,10 +14,10 @@ const seo = require('./apps/seo'); @@ -14,10 +14,10 @@ const seo = require('./apps/seo');
14 // 定时任务 主动推送和生成xml 14 // 定时任务 主动推送和生成xml
15 seo.start(); 15 seo.start();
16 16
17 -// 提供sitemap给搜索百度访问  
18 -app.use(express.static(config.sitemapPath)); 17 +app.get('/synchronousKeywords', seo.synchronousKeywords);
  18 +app.get('/sendKeywordsUrls', seo.sendKeywordsUrls);
19 19
20 app.listen(config.port, function() { 20 app.listen(config.port, function() {
21 - logger.info('yoho seo start'); 21 + logger.info(`yoho seo start : ${config.port}`);
22 }); 22 });
23 23
@@ -11,6 +11,8 @@ const helper = global.yoho.helpers; @@ -11,6 +11,8 @@ const helper = global.yoho.helpers;
11 const config = require('../config/config'); 11 const config = require('../config/config');
12 const schedule = require('node-schedule'); 12 const schedule = require('node-schedule');
13 const qs = require('querystring'); 13 const qs = require('querystring');
  14 +const seoModel = require('./seoModel');
  15 +
14 const baiduUrls = { 16 const baiduUrls = {
15 urls: 'http://data.zz.baidu.com/urls', 17 urls: 'http://data.zz.baidu.com/urls',
16 update: 'http://data.zz.baidu.com/update', 18 update: 'http://data.zz.baidu.com/update',
@@ -120,6 +122,22 @@ const sendUrls = () => { @@ -120,6 +122,22 @@ const sendUrls = () => {
120 })(); 122 })();
121 }; 123 };
122 124
  125 +// 同步建议词(把接口拓展的建议词同步到灰度redis)
  126 +const synchronousKeywords = (req, res) => {
  127 + seoModel.synchronousKeywords();
  128 + res.end();
  129 +};
  130 +
  131 +// 定时缓慢爬取关键词页面生成缓存,防止蜘蛛爬取
  132 +
  133 +
  134 +// 向百度推送页面新的页面
  135 +const sendKeywordsUrls = (req, res) => {
  136 + seoModel.sendKeywordsUrls();
  137 + res.end();
  138 +
  139 +};
  140 +
123 /** 141 /**
124 * 定时每天1点推送最新商品和文章,更新站点sitemap 142 * 定时每天1点推送最新商品和文章,更新站点sitemap
125 */ 143 */
@@ -130,5 +148,7 @@ const start = () => { @@ -130,5 +148,7 @@ const start = () => {
130 }; 148 };
131 149
132 module.exports = { 150 module.exports = {
133 - start 151 + start,
  152 + synchronousKeywords,
  153 + sendKeywordsUrls
134 }; 154 };
  1 +'use strict';
  2 +const api = global.yoho.API;
  3 +const redis = global.yoho.redis;
  4 +const _ = require('lodash');
  5 +
  6 +/**
  7 + * redis multi command
  8 + */
  9 +const multiAsync = (multi)=>{
  10 + return multi.execAsync().then(function(res) {
  11 + return res;
  12 + });
  13 +};
  14 +
  15 +/**
  16 + * 将链接推送到百度站长
  17 + * @param site string 站点
  18 + * @param urls object {site: 'https://www.yohobuy.com', type: 'mip'} 默认不需要type
  19 + */
  20 +// const sendUrlsToBaidu = (params, urls) => {
  21 +// let paramsDef = {
  22 +// token: config.baiduToken
  23 +// };
  24 +//
  25 +// // 过滤无效的参数
  26 +// _.forEach(params, (val, key) => {
  27 +// if (!val) {
  28 +// delete params[key];
  29 +// }
  30 +// });
  31 +//
  32 +// qs.escape = (str) => {
  33 +// return str;
  34 +// };
  35 +//
  36 +// let options = {
  37 +// url: `${baiduUrls.urls}?${qs.stringify(Object.assign(paramsDef, params), null, null, {})}`,
  38 +// headers: {
  39 +// 'Content-Type': 'text/plain'
  40 +// },
  41 +// method: 'post',
  42 +// form: urls.join('\n'),
  43 +// json: true,
  44 +// timeout: 10000,
  45 +// gzip: true
  46 +// };
  47 +//
  48 +// return rp(options).then(result => {
  49 +// logger.info(result);
  50 +// });
  51 +// };
  52 +
  53 +const getKeywordsApi = (page, limit) => {
  54 + let params = {
  55 + page: page || 1,
  56 + limit: limit || 1000,
  57 + method: 'web.search.suggestList'
  58 + };
  59 +
  60 + return api.get('', params);
  61 +};
  62 +
  63 +/**
  64 + * 关键词同步到redis
  65 + */
  66 +const synchronousKeywords = () => {
  67 +
  68 + return getKeywordsApi(1, 1).then(res => {
  69 + let start = 0,
  70 + page = 1,
  71 + limit = 1000, // 每次请求接口关键词数量
  72 + total = _.get(res, 'data.total', 0);
  73 +
  74 + // 接口调用失败
  75 + if (total <= 0) {
  76 + console.log('no data');
  77 + return;
  78 + }
  79 +
  80 + // 循环遍历接口关键词写入redis
  81 + let interval = setInterval(() => {
  82 + if (start > total) {
  83 + clearInterval(interval);
  84 + }
  85 +
  86 + getKeywordsApi(page, limit).then(result => {
  87 + let multi = redis.multi();
  88 +
  89 + start += limit;
  90 + page++;
  91 + console.log(page);
  92 + _.forEach(_.get(result, 'data.suggest_list', []), value => {
  93 + let key = `keywords_mana:${value.keyword}`;
  94 +
  95 + multi.set(key, value.keyword);
  96 + multi.lrem('keywords_mana_list', 1, key).lpush('keywords_mana_list', key);
  97 + });
  98 +
  99 + multiAsync(multi);
  100 +
  101 + }).catch(()=>{
  102 + clearInterval(interval);
  103 + });
  104 +
  105 + }, 1000);
  106 +
  107 + });
  108 +};
  109 +
  110 +/**
  111 + * 查询 redis中 关键词
  112 + * @type {{getKeyWordsUrl}}
  113 + */
  114 +
  115 +const getRedisKeywords = (start, end) => {
  116 + return redis.lrangeAsync('keywords_mana_list', start, end).then(res => {
  117 + let urls = [];
  118 +
  119 + _.forEach(res, keyword => {
  120 + let buff = new Buffer(keyword).toString('hex').toUpperCase();
  121 +
  122 + urls.push(`https://www.yohobuy.com/so/${buff}.html`);
  123 + });
  124 +
  125 + return urls;
  126 + });
  127 +};
  128 +
  129 +/**
  130 + * 推送url
  131 + */
  132 +const sendKeywordsUrls = () => {
  133 + return redis.llenAsync('keywords_mana_list').then(total => {
  134 + console.log(total);
  135 + if (total <= 0) {
  136 + return;
  137 + }
  138 +
  139 + let start = 0,
  140 + count = 1000;
  141 +
  142 + let interval = setInterval(() => {
  143 + if (start >= total) {
  144 + clearInterval(interval);
  145 + }
  146 +
  147 + console.log(start);
  148 + getRedisKeywords(start, start + count).then(urls => {
  149 + console.log(urls);
  150 +
  151 + // 发送到百度
  152 + // sendUrlsToBaidu({site: 'https://www.yohobuy.com'}, urls);
  153 + }).catch(() => {
  154 + clearInterval(interval);
  155 + });
  156 +
  157 + start += count;
  158 +
  159 + }, 1000);
  160 +
  161 + return [];
  162 +
  163 + });
  164 +};
  165 +
  166 +module.exports = {
  167 + synchronousKeywords,
  168 + sendKeywordsUrls
  169 +};
@@ -17,18 +17,18 @@ module.exports = { @@ -17,18 +17,18 @@ module.exports = {
17 cookieDomain: '.yohobuy.com', 17 cookieDomain: '.yohobuy.com',
18 domains: { 18 domains: {
19 // test3 19 // test3
20 - // singleApi: 'http://api-test3.yohops.com:9999/',  
21 - // api: 'http://api-test3.yohops.com:9999/',  
22 - // service: 'http://service-test3.yohops.com:9999/',  
23 - // serviceNotify: 'http://service-test3.yohops.com:9999/',  
24 - // global: 'http://global-test-soa.yohops.com:9999/', 20 + singleApi: 'http://api-test3.yohops.com:9999/',
  21 + api: 'http://api-test3.yohops.com:9999/',
  22 + service: 'http://service-test3.yohops.com:9999/',
  23 + serviceNotify: 'http://service-test3.yohops.com:9999/',
  24 + global: 'http://global-test-soa.yohops.com:9999/',
25 25
26 // prod 26 // prod
27 - singleApi: 'http://single.yoho.cn/',  
28 - api: 'http://api.yoho.cn/',  
29 - service: 'http://service.yoho.cn/',  
30 - serviceNotify: 'http://service.yoho.cn/',  
31 - global: 'http://api-global.yohobuy.com/', 27 + // singleApi: 'http://single.yoho.cn/',
  28 + // api: 'http://api.yoho.cn/',
  29 + // service: 'http://service.yoho.cn/',
  30 + // serviceNotify: 'http://service.yoho.cn/',
  31 + // global: 'http://api-global.yohobuy.com/',
32 32
33 // gray 33 // gray
34 // singleApi: 'http://single.gray.yohops.com/', 34 // singleApi: 'http://single.gray.yohops.com/',
@@ -133,7 +133,25 @@ module.exports = { @@ -133,7 +133,25 @@ module.exports = {
133 maxQps: 1200, 133 maxQps: 1200,
134 sessionMemcachedPrefix: 'yohobuy_session:', 134 sessionMemcachedPrefix: 'yohobuy_session:',
135 baiduToken: '0lSAO4ZxEKsYopMG', // 百度站长推送的token 135 baiduToken: '0lSAO4ZxEKsYopMG', // 百度站长推送的token
136 - sitemapPath: './files' 136 + redis: {
  137 + connect: {
  138 + host: '127.0.0.1',
  139 + port: '6379',
  140 + retry_strategy(options) {
  141 + if (options.error && options.error.code === 'ECONNREFUSED') {
  142 + console.log('redis连接不成功');
  143 + }
  144 + if (options.total_retry_time > 1000 * 60 * 60 * 6) {
  145 + console.log('redis连接超时');
  146 + return;
  147 + }
  148 + if (options.attempt > 10) {
  149 + return 1000 * 60 * 60 * 0.5;
  150 + }
  151 + return Math.min(options.attempt * 100, 1000);
  152 + }
  153 + }
  154 + }
137 }; 155 };
138 156
139 if (isProduction) { 157 if (isProduction) {
@@ -167,7 +185,26 @@ if (isProduction) { @@ -167,7 +185,26 @@ if (isProduction) {
167 open: false, 185 open: false,
168 url: 'http://123.206.2.55/strategy' 186 url: 'http://123.206.2.55/strategy'
169 }, 187 },
170 - zookeeperServer: 'web.zookeeper.yohoops.org:2181' 188 + zookeeperServer: 'web.zookeeper.yohoops.org:2181',
  189 + redis: {
  190 + connect: {
  191 + host: 'web.redis.yohoops.org'
  192 + },
  193 + port: '6379',
  194 + retry_strategy(options) {
  195 + if (options.error && options.error.code === 'ECONNREFUSED') {
  196 + console.log('redis连接不成功');
  197 + }
  198 + if (options.total_retry_time > 1000 * 60 * 60 * 6) {
  199 + console.log('redis连接超时');
  200 + return;
  201 + }
  202 + if (options.attempt > 10) {
  203 + return 1000 * 60 * 60 * 0.5;
  204 + }
  205 + return Math.min(options.attempt * 100, 1000);
  206 + }
  207 + }
171 }); 208 });
172 } else if (isTest) { 209 } else if (isTest) {
173 Object.assign(module.exports, { 210 Object.assign(module.exports, {
  1 +const redis = require('redis');
  2 +const bluebird = require('bluebird');
  3 +const config = require('../config/config');
  4 +let client;
  5 +
  6 +try {
  7 + client = redis.createClient(config.redis.connect);
  8 +
  9 + bluebird.promisifyAll(redis.RedisClient.prototype);
  10 + bluebird.promisifyAll(redis.Multi.prototype);
  11 +
  12 + client.on('error', function() {
  13 + global.yoho.redis = '';
  14 + });
  15 +
  16 + client.on('connect', function() {
  17 + global.yoho.redis = client;
  18 + });
  19 +} catch (e) {
  20 + global.yoho.redis = '';
  21 +}
  22 +
  23 +module.exports = client;
@@ -23,6 +23,7 @@ @@ -23,6 +23,7 @@
23 "moment": "^2.18.1", 23 "moment": "^2.18.1",
24 "node-schedule": "^1.2.1", 24 "node-schedule": "^1.2.1",
25 "nodemon": "1.9.2", 25 "nodemon": "1.9.2",
  26 + "redis": "^2.7.1",
26 "request": "^2.79.0", 27 "request": "^2.79.0",
27 "request-promise": "^4.1.1", 28 "request-promise": "^4.1.1",
28 "shelljs": "^0.7.7", 29 "shelljs": "^0.7.7",