setName('crawler')
->addArgument('action', Argument::REQUIRED, '执行动作: standings/schedule/all/menu')
->setDescription('懂球帝数据爬虫');
}
protected function execute(Input $input, Output $output)
{
$action = $input->getArgument('action');
$allowed = [
'standings',
'schedule',
'all',
'menu',
'news',
'league_news',
'article_content',
'live',
'lottery',
'lottery_draw',
'lottery_draw_force',
'match_data',
'init-db',
'test',
'csl_match',
'nba_match',
'cba_match',
'epl_match',
'bundesliga_match',
'laliga_match',
'seriea_match',
'ligue1_match',
'ucl_match',
'uel_match',
'tennis_match',
'esports_match',
'sports_match',
'truth_social',
'crypto_news',
'lottery_news',
'taiwan_lottery_news',
'hkjc_lottery_news',
'lottery_community',
'nba_news',
'cba_news',
'article_content_fetch',
'fifa_worldcup_news',
'dqd_worldcup',
'match_finish',
'live_detail',
];
if (!in_array($action, $allowed)) {
$output->writeln("不支持的动作: {$action}, 可选: " . implode('/', $allowed) . "");
return;
}
// 文件锁防止同一动作并发执行
$lockFile = runtime_path() . "crawler_{$action}.lock";
$fp = fopen($lockFile, 'w');
if (!flock($fp, LOCK_EX | LOCK_NB)) {
$output->writeln("[Crawler] {$action} 正在执行中,跳过本次");
fclose($fp);
return;
}
try {
$crawlerDir = app()->getRootPath() . 'public/dongqiudi-crawler';
$venvPython = $crawlerDir . '/venv/bin/python3';
$python = file_exists($venvPython) ? $venvPython : 'python3';
$cmd = "cd {$crawlerDir} && {$python} main.py {$action} 2>&1";
$output->writeln("[Crawler] 执行: {$cmd}");
$result = shell_exec($cmd);
$output->writeln($result ?: '(无输出)');
} finally {
flock($fp, LOCK_UN);
fclose($fp);
@unlink($lockFile);
}
}
}