海南旅游SAAS
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.

268 lines
8.5 KiB

4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
  1. <?php
  2. namespace App\Console\Commands;
  3. use App\Models\CollectProduct;
  4. use App\Models\Product;
  5. use Illuminate\Console\Command;
  6. use Illuminate\Support\Facades\Http;
  7. class Collector extends Command
  8. {
  9. /**
  10. * The name and signature of the console command.
  11. *
  12. * @var string
  13. */
  14. protected $signature = 'collector {--import=} {--limit=}'; //php artisan collector --import=$supplier_id
  15. /**
  16. * The console command description.
  17. *
  18. * @var string
  19. */
  20. protected $description = '驴妈妈产品采集';
  21. /**
  22. * 如果已经存在是否要更新,true更新,false不更新
  23. * @var bool
  24. */
  25. private bool $exists_update = true;
  26. /**
  27. * Create a new command instance.
  28. *
  29. * @return void
  30. */
  31. public function __construct()
  32. {
  33. parent::__construct();
  34. }
  35. /**
  36. * Execute the console command.
  37. *
  38. * @return int
  39. */
  40. public function handle()
  41. {
  42. $supplier_id = $this->option('import');
  43. if (!empty($supplier_id)) {
  44. if (ctype_digit($supplier_id)) {
  45. $this->import($supplier_id);
  46. }
  47. $this->line("供应商 $supplier_id 导入完毕");
  48. } else {
  49. // $this->exists_update = false;
  50. $this->scenic();
  51. $this->hotel();
  52. $this->line('全部采集完毕');
  53. }
  54. return Command::SUCCESS;
  55. }
  56. //导入
  57. private function import($supplier_id)
  58. {
  59. $limit = $this->option('limit');
  60. if (!empty($limit)) {
  61. $arr = explode(',', $limit);
  62. $count = count($arr);
  63. $cpModel = CollectProduct::query()->orderBy('id', 'desc');
  64. if ($count == 1) {
  65. $import_data = $cpModel->limit($arr[0])->get()->toArray();
  66. } else if ($count == 2) {
  67. $import_data = $cpModel->offset($arr[0])->limit($arr[1])->get()->toArray();
  68. } else {
  69. $import_data = $cpModel->get()->toArray();
  70. }
  71. array_walk($import_data, function ($v) use ($supplier_id) {
  72. $v['supplier_id'] = $supplier_id;
  73. unset($v['unique_id'], $v['site']);
  74. Product::query()->updateOrCreate(['supplier_id' => $supplier_id, 'title' => $v['title']], $v);
  75. });
  76. }
  77. }
  78. //酒店采集
  79. private function hotel()
  80. {
  81. $http = Http::withOptions(['verify' => false]);
  82. $mddid = 10030; //10030==三亚
  83. for ($i=0; $i<10; $i++) {
  84. $this->line('开始采集:第 ' . ($i + 1) . ' 页');
  85. $data = $http->get('https://m.mafengwo.cn/rest/hotel/hotels/', [
  86. 'filter' => [
  87. 'mddid' => $mddid
  88. ],
  89. 'page' => [
  90. 'mode' => 'sequential',
  91. 'boundary' => $i * 20, //分页参数
  92. 'num' => 20
  93. ],
  94. ]);
  95. if (empty($data['data']['list'])) {
  96. continue;
  97. }
  98. foreach ($data['data']['list'] as $v) {
  99. if (empty($v['id'])) continue;
  100. if ($this->exists_update == false && CollectProduct::where(['unique_id' => $v['id'], 'site' => 1])->exists()) {
  101. continue;
  102. }
  103. $this->line('采集详情:' . $v['id']);
  104. //基本信息
  105. $params = [
  106. '_ts' => time() . '123',
  107. 'hotel_id' => (string)$v['id'],
  108. 'lat' => '',
  109. 'lng' => '',
  110. 'rmdd_id' => (string)$mddid,
  111. ];
  112. $params['_sn'] = $this->_sn($params);
  113. $data = $http->get('https://m.mafengwo.cn/hservice/detail/info/base_info', $params);
  114. if (empty($data['data']['info'])) {
  115. continue;
  116. }
  117. $base_info = $data['data']['info'];
  118. //酒店详情
  119. $data = $http->get('https://m.mafengwo.cn/hservice/detail/info/guide_info', ['hotel_id' => $v['id']]);
  120. $guide_info = $data['data']['info'] ?? [];
  121. //旅游须知
  122. $know = "<p>入住时间:" . (!empty($guide_info['check_in']['title']) ? $guide_info['check_in']['title'] : '') . "</p>";
  123. $know .= "<p>离店时间:" . (!empty($guide_info['check_out']['title']) ? $guide_info['check_out']['title'] : '') . "</p>";
  124. $know .= '<p>' . array_reduce($base_info['facility_sort'] ?? [], fn($v1, $v2) => $v1 . $v2['title'] ?? '') . '</p>';
  125. //扩展字段
  126. $extends['field_1_tags'] = array_map(fn($v) => $v['title'] ?? '', $guide_info['facility'] ?? []);
  127. $extends['field_1_name'] = $base_info['name'];
  128. $extends['field_1_address'] = $base_info['address'];
  129. $extends['field_1_latitude'] = $base_info['lat'];
  130. $extends['field_1_longitude'] = $base_info['lng'];
  131. CollectProduct::updateOrCreate(['unique_id' => $v['id'], 'site' => 1], [
  132. 'unique_id' => $v['id'],
  133. 'site' => 1,
  134. 'type' => 1, //0:旅游线路、1:酒店、2:景区、3:餐厅、4:车队、5:单项
  135. 'title' => mb_substr($base_info['name'] ?? '' . $base_info['level'] ?? '', 0, 255),
  136. 'price' => mt_rand(150, 350),
  137. 'original_price' => mt_rand(350, 550),
  138. 'pictures' => array_map(fn($v) => $v['url'] ?? '', $base_info['album'] ?? []) ?? [],
  139. 'stock' => mt_rand(1000, 9999),
  140. 'sale' => $base_info['num_collect'] ?? 0,
  141. 'status' => -2, //-2下架
  142. 'know' => $know,
  143. 'content' => $guide_info['intro'] ?? '',
  144. 'extends' => $extends,
  145. 'logitude' => $base_info['lng'] ?? 0,
  146. 'latitude' => $base_info['lat'] ?? 0,
  147. 'address' => $base_info['address'] ?? '',
  148. ]);
  149. $this->line("{$v['id']} 采集结束" . PHP_EOL);
  150. }
  151. $this->line('第 ' . ($i + 1) . ' 页采集结束' . PHP_EOL);
  152. }
  153. }
  154. //酒店详情计算_sn
  155. private function _sn($params): string
  156. {
  157. ksort($params);
  158. return substr(md5(json_encode($params) . 'c9d6618dbc657b41a66eb0af952906f1'), 2, 10);
  159. }
  160. //景区采集
  161. private function scenic()
  162. {
  163. $http = Http::withOptions(['verify' => false]);
  164. for($i=0; $i<10; $i++) {
  165. $data = $http->get('https://m.mafengwo.cn/sales/ajax.php', [
  166. 'sF' => 'search_new_list',
  167. 'offset' => $i * 10, //分页参数
  168. ]);
  169. if (empty($data['data'])) {
  170. continue;
  171. }
  172. $data = $data['data'];
  173. preg_match_all('/<a href="\/sales\/(\d+)\.html"/', $data, $matches);
  174. if (empty($matches[1])) continue;
  175. foreach ($matches[1] as $id) {
  176. if ($this->exists_update == false && CollectProduct::where(['unique_id' => $id, 'site' => 1])->exists()) {
  177. continue;
  178. }
  179. $this->line('开始采集:' . $id);
  180. $info = $http->get('https://m.mafengwo.cn/sales/detail/index/info?id=' . $id);
  181. //旅游须知
  182. $know = $info['data']['list']['content'][0]['content'] ?? [];
  183. if (isset($info['data']['list']['content'][0]['content']) && is_array($info['data']['list']['content'][0]['content'])) {
  184. $know = current(array_filter($info['data']['list']['content'][0]['content'], fn($v) => isset($v['name']) && $v['name'] == '购买须知'));
  185. if (isset($know['content']) && is_array($know['content'])) {
  186. $know = array_reduce(
  187. $know['content'], fn($v1, $v2) => $v1 .
  188. (isset($v2['name']) && is_string($v2['name']) ? "<h3>{$v2['name']}</h3>" : '') .
  189. (isset($v2['content']) && is_string($v2['content']) ? $v2['content'] : '')
  190. );
  191. }
  192. }
  193. //产品详情
  194. $content = '';
  195. if (isset($info['data']['list']['content'][0]['content']) && is_array($info['data']['list']['content'][0]['content'])) {
  196. $content = current(array_filter($info['data']['list']['content'][0]['content'], fn($v) => isset($v['key']) && $v['key'] == 'introduce'));
  197. if (isset($content['content']) && is_array($content['content'])) {
  198. $content = current(array_filter($content['content'], fn($v) => isset($v['key']) && $v['key'] == 'introduction'));
  199. $content = is_string($content['content']) ? $content['content'] : '';
  200. } else {
  201. $content = '';
  202. }
  203. }
  204. //扩展字段
  205. $extends = [];
  206. if (isset($info['data']['list']['base']['tags']) && is_array($info['data']['list']['base']['tags'])) {
  207. foreach ($info['data']['list']['base']['tags'] as $tag) {
  208. $extends['field_2_project'][] = ['name' => $tag, 'num' => '', 'price' => ''];
  209. }
  210. }
  211. CollectProduct::updateOrCreate(['unique_id' => $id, 'site' => 1], [
  212. 'unique_id' => $id,
  213. 'site' => 1,
  214. 'type' => 2, //0:旅游线路、1:酒店、2:景区、3:餐厅、4:车队、5:单项
  215. 'title' => mb_substr($info['data']['list']['base']['title'] ?? '', 0, 255),
  216. 'price' => $info['data']['list']['base']['price_zhanshi'] ?? 0,
  217. 'original_price' => ($info['data']['list']['base']['price_zhanshi'] ?? 0) * 1.58,
  218. 'pictures' => $info['data']['list']['base']['imgList'] ?? [],
  219. 'stock' => mt_rand(1000, 9999),
  220. 'sale' => $info['data']['list']['base']['sold']['num'] ?? 0,
  221. 'status' => -2, //-2下架
  222. 'know' => $know,
  223. 'content' => $content,
  224. 'extends' => $extends,
  225. 'logitude' => 0,
  226. 'latitude' => 0,
  227. 'address' => '',
  228. ]);
  229. $this->line($id . ' 采集完毕!' . PHP_EOL);
  230. }
  231. }
  232. }
  233. }