2 changed files with 251 additions and 0 deletions
			
			
		@ -0,0 +1,233 @@ | 
				
			|||
<?php | 
				
			|||
 | 
				
			|||
namespace App\Console\Commands; | 
				
			|||
 | 
				
			|||
use App\Models\CollectProduct; | 
				
			|||
use Illuminate\Console\Command; | 
				
			|||
use Illuminate\Support\Facades\Http; | 
				
			|||
 | 
				
			|||
class Collector extends Command | 
				
			|||
{ | 
				
			|||
    /** | 
				
			|||
     * The name and signature of the console command. | 
				
			|||
     * | 
				
			|||
     * @var string | 
				
			|||
     */ | 
				
			|||
    protected $signature = 'collector'; | 
				
			|||
 | 
				
			|||
    /** | 
				
			|||
     * The console command description. | 
				
			|||
     * | 
				
			|||
     * @var string | 
				
			|||
     */ | 
				
			|||
    protected $description = '驴妈妈产品采集'; | 
				
			|||
 | 
				
			|||
    /** | 
				
			|||
	 * 如果已经存在是否要更新,true更新,false不更新 | 
				
			|||
	 * @var bool | 
				
			|||
	 */ | 
				
			|||
    private bool $exists_update = true; | 
				
			|||
 | 
				
			|||
    /** | 
				
			|||
     * Create a new command instance. | 
				
			|||
     * | 
				
			|||
     * @return void | 
				
			|||
     */ | 
				
			|||
    public function __construct() | 
				
			|||
    { | 
				
			|||
        parent::__construct(); | 
				
			|||
    } | 
				
			|||
 | 
				
			|||
    /** | 
				
			|||
     * Execute the console command. | 
				
			|||
     * | 
				
			|||
     * @return int | 
				
			|||
     */ | 
				
			|||
    public function handle() | 
				
			|||
    { | 
				
			|||
//    	$this->exists_update = false;
 | 
				
			|||
		$this->scenic(); | 
				
			|||
		$this->hotel(); | 
				
			|||
        return Command::SUCCESS; | 
				
			|||
    } | 
				
			|||
    //php artisan collector
 | 
				
			|||
 | 
				
			|||
    //酒店采集
 | 
				
			|||
    private function hotel() | 
				
			|||
    { | 
				
			|||
        $http = Http::withOptions(['verify' => false]); | 
				
			|||
 | 
				
			|||
        $mddid = 10030; //10030==三亚
 | 
				
			|||
        for ($i=0; $i<10; $i++) { | 
				
			|||
        	$this->line('开始采集:第 ' . ($i + 1) . ' 页'); | 
				
			|||
			$data = $http->get('https://m.mafengwo.cn/rest/hotel/hotels/', [ | 
				
			|||
				'filter' => [ | 
				
			|||
					'mddid' => $mddid | 
				
			|||
				], | 
				
			|||
				'page' => [ | 
				
			|||
					'mode' => 'sequential', | 
				
			|||
					'boundary' => $i * 20, //分页参数
 | 
				
			|||
					'num' => 20 | 
				
			|||
				], | 
				
			|||
			]); | 
				
			|||
 | 
				
			|||
			if (empty($data['data']['list'])) { | 
				
			|||
				continue; | 
				
			|||
			} | 
				
			|||
 | 
				
			|||
			foreach ($data['data']['list'] as $v) { | 
				
			|||
				if (empty($v['id'])) continue; | 
				
			|||
 | 
				
			|||
				if ($this->exists_update == false && CollectProduct::where(['unique_id' => $v['id'], 'site' => 1])->exists()) { | 
				
			|||
					continue; | 
				
			|||
				} | 
				
			|||
 | 
				
			|||
				$this->line('采集详情:' . $v['id']); | 
				
			|||
 | 
				
			|||
				//基本信息
 | 
				
			|||
				$params = [ | 
				
			|||
					'_ts' => time() . '123', | 
				
			|||
					'hotel_id' => (string)$v['id'], | 
				
			|||
					'lat' => '', | 
				
			|||
					'lng' => '', | 
				
			|||
					'rmdd_id' => (string)$mddid, | 
				
			|||
				]; | 
				
			|||
				$params['_sn'] = $this->_sn($params); | 
				
			|||
				$data = $http->get('https://m.mafengwo.cn/hservice/detail/info/base_info', $params); | 
				
			|||
 | 
				
			|||
				if (empty($data['data']['info'])) { | 
				
			|||
					continue; | 
				
			|||
				} | 
				
			|||
				$base_info = $data['data']['info']; | 
				
			|||
 | 
				
			|||
				//酒店详情
 | 
				
			|||
				$data = $http->get('https://m.mafengwo.cn/hservice/detail/info/guide_info', ['hotel_id' => $v['id']]); | 
				
			|||
				$guide_info = $data['data']['info'] ?? []; | 
				
			|||
 | 
				
			|||
				//旅游须知
 | 
				
			|||
				$know = "<p>入住时间:" . (!empty($guide_info['check_in']['title']) ? $guide_info['check_in']['title'] : '') . "</p>"; | 
				
			|||
				$know .= "<p>离店时间:" . (!empty($guide_info['check_out']['title']) ? $guide_info['check_out']['title'] : '') . "</p>"; | 
				
			|||
				$know .= '<p>' . array_reduce($base_info['facility_sort'] ?? [], fn($v1, $v2) => $v1 . $v2['title'] ?? '') . '</p>'; | 
				
			|||
 | 
				
			|||
				//扩展字段
 | 
				
			|||
				$extends['field_1_tags'] = array_map(fn($v) => $v['title'] ?? '', $guide_info['facility'] ?? []); | 
				
			|||
				$extends['field_1_name'] = $base_info['name']; | 
				
			|||
				$extends['field_1_address'] = $base_info['address']; | 
				
			|||
				$extends['field_1_latitude'] = $base_info['lat']; | 
				
			|||
				$extends['field_1_longitude'] = $base_info['lng']; | 
				
			|||
 | 
				
			|||
				CollectProduct::updateOrCreate(['unique_id' => $v['id'], 'site' => 1], [ | 
				
			|||
					'unique_id' => $v['id'], | 
				
			|||
					'site' => 1, | 
				
			|||
					'type' => 1, //0:旅游线路、1:酒店、2:景区、3:餐厅、4:车队、5:单项
 | 
				
			|||
					'title' => mb_substr($base_info['name'] ?? '' . $base_info['level'] ?? '', 0, 255), | 
				
			|||
					'price' => mt_rand(150, 350), | 
				
			|||
					'original_price' => mt_rand(350, 550), | 
				
			|||
					'pictures' => array_map(fn($v) => $v['url'] ?? '', $base_info['album'] ?? []) ?? [], | 
				
			|||
					'stock' => mt_rand(1000, 9999), | 
				
			|||
					'sale' => $base_info['num_collect'] ?? 0, | 
				
			|||
					'status' => -2, //-2下架
 | 
				
			|||
					'know' => $know, | 
				
			|||
					'content' => $guide_info['intro'] ?? '', | 
				
			|||
					'extends' => $extends, | 
				
			|||
					'logitude' => $base_info['lng'] ?? 0, | 
				
			|||
					'latitude' => $base_info['lat'] ?? 0, | 
				
			|||
					'address' => $base_info['address'] ?? '', | 
				
			|||
				]); | 
				
			|||
				$this->line("{$v['id']} 采集结束" . PHP_EOL); | 
				
			|||
			} | 
				
			|||
			$this->line('第 ' . ($i + 1) . ' 页采集结束' . PHP_EOL); | 
				
			|||
        } | 
				
			|||
    } | 
				
			|||
 | 
				
			|||
    //酒店详情计算_sn
 | 
				
			|||
    private function _sn($params): string | 
				
			|||
	{ | 
				
			|||
		ksort($params); | 
				
			|||
		return substr(md5(json_encode($params) . 'c9d6618dbc657b41a66eb0af952906f1'), 2, 10); | 
				
			|||
	} | 
				
			|||
 | 
				
			|||
    //景区采集
 | 
				
			|||
    private function scenic() | 
				
			|||
    { | 
				
			|||
        $http = Http::withOptions(['verify' => false]); | 
				
			|||
 | 
				
			|||
        for($i=0; $i<10; $i++) { | 
				
			|||
            $data = $http->get('https://m.mafengwo.cn/sales/ajax.php', [ | 
				
			|||
                'sF' => 'search_new_list', | 
				
			|||
                'offset' => $i * 10, //分页参数
 | 
				
			|||
            ]); | 
				
			|||
 | 
				
			|||
            if (empty($data['data'])) { | 
				
			|||
				continue; | 
				
			|||
			} | 
				
			|||
			$data = $data['data']; | 
				
			|||
 | 
				
			|||
            preg_match_all('/<a href="\/sales\/(\d+)\.html"/', $data, $matches); | 
				
			|||
            if (empty($matches[1])) continue; | 
				
			|||
 | 
				
			|||
			foreach ($matches[1] as $id) { | 
				
			|||
				if ($this->exists_update == false && CollectProduct::where(['unique_id' => $id, 'site' => 1])->exists()) { | 
				
			|||
					continue; | 
				
			|||
				} | 
				
			|||
 | 
				
			|||
				$this->line('开始采集:' . $id); | 
				
			|||
				$info = $http->get('https://m.mafengwo.cn/sales/detail/index/info?id=' . $id); | 
				
			|||
 | 
				
			|||
				//旅游须知
 | 
				
			|||
				$know = $info['data']['list']['content'][0]['content'] ?? []; | 
				
			|||
				if (isset($info['data']['list']['content'][0]['content']) && is_array($info['data']['list']['content'][0]['content'])) { | 
				
			|||
					$know = current(array_filter($info['data']['list']['content'][0]['content'], fn($v) => isset($v['name']) && $v['name'] == '购买须知')); | 
				
			|||
					if (isset($know['content']) && is_array($know['content'])) { | 
				
			|||
						$know = array_reduce( | 
				
			|||
							$know['content'], fn($v1, $v2) => $v1 . | 
				
			|||
							(isset($v2['name']) && is_string($v2['name']) ? "<h3>{$v2['name']}</h3>" : '') . | 
				
			|||
							(isset($v2['content']) && is_string($v2['content']) ? $v2['content'] : '') | 
				
			|||
						); | 
				
			|||
					} | 
				
			|||
				} | 
				
			|||
 | 
				
			|||
				//产品详情
 | 
				
			|||
				$content = ''; | 
				
			|||
				if (isset($info['data']['list']['content'][0]['content']) && is_array($info['data']['list']['content'][0]['content'])) { | 
				
			|||
					$content = current(array_filter($info['data']['list']['content'][0]['content'], fn($v) => isset($v['key']) && $v['key'] == 'introduce')); | 
				
			|||
					if (isset($content['content']) && is_array($content['content'])) { | 
				
			|||
						$content = current(array_filter($content['content'], fn($v) => isset($v['key']) && $v['key'] == 'introduction')); | 
				
			|||
						$content = is_string($content['content']) ? $content['content'] : ''; | 
				
			|||
					} else { | 
				
			|||
						$content = ''; | 
				
			|||
					} | 
				
			|||
				} | 
				
			|||
 | 
				
			|||
				//扩展字段
 | 
				
			|||
				$extends = []; | 
				
			|||
				if (isset($info['data']['list']['base']['tags']) && is_array($info['data']['list']['base']['tags'])) { | 
				
			|||
					foreach ($info['data']['list']['base']['tags'] as $tag) { | 
				
			|||
						$extends['field_2_project'][] = ['name' => $tag, 'num' => '', 'price' => '']; | 
				
			|||
					} | 
				
			|||
				} | 
				
			|||
 | 
				
			|||
				CollectProduct::updateOrCreate(['unique_id' => $id, 'site' => 1], [ | 
				
			|||
					'unique_id' => $id, | 
				
			|||
					'site' => 1, | 
				
			|||
					'type' => 2, //0:旅游线路、1:酒店、2:景区、3:餐厅、4:车队、5:单项
 | 
				
			|||
					'title' => mb_substr($info['data']['list']['base']['title'] ?? '', 0, 255), | 
				
			|||
					'price' => $info['data']['list']['base']['price_zhanshi'] ?? 0, | 
				
			|||
					'original_price' => ($info['data']['list']['base']['price_zhanshi'] ?? 0) * 1.58, | 
				
			|||
					'pictures' => $info['data']['list']['base']['imgList'] ?? [], | 
				
			|||
					'stock' => mt_rand(1000, 9999), | 
				
			|||
					'sale' => $info['data']['list']['base']['sold']['num'] ?? 0, | 
				
			|||
					'status' => -2, //-2下架
 | 
				
			|||
					'know' => $know, | 
				
			|||
					'content' => $content, | 
				
			|||
					'extends' => $extends, | 
				
			|||
					'logitude' => 0, | 
				
			|||
					'latitude' => 0, | 
				
			|||
					'address' => '', | 
				
			|||
				]); | 
				
			|||
 | 
				
			|||
				$this->line($id . ' 采集完毕!' . PHP_EOL); | 
				
			|||
			} | 
				
			|||
        } | 
				
			|||
    } | 
				
			|||
} | 
				
			|||
@ -0,0 +1,18 @@ | 
				
			|||
<?php | 
				
			|||
 | 
				
			|||
namespace App\Models; | 
				
			|||
 | 
				
			|||
use Illuminate\Database\Eloquent\Factories\HasFactory; | 
				
			|||
use Illuminate\Database\Eloquent\Model; | 
				
			|||
use Illuminate\Database\Eloquent\Concerns\HasTimestamps; | 
				
			|||
 | 
				
			|||
class CollectProduct extends Model | 
				
			|||
{ | 
				
			|||
    use HasFactory, HasTimestamps; | 
				
			|||
 | 
				
			|||
    protected $guarded = ['id']; | 
				
			|||
    protected $casts = [ | 
				
			|||
        'pictures' => 'json', | 
				
			|||
        'extends' => 'json', | 
				
			|||
    ]; | 
				
			|||
} | 
				
			|||
						Write
						Preview
					
					
					Loading…
					
					Cancel
						Save
					
		Reference in new issue