WebTraffic.php 11.5 KB
<?php

namespace App\Console\Commands;

use App\Helper\Arr;
use App\Models\Product\Category;
use App\Models\Product\Product;
use App\Models\RouteMap\RouteMap;
use GuzzleHttp\Client;
use GuzzleHttp\Promise\Utils;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;

/**
 * 网站引流
 * Class Traffic
 * @package App\Console\Commands
 * @author zbj
 * @date 2023/5/18
 */
class WebTraffic extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'web_traffic {type}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = '网站引流';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * google域名后缀
     * @var string[]
     */
    protected $suffix = [
        'co.jp' => '日本',
        'com.tr' => '土耳其',
        'nl' => '荷兰',
        'ru' => '俄罗斯',
        'fr' => '法国',
        'co.kr' => '韩国',
        'fi' => '芬兰',
        'be' => '比利时',
        'lt' => '立陶宛',
        'es' => '西班牙',
        'it' => '意大利',
        'com.au' => '澳大利亚',
        'no' => '挪威',
        'al' => '阿尔巴尼亚',
        'pt' => '葡萄牙',
        'lv' => '拉脱维亚',
        'hu' => '匈牙利',
        'cz' => '捷克',
        'de' => '德国',
        'ca' => '加拿大',
        'co.in' => '印度',
        'co.uk' => '英国',
        'com.vn' => '越南',
        'com.br' => '巴西',
        'co.il' => '以色列',
        'pl' => '波兰',
        'com.eg' => '埃及',
        'co.th' => '泰国',
        'sk' => '斯洛伐克',
        'ro' => '罗马尼亚',
        'com.mx' => '墨西哥',
        'com.my' => '马来西亚',
        'com.pk' => '巴基斯坦',
        'co.nz' => '新西兰',
        'co.za' => '南非',
        'com.ar' => '阿根廷',
        'com.kw' => '科威特',
        'com.sg' => '新加坡',
        'com.co' => '哥伦比亚',
        'co.id' => '印度尼西亚',
        'gr' => '希腊',
        'bg' => '保加利亚',
        'mn' => '蒙古',
        'dk' => '丹麦',
        'com.sa' => '沙特阿拉伯',
        'com.pe' => '秘鲁',
        'com.ph' => '菲律宾',
        'com.ua' => '乌克兰',
        'ge' => '格鲁吉亚',
        'ae' => '阿拉伯联合酋长国',
        'tn' => '突尼斯',
    ];

    /**
     * 概率值
     * @var int[]
     */
    protected $sjjg = [720, 280];//访问间隔占比  访问|不访问
    //访问页面类型占比  产品详情页、单页|产品分类页
    protected $ymzb = [
        'urls_cats' => 700,
        'urls_details' => 300
    ];
    protected $sdzb = [600, 200, 150, 50]; //访问页面深度占比 1页|2页|3-6页|7-11页
    protected $yddzb = [1 => 700, 2 => 300]; //移动端占比 pc|mobile
    //模拟访问来源占比 (美国)
    protected $lyzb = [
        'https://www.google.com/' => 630,
        'http://www.google.com/' => 30,
        'http://www.bing.com/' => 20,
        'https://www.bing.com/' => 5,
        'https://www.youtube.com/' => 5,
        'https://search.yahoo.com/' => 5,
        'https://www.facebook.com/' => 5,
    ];
    protected $otherzb = [700, 300]; //模拟访问来源占比 (非美国) google.com|google.其他后缀

    protected $pc_ua = [
        0  => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_0) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11',
        1  => 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36',
        2  => 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1'
    ];

    protected $mobile_ua = [
        0  => 'Mozilla/5.0 (Linux; Android 4.2.1; en-us; Nexus 5 Build/JOP40D) AppleWebKit/535.19 (KHTML, like Gecko; googleweblight) Chrome/38.0.1025.166 Mobile Safari/535.19',
    ];

    /**
     * @return bool
     */
    public function handle()
    {
        $type = $this->argument('type');

        $this->sleep($type);

        $project_list = $this->getProjectList($type);
        $project_chunk = array_chunk($project_list,500,true);

        foreach ($project_chunk as $chunk) {
            $need_project = [];
            foreach ($chunk as $project) {
                //随机引流间隔
                $res_sjjg = $this->get_rand($this->sjjg);
                if ($res_sjjg == 1) {
                    continue;
                }

                $project_urls = $this->getProductUrls($project['project_id']);
                $project_urls['home'] = $project['domain'];
                //随机访问页面
                $project['visit_urls'] = $this->getVisitUrls($project_urls);
                //随机客户端
                $project['device_port'] = $this->get_rand($this->yddzb);
                $project['user_agent'] = $project['device_port'] == 1 ? Arr::random($this->pc_ua) : Arr::random($this->mobile_ua);

                $need_project[] = $project;
            }

            //随机访问ip
            $ips = $this->getIpAreas(count($need_project));
            //最多10层深度
            $client = new Client(['verify' => false]);
            for ($j = 0; $j < 10; $j++) {
                for ($j = 0; $j < 10; $j++) {
                    //并发请求
                    $promises = [];
                    foreach ($need_project as $project_key => $project) {
                        if (empty($project['visit_urls'][$j])) {
                            continue;
                        }

                        $data = [
                            'ip' => $ips[$project_key]['ip'],
                            'referer' => $this->getReferer($ips[$project_key]['ip_area']),
                            'url' => $project['visit_urls'][$j],
                            'device_port' => $this->get_rand($this->yddzb)
                        ];
                        $promises[] = $client->postAsync($project['domain'] . 'api/customerVisit', ['form_params' => $data]);
                    }
                    Utils::settle($promises)->wait();

                    //每个深度随机等待
                    sleep(rand(2, 10));
                }
            }
        }
    }

    /**
     * 不同项目 休眠
     */
    protected function sleep($type){
        if($type == 1){ //1-3个月的项目
            sleep(rand(5,480));
        }elseif($type == 2){ //4-8个月的项目
            sleep(rand(5,240));
        }elseif($type == 3){ // 大于9个月的项目
            sleep(rand(5,120));
        }
    }

    /**
     * 引流的项目
     */
    protected function getProjectList($type){
        //todo 根据type获取需要引流的项目
        return [
            [
                'project_id' => 1,
                'domain' => 'https://demomark.globalso.com/',
            ]
        ];
    }

    /**
     * 获取产品分类、单页和详情链接
     */
    protected function getProductUrls($project_id){
        //产品分类页面
        $product_cate_ids = Category::where('project_id', $project_id)->where('status', Category::STATUS_ACTIVE)->pluck('id')->toArray();
        $data['urls_cats'] = RouteMap::where('project_id', $project_id)->where('source', RouteMap::SOURCE_PRODUCT_CATE)->whereIn('source_id', $product_cate_ids)->get()->toArray();
        //单页面
        //todo 发布状态的单页面id
        $data['urls_page'] = RouteMap::where('project_id', $project_id)->where('source', RouteMap::SOURCE_PAGE)->get()->toArray();
        //产品详情页
        $product_ids = Product::where('project_id', $project_id)->where('status', Product::STATUS_ON)->pluck('id')->toArray();
        $data['urls_details'] = RouteMap::where('project_id', $project_id)->where('source', RouteMap::SOURCE_PRODUCT)->whereIn('source_id', $product_ids)->get()->toArray();

        $data['urls_cats'] = array_merge($data['urls_cats'], $data['urls_page']);
        if(empty($data['urls_cats'])){
            $data['urls_cats'] = $data['urls_details'];
        }

        return $data;
    }

    /**
     * 获取地区IP
     */
    protected function getIpAreas($num)
    {
        //本地时间为7-23点的地区
        $h = date('H');
        $areas = [];
        $list = DB::table('gl_area_timezone')->get();
        foreach ($list as $v) {
            $v = (array)$v;
            $country_hour = $h + $v['diff'];
            if ($country_hour < 0) {
                $country_hour = 24 + $country_hour;
            }
            if ($country_hour >= 7 && $country_hour < 23) {
                $areas[] = $v['name'];
            }
        }
        //根据地区随机取该地区的IP
        $data = DB::table('gl_xunpan_ipdata')->whereIn('ip_area', $areas)->inRandomOrder()->limit($num)->get();
        return Arr::s2a(Arr::a2s($data));
    }

    /**
     * 概率算法
     */
    protected function get_rand($proArr) {
        $result = '';
        $proSum = array_sum($proArr);
        foreach ($proArr as $key => $proCur) {
            $randNum = mt_rand(1, $proSum);
            if ($randNum <= $proCur) {
                $result = $key;
                break;
            } else {
                $proSum -= $proCur;
            }
        }
        unset ($proArr);
        return $result;
    }

    /**
     * 根据随机访问深度 随机获取访问页面
     */
    protected function getVisitUrls($project_urls){
        //没有分类页 就只访问首页
        if(!$project_urls['urls_cats']){
            $url[] = $project_urls['home'];
            return $url;
        }
        //随机访问深度
        $res_sdzb = $this->get_rand($this->sdzb);
        //随机访问页面类型
        $res_ymzb = $this->get_rand($this->ymzb);

        $all_url = array_merge($project_urls['urls_cats'],$project_urls['urls_details']);
        if(!$all_url){
            $url[] = $project_urls['home'];
            return $url;
        }

        $url = [];
        if($res_sdzb == 0){//深度一页
            $url[] = $project_urls[$res_ymzb] ? Arr::random($project_urls[$res_ymzb])['route'] : '';
        }elseif($res_sdzb == 1){//深度两页
            $url[] = $project_urls['home'];
            $url[] = $project_urls[$res_ymzb] ? Arr::random($project_urls[$res_ymzb])['route'] : '';
        }elseif($res_sdzb == 2){//深度3-6页
            $yms = rand(2,5); //随机页面数
            $url = Arr::pluck(Arr::random($all_url, $yms), 'route');
            $url = Arr::prepend($url, $project_urls['home']);//首页加到最前面去
        }elseif($res_sdzb == 3){//深度7-11页
            $yms = rand(6,10); //随机页面数
            $url = Arr::pluck(Arr::random($all_url, $yms), 'route');
            $url = Arr::prepend($url, $project_urls['home']);//首页加到最前面去
        }
        foreach ($url as &$v){
            if(!Str::contains($v, $project_urls['home'])){
                $v = $project_urls['home'] . $v;
            }
        }
        return array_unique(array_filter($url));
    }

    /**
     * 获取访问来路
     */
    protected function getReferer($ip_area){
        if($ip_area == '美国'){
            $referer = $this->get_rand($this->lyzb);
        }else{
            $referer = 'https://www.google.com/';

            $suffix = array_search($ip_area, $this->suffix);
            if($suffix){
                $res_qtzb = $this->get_rand($this->otherzb);
                if($res_qtzb == 1){
                    $referer = 'https://www.google.'.$suffix.'/';
                }
            }
        }
        return $referer;
    }
}