You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							281 lines
						
					
					
						
							8.9 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							281 lines
						
					
					
						
							8.9 KiB
						
					
					
				
								<?php
							 | 
						|
								
							 | 
						|
								namespace App\Console\Commands;
							 | 
						|
								
							 | 
						|
								use App\Models\CollectProduct;
							 | 
						|
								use App\Models\Product;
							 | 
						|
								use App\Models\Supplier;
							 | 
						|
								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 {--import=} {--limit=}'; //php artisan collector --import=$supplier_id
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * 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()
							 | 
						|
								    {
							 | 
						|
										$supplier_id = $this->option('import');
							 | 
						|
										if (!empty($supplier_id)) {
							 | 
						|
											$this->import($supplier_id);
							 | 
						|
											$this->line("供应商 $supplier_id 导入完毕");
							 | 
						|
										} else {
							 | 
						|
								//    		$this->exists_update = false;
							 | 
						|
											$this->tourist_line();
							 | 
						|
											$this->hotel();
							 | 
						|
											$this->line('全部采集完毕');
							 | 
						|
										}
							 | 
						|
								        return Command::SUCCESS;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    //导入
							 | 
						|
								    private function import($supplier_id)
							 | 
						|
									{
							 | 
						|
										$limit = $this->option('limit');
							 | 
						|
										$cpModel = CollectProduct::query()->orderBy('id', 'desc');
							 | 
						|
										if (!empty($limit)) {
							 | 
						|
											$arr = explode(',', $limit);
							 | 
						|
											$count = count($arr);
							 | 
						|
								
							 | 
						|
											if ($count == 1) {
							 | 
						|
												$import_data = $cpModel->limit($arr[0])->get()->toArray();
							 | 
						|
											} else if ($count == 2) {
							 | 
						|
												$import_data = $cpModel->offset($arr[0])->limit($arr[1])->get()->toArray();
							 | 
						|
											} else {
							 | 
						|
												$import_data = $cpModel->get()->toArray();
							 | 
						|
											}
							 | 
						|
										} else {
							 | 
						|
											$import_data = $cpModel->get()->toArray();
							 | 
						|
										}
							 | 
						|
								
							 | 
						|
										if (ctype_digit($supplier_id)) {
							 | 
						|
											$ids = [$supplier_id];
							 | 
						|
										} else if ($supplier_id == 'all') {
							 | 
						|
											$ids = Supplier::query()->where('id', '>', 1)->pluck('id');
							 | 
						|
										} else {
							 | 
						|
											return;
							 | 
						|
										}
							 | 
						|
								
							 | 
						|
										foreach ($ids as $supplier_id) {
							 | 
						|
											$this->line('正在导入 ' . $supplier_id);
							 | 
						|
											array_walk($import_data, function ($v) use ($supplier_id) {
							 | 
						|
												$v['supplier_id'] = $supplier_id;
							 | 
						|
												unset($v['unique_id'], $v['site']);
							 | 
						|
								
							 | 
						|
												Product::query()->updateOrCreate(['supplier_id' => $supplier_id, 'title' => $v['title']], $v);
							 | 
						|
											});
							 | 
						|
											$this->line("导入 $supplier_id 结束");
							 | 
						|
										}
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
								    //酒店采集
							 | 
						|
								    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,
							 | 
						|
													'longitude' => $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 tourist_line()
							 | 
						|
								    {
							 | 
						|
								        $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_0_project'][] = ['name' => $tag, 'num' => '', 'price' => ''];
							 | 
						|
													}
							 | 
						|
												}
							 | 
						|
								
							 | 
						|
												CollectProduct::updateOrCreate(['unique_id' => $id, 'site' => 1], [
							 | 
						|
													'unique_id' => $id,
							 | 
						|
													'site' => 1,
							 | 
						|
													'type' => 0, //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,
							 | 
						|
													'longitude' => 0,
							 | 
						|
													'latitude' => 0,
							 | 
						|
													'address' => '',
							 | 
						|
												]);
							 | 
						|
								
							 | 
						|
												$this->line($id . ' 采集完毕!' . PHP_EOL);
							 | 
						|
											}
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								}
							 |