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