185 lines
		
	
	
		
			7.9 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			185 lines
		
	
	
		
			7.9 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?php
 | ||
| 
 | ||
| namespace app\event;
 | ||
| 
 | ||
| use app\model\TiktokAdsDetail;
 | ||
| use GuzzleHttp\Client;
 | ||
| use GuzzleHttp\Exception\GuzzleException;
 | ||
| use support\Db;
 | ||
| use QL\QueryList;
 | ||
| use support\Redis;
 | ||
| 
 | ||
| 
 | ||
| class TiktokAdsDetails
 | ||
| {
 | ||
| 
 | ||
|     const  userAgent = 'user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36';
 | ||
| 
 | ||
|     const url = 'https://library.tiktok.com/api/v1/items';
 | ||
| 
 | ||
|     const type = 'tiktokadsdetails';
 | ||
| 
 | ||
| 
 | ||
| //    const countries = ["AT", "BE", "BG", "HR", "CY", "CZ", "DK", "EE", "FI", "FR", "DE", "GR", "HU", "IS", "IE","IT", "LV", "LI", "LT", "LU", "MT", "NL", "NO", "PL", "PT", "RO", "SK", "SI", "ES", "SE", "CH", "TR", "GB"] ;
 | ||
| //    const countries = ["GB", "BE"];
 | ||
| 
 | ||
| 
 | ||
|     /**
 | ||
|      * 每天爬取tiktok广告详情
 | ||
|      * @return void
 | ||
|      */
 | ||
|     public function update()
 | ||
|     {
 | ||
|         try {
 | ||
| 
 | ||
|             $client = new Client([
 | ||
|                 //允许重定向
 | ||
| //                'allow_redirects' => true,
 | ||
|             ]);
 | ||
| 
 | ||
| 
 | ||
|             $adIdCache = Redis::lPop(TiktokAds::type . 'AdsIds');
 | ||
|             if (empty($adIdCache)) {
 | ||
|                 dump('获取AD id 异常:');
 | ||
|                 return;
 | ||
|             }
 | ||
| 
 | ||
|             $currentParams = ['ad_id' => $adIdCache,'action' => 'details'];
 | ||
| 
 | ||
|             $environment = 'vvv';
 | ||
|             $proxyIp = '103.122.176.175';
 | ||
|             $proxyPort = '31186';
 | ||
|             $proxyUser = 'B978321E';
 | ||
|             $proxyPassword = '1EC4E3C7398F';
 | ||
| 
 | ||
|             $proxyAuth = base64_encode($proxyUser . ":" . $proxyPassword);
 | ||
|             $options = [
 | ||
|                 "headers" => [
 | ||
|                     'accept' => 'application/json, text/plain, */*',
 | ||
|                     'accept-language' => 'zh-CN,zh;q=0.9',
 | ||
|                     'content-type' => 'application/json',
 | ||
|                     'cookie' => 'cookie: _ttp=2ov8Fc4C2CaNscHJd90O9fMhlpE; _ga=GA1.1.1025820618.1731926196; FPID=FPID2.2.Bcgkp%2Fk%2Bbn5w5YeSMR9wd9VpNHJwTUpkkaEqSdCEa0w%3D.1731926196; FPAU=1.2.944915349.1731926193; FPLC=CfAlWGYPInwi1oHk0kTm68d0p21YS3UZ31sOR60H2uVC7A20NL46YHkF9z36OOlKC9XHODO2%2Biet2kk486i6SmO0TcqGntq1CbgwSqOH6f4ZES7jiHeI0mu82CKUVg%3D%3D',
 | ||
|                     'origin' => 'https://library.tiktok.com',
 | ||
|                     'priority' => 'u=1, i',
 | ||
|                     'referer' => 'https://library.tiktok.com/ads?region=AT&start_time=1731945600000&end_time=1732032000000&adv_name=&adv_biz_ids=&query_type=&sort_type=last_shown_date,desc',
 | ||
|                     'sec-ch-ua' => '"Google Chrome";v="131", "Chromium";v="131", "Not_A Brand";v="24"',
 | ||
|                     'sec-ch-ua-mobile' => '?0',
 | ||
|                     'sec-ch-ua-platform' => '"Windows"',
 | ||
|                     'sec-fetch-dest' => 'empty',
 | ||
|                     'sec-fetch-mode' => 'cors',
 | ||
|                     'sec-fetch-site' => 'same-origin',
 | ||
|                     'user-agent' => self::userAgent,
 | ||
|                 ],
 | ||
|             ];
 | ||
|             if($environment !== 'env') {
 | ||
|                 $options["headers"]["Proxy-Authorization"] = "Basic " . $proxyAuth;
 | ||
|                 $options["proxy"] = $proxyIp . ':' . $proxyPort;
 | ||
|             }
 | ||
| 
 | ||
|             $res = json_decode($client->request('Get', self::url.'/'.$currentParams['ad_id'].'/'.$currentParams['action'], $options)->getBody()->getContents(), true);
 | ||
| //            dump($res);return;  //调试点
 | ||
| 
 | ||
| 
 | ||
|             if (empty($res['data']) || $res['code'] != 0) {
 | ||
|                 dump('更新tiktok Ads Details接口响应异常:' . json_encode($res, JSON_UNESCAPED_UNICODE));
 | ||
|                 return;
 | ||
|             }
 | ||
| 
 | ||
|                 $ad =  $res['data'];
 | ||
|                 if( $ad['ad']['audit_status'] == 2 || empty( $ad['ad']['videos'])){
 | ||
|                     return; //审核不过或者没视频不采集
 | ||
|                 }
 | ||
|                 $imagesJson = is_array($ad['ad']['image_urls']) ? json_encode($ad['ad']['image_urls']):json_encode([]);
 | ||
|                 $targetingLocationJson = is_array($ad['targeting']['location']) ? json_encode($ad['targeting']['location']):json_encode([]);
 | ||
|                 $targetingAgeJson = is_array($ad['targeting']['age']) ? json_encode($ad['targeting']['age']):json_encode([]);
 | ||
|                 $targetingGenderJson = is_array($ad['targeting']['gender']) ? json_encode($ad['targeting']['gender']):json_encode([]);
 | ||
| 
 | ||
| //                dump($rejection_info);
 | ||
|                 $insertData[$ad['ad']['id']] = [
 | ||
|                     'ad_id' => $ad['ad']['id'],
 | ||
|                     'ad_name' =>  $ad['ad']['name'],
 | ||
|                     'audit_status' =>  $ad['ad']['audit_status'],
 | ||
|                     'ad_type' =>  $ad['ad']['type'],
 | ||
|                     'first_shown_date' =>  $ad['ad']['first_shown_date'],
 | ||
|                     'last_shown_date' =>  $ad['ad']['last_shown_date'],
 | ||
| 
 | ||
|                     'estimated_audience' => $ad['ad']['estimated_audience'],
 | ||
|                     'spent' => $ad['ad']['spent'],
 | ||
|                     'impression' => $ad['ad']['impression'],
 | ||
|                     'show_mode' => $ad['ad']['show_mode'],
 | ||
|                     'sor_audit_status' => $ad['ad']['sor_audit_status'],
 | ||
|                     'image_urls' => $imagesJson,
 | ||
| 
 | ||
|                     'advertiser_name' => $ad['advertiser']['name'],
 | ||
|                     'adv_biz_ids' =>  $ad['advertiser']['adv_biz_ids'],
 | ||
|                     'registry_location' =>  $ad['advertiser']['registry_location'],
 | ||
|                     'sponsor' =>  $ad['advertiser']['sponsor'],
 | ||
| 
 | ||
|                     'targeting_location' =>  $targetingLocationJson,
 | ||
|                     'targeting_age' =>  $targetingAgeJson,
 | ||
|                     'targeting_gender' =>  $targetingGenderJson,
 | ||
|                     'target_audience_size' => $ad['targeting']['target_audience_size'],
 | ||
|                     'audience_type' => $ad['targeting']['audience'],
 | ||
|                     'interest' => $ad['targeting']['interest'],
 | ||
|                     'video_interactions' => $ad['targeting']['video_interactions'],
 | ||
|                     'creator_interactions' => $ad['targeting']['creator_interactions'],
 | ||
| 
 | ||
|                 ];
 | ||
|                 if(isset($ad['ad']['videos']) && !empty($ad['ad']['videos'])) {
 | ||
|                     // 遍历 "videos" 数组
 | ||
|                     foreach ($ad['ad']['videos'] as $video) {
 | ||
|                         $insertData[$ad['ad']['id']]['video_url'] = $video['video_url'];
 | ||
|                         $insertData[$ad['ad']['id']]['cover_img'] = $video['cover_img'];
 | ||
|                     }
 | ||
|                 }
 | ||
| 
 | ||
| 
 | ||
| //            dump($insertData);return;
 | ||
| 
 | ||
|             if (empty($insertData)) return;
 | ||
| 
 | ||
|             //开启事务
 | ||
|             Db::beginTransaction();
 | ||
| 
 | ||
| 
 | ||
|             //删除原来的旧数据
 | ||
|             TiktokAdsDetail::query()->where('ad_id', $currentParams['ad_id'])->delete();
 | ||
|             //添加新的数据
 | ||
|             TiktokAdsDetail::query()->insert($insertData);
 | ||
| 
 | ||
|             //redis缓存
 | ||
|             Redis::set(self::type, json_encode($insertData, JSON_UNESCAPED_UNICODE));
 | ||
| 
 | ||
|             //redis缓存 记录更新时间
 | ||
|             $time = date('Y-m-d H:i:s');
 | ||
|             Redis::set(self::type . 'time', $time);
 | ||
| 
 | ||
| 
 | ||
|             //提交事务
 | ||
|             Db::commit();
 | ||
|             //销毁$res
 | ||
|             unset($res);
 | ||
| 
 | ||
|             dump(date('Y-m-d H:i:s') . '更新' . self::type . '成功');
 | ||
|         } catch (GuzzleException|\Exception $exception) {
 | ||
|             //回滚事务
 | ||
|             Db::rollBack();
 | ||
|             dump('更' . self::type . '的广告ID为 '.$currentParams['ad_id'].' 异常:' . $exception->getMessage());
 | ||
|             dump($exception);
 | ||
|         }
 | ||
| //        } catch (ClientExceptionInterface $e) {
 | ||
| //            // 捕获 4xx 错误
 | ||
| //            dump( 'Client error: ' . $e->getMessage() . "\n");
 | ||
| //        } catch (ServerExceptionInterface $e) {
 | ||
| //            // 捕获 5xx 错误
 | ||
| //            dump('Server error: ' . $e->getMessage() . "\n");
 | ||
| //        } catch (TransportExceptionInterface $e) {
 | ||
| //            // 捕获网络传输错误
 | ||
| //            dump('Transport error: ' . $e->getMessage() . "\n") ;
 | ||
| //        } catch (\Exception $e) {
 | ||
| //            // 捕获所有其他错误
 | ||
| //            dump('General error: ' . $e->getMessage() . "\n") ;
 | ||
| //        }
 | ||
|     }
 | ||
| }
 |