فهرست منبع

feat: [api - crop] for 1111 &104

Hugh Harlequin 2 سال پیش
والد
کامیت
efdbf89a61

+ 24 - 0
app/Http/Controllers/Api/Crop/CropController.php

@@ -0,0 +1,24 @@
+<?php
+
+
+namespace App\Http\Controllers\Api\Crop;
+
+
+class CropController
+{
+    private $service;
+    public function __construct(\Illuminate\Http\Request $request)
+    {
+        $crop = $request->route()->crop;
+        $serviceName = "\App\Services\Api\Crop\Crop{$crop}Service";
+        $this->service = new $serviceName;
+    }
+    public function search($crop, $name)
+    {
+        return $this->service->search($name);
+    }
+    public function getJobs($crop, $encodedCustNo)
+    {
+        return $this->service->jobList($encodedCustNo);
+    }
+}

+ 1 - 0
app/Providers/RouteServiceProvider.php

@@ -31,6 +31,7 @@ class RouteServiceProvider extends ServiceProvider
         $this->routes(function () {
             Route::middleware('api')
                 ->prefix('api')
+                ->namespace('App\Http\Controllers\Api')
                 ->group(base_path('routes/api.php'));
 
             Route::middleware('web')

+ 74 - 0
app/Services/Api/Crop/Crop104Service.php

@@ -0,0 +1,74 @@
+<?php
+
+
+namespace App\Services\Api\Crop;
+
+
+class Crop104Service implements CropService
+{
+    private $apiUrl = 'https://www.104.com.tw/company/ajax';
+    public function search($name)
+    {
+        $urlName = urlencode($name);
+        $searchResult = \Curl::to("{$this->apiUrl}/list?keyword=$urlName")
+            ->withHeader('Referer:https://www.104.com.tw')
+            ->get();
+        $searchResultArray = json_decode($searchResult, true);
+        $data = $searchResultArray['data'];
+        $collect = collect($data);
+        $filteredCollect = $collect->where('name', $name);
+        if ($filteredCollect->count() === 1) {
+            $hit = $filteredCollect->first();
+            $hit['jobs'] = $this->jobList($hit['encodedCustNo']);
+            return $hit;
+        }
+        return $collect;
+    }
+    public function jobList($encodedCustNo)
+    {
+        $listResult = \Curl::to("{$this->apiUrl}/joblist/$encodedCustNo?page=1&pageSize=100")
+            ->withHeader('Referer:https://www.104.com.tw')
+            ->get();
+        $listResultArray = json_decode($listResult, true);
+        $totalPages = $listResultArray['data']['totalPages'];
+        $result = [];
+        $result[0] = \Arr::get($listResultArray, 'data.list.topJobs');
+        $result[1] = \Arr::get($listResultArray, 'data.list.normalJobs');
+        if ($totalPages > 1) {
+            $result = array_merge($result, $this->getJobPages("{$this->apiUrl}/joblist/$encodedCustNo?pageSize=100&page=", $totalPages));
+        }
+        $result = array_merge(...$result);
+        $result = array_combine(\Arr::pluck($result, 'encodedJobNo'), $result);
+        return $result;
+    }
+    public function getJobPages($baseUrl, $end, $start = 2)
+    {
+        $mh = curl_multi_init();
+        $curls = [];
+        $result = [];
+        foreach (range($start, $end) as $page) {
+            $headers = [
+                'Referer:https://www.104.com.tw',
+            ];
+            $apiUrl = "$baseUrl$page";
+            $handle = curl_init($apiUrl);
+            curl_setopt($handle, CURLOPT_HTTPHEADER, $headers);
+            curl_setopt($handle, CURLOPT_RETURNTRANSFER, true);
+            curl_multi_add_handle($mh, $handle);
+            $curls[$page] = $handle;
+        }
+        $running=null;
+        do {
+            curl_multi_exec($mh,$running);
+        } while ($running > 0);
+        foreach($curls as $page => $curl)
+        {
+            $content = curl_multi_getcontent($curl);
+            $contentArray = json_decode($content, true);
+            $result[$page] = \Arr::get($contentArray, 'data.list.normalJobs');
+            curl_multi_remove_handle($mh, $curl);
+        }
+        curl_multi_close($mh);
+        return $result;
+    }
+}

+ 111 - 0
app/Services/Api/Crop/Crop1111Service.php

@@ -0,0 +1,111 @@
+<?php
+
+
+namespace App\Services\Api\Crop;
+
+
+class Crop1111Service implements CropService
+{
+    private $apiUrl = 'https://www.1111.com.tw/';
+    private $cropReg = '/1111\.com\.tw\/corp\/(\d+)\/" title="([\n\S\s]+?)".+card-title.+?>(.+)<\/h.+job_item_detail_location.+?>(.+?)<\/div(.+?corp_about_info.+?>(.+?)<\/div)?(.+?corp_about_info.+?>(.+?)<\/div)?(.+?corp_about_info.+?>(.+?)<\/div)?.+card-text job_item_description.+?>([\S\s\n]+?)<\/p(.+(<ul.+?>(.+)<\/ul))?/';
+    private $jobReg = '/job\/(\d+)[\S\s]+?card-title.+?>([\S\s]+?)<\/h[\S\s]+?job_item_detail_location.+?>(.+?)<\/[\S\s]+?job_item_detail_salary.+?>(.+?)<\/[\S\s]+?applicants_data.+?>(.+?)<\/[\S\s]+?job_item_data.+([\S\s\n]+?)<\/ul[\S\s]+?job_item_description.+([\S\s\n]+?)<\/p[\S\s]+?job_item_date">([\S\s\n]+?)<\/small/';
+    public function search($name)
+    {
+        $urlName = urlencode($name);
+        $searchResult = \Curl::to("{$this->apiUrl}search/corp?fs=0&ks=$urlName&page=1&act=load_page")
+            ->get();
+        $searchResultArray = json_decode($searchResult, true);
+        preg_match_all($this->cropReg, $searchResultArray['html1_d'], $matches);
+        $result = [];
+        foreach ($matches[0] as $index => $match) {
+            preg_match_all('/<\/a>(.+?)<li>/', $matches[14][$index], $tags);
+            $result[] = [
+                'encodedCustNo' => $matches[1][$index],
+                'title' => $matches[2][$index],
+                'name' => str_replace(['</em>', '<em>'], '', $matches[3][$index]),
+                'areaDesc' => $matches[4][$index],
+                'about_info' => array_filter([$matches[6][$index], $matches[8][$index], $matches[10][$index]]),
+                'profile' => $matches[11][$index],
+                'tags' => $tags[1],
+            ];
+        }
+        $collect = collect($result);
+        $filteredCollect = $collect->where('name', $name);
+        if ($filteredCollect->count() === 1) {
+            $hit = $filteredCollect->first();
+            $hit['jobs'] = $this->jobList($filteredCollect->first()['encodedCustNo']);
+            return $hit;
+        }
+        return $collect;
+    }
+    public function jobList($encodedCustNo)
+    {
+        $response = \Curl::to("{$this->apiUrl}/Corp/SearchByJobAjax")
+            ->withData([
+                'organNo' => $encodedCustNo,
+                'pageIndex' => 1,
+            ])
+            ->post();
+        preg_match('/<u>1<\/u> \/ ([\d]+)/', $response, $pages);
+        $totalPages = $pages[1];
+        $result = [];
+        $result[1] = $this->formatJob($response);
+        if ($totalPages > 1) {
+            $result = array_merge($result, $this->getJobPages($encodedCustNo, $totalPages));
+        }
+        $result = array_merge(...$result);
+        return $result;
+    }
+    public function getJobPages($encodedCustNo, $end, $start = 2)
+    {
+        $mh = curl_multi_init();
+        $curls = [];
+        $result = [];
+        foreach (range($start, $end) as $page) {
+            $data = [
+                'organNo' => $encodedCustNo,
+                'pageIndex' => $page,
+            ];
+            $handle = curl_init("{$this->apiUrl}/Corp/SearchByJobAjax");
+            curl_setopt($handle, CURLOPT_RETURNTRANSFER, true);
+            curl_setopt($handle, CURLOPT_POST, true);
+            curl_setopt($handle, CURLOPT_POSTFIELDS, $data);
+            curl_multi_add_handle($mh, $handle);
+            $curls[$page] = $handle;
+        }
+        $running=null;
+        do {
+            curl_multi_exec($mh,$running);
+        } while ($running > 0);
+        foreach($curls as $page => $curl)
+        {
+            $content = curl_multi_getcontent($curl);
+            $result[$page] =  $this->formatJob($content);
+            curl_multi_remove_handle($mh, $curl);
+        }
+        curl_multi_close($mh);
+        return $result;
+    }
+    private function formatJob($html)
+    {
+        preg_match_all($this->jobReg, $html, $matches);
+        $result = [];
+        foreach ($matches[0] as $index => $match) {
+            preg_match_all('/<li>(.+?)<\/li>/', $matches[6][$index], $tags);
+
+            $result[$matches[1][$index]] = [
+                'jobNo' => $matches[1][$index],
+                'jobName' => trim($matches[2][$index]),
+                'jobUrl' => "//www.1111.com.tw/job/{$matches[1][$index]}",
+                'jobAddrNoDesc' => $matches[3][$index],
+                'jobSalary' => $matches[4][$index],
+                'jobAccepted' => $matches[5][$index],
+                'appearDate' => $matches[8][$index],
+                'jobDescription' => trim($matches[7][$index]),
+                'tags' => $tags[1],
+            ];
+        }
+
+        return $result;
+    }
+}

+ 15 - 0
app/Services/Api/Crop/CropService.php

@@ -0,0 +1,15 @@
+<?php
+
+
+namespace App\Services\Api\Crop;
+
+
+interface CropService
+{
+    public function search($name);
+
+    public function jobList($encodedCustNo);
+
+    public function getJobPages($encodedCustNo, $end, $start = 2);
+
+}

+ 5 - 0
routes/api.php

@@ -17,3 +17,8 @@ use Illuminate\Support\Facades\Route;
 Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
     return $request->user();
 });
+Route::group(['namespace' => 'Crop'], function()
+{
+    Route::get('crop/{crop}/{name}', 'CropController@search')->where('crop', '104|1111');
+    Route::get('crop/{crop}/{encodedCustNo}/jobs', 'CropController@getJobs')->where('crop', '104|1111');
+});