使用PHP file_get_contents调用Yahoo Finance API遭429错误求助
遇到这种file_get_contents报429但curl正常的情况,大概率是请求头或会话追踪的差异导致的,以下是几个可行的排查和解决方向:
统一请求头(重点排查User-Agent)
Yahoo的API可能会根据请求的User-Agent识别请求来源,file_get_contents默认的UA是类似PHP/7.4.x的标识,容易被归类到非浏览器请求池里,哪怕总请求量没到上限,也可能触发限制。而curl默认的UA更接近浏览器,所以能正常请求。
解决办法是给file_get_contents添加自定义User-Agent,模拟浏览器请求:$opts = [ 'http' => [ 'header' => 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36' ] ]; $context = stream_context_create($opts); $data = file_get_contents('https://query1.finance.yahoo.com/v8/finance/chart/Ticker', false, $context);携带会话Cookie
curl会自动保存和发送Cookie,而file_get_contents默认不会。Yahoo可能通过Cookie追踪单个会话的请求次数,哪怕IP相同,无Cookie的请求可能被视为新会话,触发错误。可以先在curl里抓下响应的Cookie,然后在file_get_contents里带上:$opts = [ 'http' => [ 'header' => "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36\r\nCookie: YOUR_CURL_COOKIE_HERE" ] ]; $context = stream_context_create($opts); $data = file_get_contents('https://query1.finance.yahoo.com/v8/finance/chart/Ticker', false, $context);或者配置stream上下文让file_get_contents自动处理Cookie(需要设置
cookie_file和cookie_jar)。直接替换为PHP cURL实现
既然命令行curl能正常工作,直接在PHP里用cURL函数替代file_get_contents是最稳妥的方案,能更好地控制请求参数:$ch = curl_init('https://query1.finance.yahoo.com/v8/finance/chart/Ticker'); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36'); // 可选:如果需要处理Cookie // curl_setopt($ch, CURLOPT_COOKIEJAR, '/tmp/yahoo_cookie.txt'); // curl_setopt($ch, CURLOPT_COOKIEFILE, '/tmp/yahoo_cookie.txt'); $response = curl_exec($ch); curl_close($ch);排查请求频率的计算逻辑
有时候API的限制不是单纯按IP统计,可能结合了UA、会话ID等维度。哪怕总请求量只有40次,不同UA的请求可能被分开计数,导致某个UA维度下触发了限制。统一UA后可以解决这类问题。
内容的提问来源于stack exchange,提问作者Jay

