关键词抓取
This commit is contained in:
@@ -187,6 +187,27 @@ class UsedCarController extends BaseController
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 关键词搜索懂车帝车型数据
|
||||
*/
|
||||
public function crawlKeyword(Request $request): Response
|
||||
{
|
||||
$this->requireAuth($request);
|
||||
$keyword = $request->post('keyword') ?: $request->get('keyword');
|
||||
|
||||
if (empty($keyword)) {
|
||||
return $this->error('关键词不能为空');
|
||||
}
|
||||
|
||||
try {
|
||||
$crawlService = new \app\Service\UsedCarCrawlService();
|
||||
$data = $crawlService->searchByKeyword($keyword);
|
||||
return $this->success($data);
|
||||
} catch (\Exception $e) {
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成PDF
|
||||
*/
|
||||
|
||||
@@ -521,4 +521,140 @@ class UsedCarCrawlService
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过关键词搜索懂车帝车系信息
|
||||
*
|
||||
* @param string $keyword 搜索关键词(如 "奥迪A4")
|
||||
* @return array 品牌和车系信息
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function searchByKeyword(string $keyword): array
|
||||
{
|
||||
// 访问懂车帝搜索页面获取第一个结果的链接
|
||||
$searchUrl = "https://www.dongchedi.com/search?keyword=" . urlencode($keyword);
|
||||
|
||||
try {
|
||||
$html = $this->fetchHtml($searchUrl);
|
||||
$ql = QueryList::html($html);
|
||||
|
||||
// 查找"查看全部"按钮的链接
|
||||
$href = '';
|
||||
$ql->find('a.fold-btn')->each(function ($item) use (&$href) {
|
||||
$itemHref = $item->attr('href');
|
||||
if ($itemHref) {
|
||||
$href = $itemHref;
|
||||
}
|
||||
});
|
||||
|
||||
if (empty($href)) {
|
||||
throw new \Exception('未找到相关车系,请使用更精确的关键词');
|
||||
}
|
||||
|
||||
// 提取车系ID
|
||||
$seriesId = $this->extractSeriesId($href);
|
||||
if (!$seriesId) {
|
||||
throw new \Exception('无法解析车系ID');
|
||||
}
|
||||
|
||||
// 获取品牌和车系信息
|
||||
return $this->getBrandSeries($seriesId);
|
||||
} catch (\Exception $e) {
|
||||
throw new \Exception('搜索失败: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取品牌和车系名称
|
||||
*
|
||||
* @param string $seriesId 车系ID
|
||||
* @return array 包含品牌和车系信息的数组
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function getBrandSeries(string $seriesId): array
|
||||
{
|
||||
$url = "https://www.dongchedi.com/auto/series/" . $seriesId . "?anchorId=carModels";
|
||||
|
||||
try {
|
||||
$html = $this->fetchHtml($url);
|
||||
$ql = QueryList::html($html);
|
||||
|
||||
// 从面包屑导航中提取品牌和车系
|
||||
$breadcrumbs = [];
|
||||
$ql->find('div.breadcrumb_wrap__2GLeU span')->each(function ($item) use (&$breadcrumbs) {
|
||||
$breadcrumbs[] = trim($item->text());
|
||||
});
|
||||
|
||||
$brand = $breadcrumbs[2] ?? '';
|
||||
$series = $breadcrumbs[3] ?? '';
|
||||
|
||||
// 获取车型列表
|
||||
$models = $this->getSeriesModels($seriesId);
|
||||
|
||||
return [
|
||||
'brand' => $brand,
|
||||
'series' => $series,
|
||||
'series_id' => $seriesId,
|
||||
'models' => $models,
|
||||
];
|
||||
} catch (\Exception $e) {
|
||||
throw new \Exception('获取车系信息失败: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取车系下的车型列表
|
||||
*
|
||||
* @param string $seriesId 车系ID
|
||||
* @return array 车型列表
|
||||
*/
|
||||
public function getSeriesModels(string $seriesId): array
|
||||
{
|
||||
$url = "https://www.dongchedi.com/auto/series/" . $seriesId . "?anchorId=carModels";
|
||||
$models = [];
|
||||
|
||||
try {
|
||||
$html = $this->fetchHtml($url);
|
||||
$ql = QueryList::html($html);
|
||||
|
||||
// 解析车型列表
|
||||
$ql->find('div.carModelsPager__EiwGC a.model-item__1r8j')->each(function ($item) use (&$models) {
|
||||
$modelName = trim($item->text());
|
||||
$modelUrl = $item->attr('href');
|
||||
|
||||
if ($modelName) {
|
||||
$models[] = [
|
||||
'name' => $modelName,
|
||||
'url' => $modelUrl ? 'https://www.dongchedi.com' . $modelUrl : '',
|
||||
];
|
||||
}
|
||||
});
|
||||
|
||||
return $models;
|
||||
} catch (\Exception) {
|
||||
// 车型解析失败,返回空数组
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从懂车帝URL中提取车系ID
|
||||
*
|
||||
* @param string $url 懂车帝URL
|
||||
* @return string|null 车系ID
|
||||
*/
|
||||
private function extractSeriesId(string $url): ?string
|
||||
{
|
||||
// 匹配 /auto/series/x123/ 格式
|
||||
if (preg_match('/\/auto\/series\/(\d+)/', $url, $matches)) {
|
||||
return $matches[1];
|
||||
}
|
||||
|
||||
// 匹配 /auto/series/x123/params/ 格式
|
||||
if (preg_match('/\/auto\/series\/(\d+)/', $url, $matches)) {
|
||||
return $matches[1];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,6 +72,7 @@ Route::group('/api/v1/usedcar', function () {
|
||||
Route::post('/status', [app\controller\UsedCarController::class, 'updateStatus']);
|
||||
Route::post('/crawl/url', [app\controller\UsedCarController::class, 'crawlByUrl']);
|
||||
Route::post('/crawl/mobile', [app\controller\UsedCarController::class, 'crawlMobileUrl']);
|
||||
Route::post('/crawl/keyword', [app\controller\UsedCarController::class, 'crawlKeyword']);
|
||||
Route::post('/pdf/generate', [app\controller\UsedCarController::class, 'generatePdf']);
|
||||
Route::get('/pdf/download', [app\controller\UsedCarController::class, 'downloadPdf']);
|
||||
Route::get('/pdf/url', [app\controller\UsedCarController::class, 'getPdfUrl']);
|
||||
|
||||
Reference in New Issue
Block a user