Yahoo Finance является одним из наиболее широко используемых публичных источников рыночных данных. На каждой странице котировок отображаются одни и те же ключевые числа, за которыми трейдер следит весь день: текущая цена тикера, абсолютное изменение относительно предыдущего закрытия и изменение в процентах. Для тех, кто отслеживает список наблюдения или записывает цены по итогам дня, ручное копирование этих данных для более чем одного-двух символов быстро надоедает.
Это краткое дополнение к более широкому руководству по скрапингу Yahoo Finance. Здесь вы создаёте один небольшой запускаемый скрипт на Python, который принимает тикер и возвращает его текущую цену, изменение и процентное изменение, ограничиваясь публичными рыночными данными, видимыми любому пользователю без аккаунта. Для полного руководства по многим полям читайте смежную статью; эта является быстрым скриптом получения цены.
Что вы создадите
Одна функция на Python, которую вы вызываете с тикером. Она загружает отрендеренную страницу котировки Yahoo Finance через Crawling API, парсит три поля и возвращает их в виде небольшого словаря. В качестве рабочего примера используется Apple (AAPL):
- Price текущая котировочная цена символа.
- Change абсолютное изменение цены относительно предыдущего закрытия.
- Change percent то же изменение, выраженное в процентах.
Почему обычный запрос не работает на Yahoo Finance
Направьте обычный HTTP-клиент на URL котировки Yahoo Finance, и вы обычно получите статус 200 со страницей, не содержащей нужных вам живых чисел. Два фактора работают против вас. Во-первых, страница котировок рендерит блок цены в браузере через JavaScript, и значение обновляется в реальном времени, поэтому исходный HTML является оболочкой, которая заполняется только после выполнения скриптов страницы. При парсинге этого первого ответа поле цены возвращается пустым. Во-вторых, финансовые сайты следят за автоматизированным трафиком: IP-адреса датацентров и паттерны запросов, не похожие на настоящий браузер, ограничиваются по скорости или блокируются до того, как возвращают отрендеренный контент.
Поэтому работающий получатель цен требует двух вещей в одном запросе: браузера, рендерящего блок котировки, и IP-адреса, который сайт воспринимает как реального посетителя. Это можно реализовать с помощью headless-браузера и ротирующих резидентских прокси, но поддержание этого стека в рабочем состоянии составляет большую часть усилий. Crawling API объединяет оба компонента в один вызов: передайте ему URL с JavaScript-токеном, он рендерит страницу за доверенным IP и возвращает готовый HTML для парсинга.
Crawlbase предлагает два типа токенов. Обычный токен получает статичный HTML; JavaScript (JS) токен сначала рендерит страницу в реальном браузере. Yahoo Finance заполняет блок цен на стороне клиента, поэтому здесь нужен JS-токен. Обычный токен возвращает ту же оболочку, что и обычный запрос, без живых цифр.
Предварительные требования
Прежде чем писать код, нужно подготовить три вещи.
Базовые знания Python. Вы должны уметь запускать скрипт и устанавливать пакеты с помощью pip. Если вы только знакомитесь с парсингом, руководство по BeautifulSoup хорошо дополняет этот материал.
Python 3.8 или новее. Проверьте версию командой python --version. Если Python не установлен, скачайте его с python.org и убедитесь, что он добавлен в PATH.
Аккаунт Crawlbase и JS-токен. Зарегистрируйтесь, откройте панель управления и скопируйте JavaScript (JS) токен со страницы документации аккаунта. Crawlbase предоставляет до 20 000 бесплатных запросов на старт, чего более чем достаточно для этого скрипта. Относитесь к токену как к паролю и не храните его в системе контроля версий.
Настройка проекта
Создайте виртуальное окружение, чтобы зависимости проекта оставались изолированными, затем установите две библиотеки, необходимые скрипту.
python --version python -m venv yahoo_env source yahoo_env/bin/activate pip install crawlbase beautifulsoup4
В Windows активируйте окружение командой yahoo_env\Scripts\activate вместо строки с source. Две зависимости выполняют основную работу: crawlbase является официальным клиентом для Crawling API, а beautifulsoup4 парсит возвращаемый HTML, позволяя извлекать поля по атрибуту. Модуль json входит в стандартную библиотеку.
Шаг 1: Получение отрендеренной страницы котировки
Начните с получения готовой страницы. Импортируйте класс CrawlingAPI, инициализируйте его с вашим JS-токеном и запросите URL котировки. Страница котировки формируется из тикера, поэтому шаблон URL: https://finance.yahoo.com/quote/<SYMBOL>. Передайте параметры ajax_wait и page_wait, чтобы блок цены загрузился до захвата страницы, и проверяйте cb_status (legacy pc_status) от Crawlbase перед парсингом, чтобы ошибки сразу становились заметными.
from crawlbase import CrawlingAPI api = CrawlingAPI({"token": "YOUR_CRAWLBASE_TOKEN"}) OPTIONS = { "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/122.0", "ajax_wait": "true", "page_wait": 4000, } def crawl(symbol): quote_url = f"https://finance.yahoo.com/quote/{symbol}" response = api.get(quote_url, OPTIONS) if response["headers"]["cb_status"] == "200": return response["body"].decode("utf-8") print(f"Request failed: {response['headers']['cb_status']}") return None if __name__ == "__main__": html = crawl("AAPL") print(html[:500] if html else "No HTML returned")
Параметры ожидания важны для клиентски-рендеримого источника. ajax_wait дожидается загрузки асинхронного контента, а page_wait задерживает выполнение на фиксированное количество миллисекунд после загрузки, чтобы блок цены был заполнен до захвата. Четырёх секунд достаточно для начала; увеличьте значение, если цена возвращается пустой. Запустите скрипт командой python yahoo_price.py, и вы должны увидеть реальную разметку Yahoo Finance, а не оболочку, которую возвращает обычный запрос, что подтверждает работу рендеринга прежде, чем вы напишете хоть один селектор.
Страница котировок требует отрендеренного блока цены за доверенным IP в одном вызове, именно это и настраивают параметры ajax_wait и page_wait, описанные выше. Crawling API принимает JS-токен, запускает страницу в реальном браузере, ротирует резидентские IP на стороне сервера и возвращает готовый HTML, избавляя вас от необходимости управлять headless-флотом и пулом прокси самостоятельно. Начните с публичной страницы котировки на бесплатном уровне.
Шаг 2: Парсинг цены, изменения и процентного изменения
Yahoo Finance помечает свои ключевые числа котировки стабильными атрибутами data-field в блоке цены, что делает их надёжными целями: цена находится в regularMarketPrice, абсолютное изменение в regularMarketChange, а процентное изменение в regularMarketChangePercent. Загрузите отрендеренный HTML в BeautifulSoup и считайте каждое значение. Каждый запрос защищён, чтобы отсутствующее поле возвращало None, а не вызывало ошибку скрипта.
from bs4 import BeautifulSoup def field(soup, name): el = soup.select_one(f'[data-field="{name}"]') return el.get_text(strip=True) if el else None def parse_quote(html, symbol): soup = BeautifulSoup(html, "html.parser") return { "symbol": symbol, "price": field(soup, "regularMarketPrice"), "change": field(soup, "regularMarketChange"), "change_percent": field(soup, "regularMarketChangePercent"), }
Вспомогательная функция field запрашивает один элемент по его атрибуту data-field и возвращает очищенный текст или None, если элемент отсутствует, поэтому символ, страница которого не содержит какого-либо значения, не прерывает выполнение. parse_quote объединяет три числа плюс тикер в словарь. Чтение полей, помеченных атрибутами, надёжнее, чем полагаться на сгенерированные CSS-классы Yahoo.
Разметка и имена классов Yahoo Finance меняются со временем, и атрибуты data-field тоже могут переезжать. Воспринимайте приведённые здесь селекторы как отправную точку, а не как контракт. Если поле возвращает None, откройте живую страницу котировки в инструментах разработчика браузера, найдите элемент с нужным числом и обновите селектор.
Шаг 3: Сборка полного скрипта
Теперь объедините оба фрагмента в один запускаемый скрипт. Он загружает отрендеренную страницу котировки, парсит три поля, выводит их и записывает результат в JSON-файл для удобной передачи дальше по цепочке.
import json from crawlbase import CrawlingAPI from bs4 import BeautifulSoup api = CrawlingAPI({"token": "YOUR_CRAWLBASE_TOKEN"}) OPTIONS = { "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/122.0", "ajax_wait": "true", "page_wait": 4000, } def crawl(symbol): quote_url = f"https://finance.yahoo.com/quote/{symbol}" response = api.get(quote_url, OPTIONS) if response["headers"]["cb_status"] == "200": return response["body"].decode("utf-8") print(f"Request failed: {response['headers']['cb_status']}") return None def field(soup, name): el = soup.select_one(f'[data-field="{name}"]') return el.get_text(strip=True) if el else None def parse_quote(html, symbol): soup = BeautifulSoup(html, "html.parser") return { "symbol": symbol, "price": field(soup, "regularMarketPrice"), "change": field(soup, "regularMarketChange"), "change_percent": field(soup, "regularMarketChangePercent"), } def get_stock_price(symbol): html = crawl(symbol) if not html: return None return parse_quote(html, symbol) def main(): quote = get_stock_price("AAPL") if not quote: print("Could not fetch quote") return print(json.dumps(quote, indent=2)) with open("quote.json", "w") as f: json.dump(quote, f, indent=2) if __name__ == "__main__": main()
Функция get_stock_price является той, которую вы вызываете: передайте ей тикер, и она вернёт словарь или None при сбое запроса. main запускает её для AAPL, выводит результат и сохраняет его в файл quote.json.
Как выглядит результат
Запустите скрипт и получите чистую структурированную запись, готовую для списка наблюдения, блокнота или базы данных. Числа ниже являются условными; ваш прогон вернёт живые значения.
{ "symbol": "AAPL", "price": "212.44", "change": "+1.86", "change_percent": "(+0.88%)" }
Отсюда следующие шаги незначительны: пройдитесь по списку наблюдения, запишите записи в CSV или запланируйте скрипт на ежедневное добавление строки по каждому символу в момент закрытия. Для более полного руководства по многим полям, включая исторические данные, см. руководство по скрапингу Yahoo Finance, а для подхода с рендерингом и доверенным IP на других JavaScript-тяжёлых целях см. скрапинг JavaScript-страниц с помощью Python.
Сохранение работоспособности
Даже при отлаженном рендеринге финансовый сайт следит за трафиком, похожим на действия скрапера. Три привычки помогают поддерживать более длинный прогон по списку наблюдения в рабочем состоянии: задавайте темп запросов с короткой паузой между символами, чтобы плотный цикл не вызвал ограничения скорости; полагайтесь на ротацию, поскольку пул резидентских IP распределяет запросы по многим адресам, чтобы ни один не превысил лимит (Crawling API делает это за вас); следите за кодами статусов, воспринимая прогон, в котором начинают появляться значения cb_status, отличные от 200, как сигнал для снижения активности. Общую стратегию см. в руководстве по скрапингу сайтов без блокировок.
Законно ли скрапить Yahoo Finance?
Допустимость скрапинга Yahoo Finance зависит от условий использования Yahoo, вашей юрисдикции и того, что вы делаете с данными. Условия Yahoo ограничивают автоматизированный доступ и массовый сбор данных, поэтому скрапер может им противоречить вне зависимости от тщательности вашего инструментария. Ознакомьтесь с Условиями использования Yahoo и файлом robots.txt сайта, соблюдайте любые ограничения по частоте и считайте оба документа границей дозволенного. Ограничивайтесь публичными рыночными данными: котировки, цены, дневное изменение и процентное изменение являются фактическими числами, доступными любому пользователю без аккаунта, что и составляет область применения этого скрипта. Не извлекайте ничего, что находится за логином или платным доступом, не собирайте персональные данные аккаунтов и не перераспределяйте защищённый авторским правом редакционный контент. Где проект предполагает персональные данные, применяются правила конфиденциальности, такие как GDPR и CCPA; обычный запрос цены, подобный этому, не затрагивает их.
Для промышленного использования предпочитайте официальный поток рыночных данных скрапингу потребительского сайта. Большая часть того, что показывает Yahoo Finance, лицензирована у поставщиков рыночных данных и бирж с собственными условиями перераспределения, поэтому извлечение числа со страницы не даёт права на его перераспределение. Если вы создаёте продукт или вам нужны котировки в масштабе, лицензируйте официальный API рыночных данных: это правильный маршрут для коммерческого или массового использования, дающий данные, которые вы действительно вправе перераспределять.
Ключевые выводы
- Страница котировок рендерится на стороне клиента. Обычный запрос возвращает оболочку без живой цены, поэтому перед парсингом страницу необходимо отрендерить.
-
Нужны рендеринг и доверенный IP вместе. Crawling API с JS-токеном делает оба в одном вызове;
ajax_waitиpage_waitуправляют временем ожидания блока цены. -
Используйте стабильные атрибуты. Читайте
regularMarketPrice,regularMarketChangeиregularMarketChangePercentпо их атрибутамdata-field, а не по сгенерированным классам Yahoo. -
Держите небольшим и повторяемым. Одна функция
get_stock_price(symbol)возвращает словарь; пройдитесь по списку наблюдения и задайте темп запросов, чтобы отслеживать несколько символов. - Оставайтесь в рамках публичных рыночных данных. Соблюдайте Условия использования Yahoo и robots.txt, избегайте логинов и персональных данных, и используйте официальный API рыночных данных для промышленного или коммерческого использования.
Часто задаваемые вопросы
Почему обычный запрос возвращает страницу без живой цены?
Потому что Yahoo Finance рендерит блок котировки на стороне клиента с помощью JavaScript, и цена обновляется в реальном времени. Исходный HTML является оболочкой, заполняющейся только после выполнения скриптов страницы, поэтому обычный HTTP-запрос возвращает статус 200 с пустым полем цены. Чтобы получить число, нужно сначала отрендерить страницу, что и обеспечивает JS-токен Crawling API.
Нужен ли обычный токен или JS-токен для Yahoo Finance?
JS-токен. Обычный токен получает статичный HTML, который на странице котировки является той же оболочкой, что и при обычном запросе. JS-токен рендерит страницу в реальном браузере перед возвратом HTML, поэтому цена, изменение и процентное изменение присутствуют, когда BeautifulSoup их парсит.
Как получить цены для нескольких тикеров?
Поместите ваши символы в список и вызывайте get_stock_price для каждого, собирая возвращаемые словари. Добавьте короткую паузу time.sleep между запросами, чтобы задать темп прогона, и добавляйте каждую запись в список, который затем можно записать в JSON или CSV.
Поле цены возвращает None. Что изменилось?
Обычно одна из двух вещей. Либо страница не успела завершить рендеринг в момент захвата, поэтому увеличьте page_wait на секунду-две, либо Yahoo изменил разметку и атрибут data-field больше не соответствует. Откройте живую страницу котировки в инструментах разработчика браузера, найдите элемент с ценой и обновите селектор. Периодическое обслуживание селекторов является нормальной практикой для любого скрапера.
Можно ли получить исторические цены с помощью этого скрипта?
Этот скрипт ограничен текущей котировкой: ценой, изменением и процентным изменением. Исторические данные находятся на другом представлении Yahoo Finance с собственной разметкой, поэтому для них нужны другие селекторы. Более полное руководство по скрапингу Yahoo Finance охватывает больше полей панели котировки и является правильным местом для начала работы с дополнительными полями.
Можно ли использовать скрапленные данные Yahoo Finance в коммерческих целях?
Относитесь к этому как к правовому вопросу, а не техническому. Большая часть данных Yahoo Finance лицензирована у поставщиков рыночных данных и бирж с собственными условиями перераспределения, а Условия использования Yahoo ограничивают автоматизированное повторное использование, поэтому коммерческое или массовое использование, как правило, требует разрешения. Для продукта или масштабного использования лицензируйте официальный API рыночных данных и обратитесь за юридической консультацией, прежде чем строить бизнес на основе этих данных.
Обходите любой сайт в масштабе, без борьбы с инфраструктурой.
Crawlbase берёт на себя прокси, отпечатки и CAPTCHA, чтобы ваша команда выпускала конвейеры данных вместо поддержки обвязки краулинга. 1 000 запросов бесплатно, без карты.
