Чотири джерела з вашого завдання поводяться по-різному: одне віддає дані готовим масивом, друге — звичайним HTML, третє має 15–30 окремих сторінок на тікер, четверте ховає таблицю за скриптом. Тому «написати парсер» — це насправді чотири різні збирачі й одна спільна база. Нижче — як я їх розділяю, що робить кожен і в якому вигляді це доходить до вашого Excel.
| Джерело | Що забираємо | Як віддається насправді | Ризик блокування |
|---|---|---|---|
| Yahoo Finance history по тікеру |
дата, open, high, low, close, adj close, volume за діапазон | Сторінка малює таблицю скриптом. Стабільніше брати не HTML, а той самий запит даних, який робить сама сторінка — відповідь приходить готовим масивом рядків, без розбору вёрстки. Діапазон дат — це два параметри часу в запиті, тобто period1/period2 у вашому ж прикладі. |
середній тримає, поки темп людський |
| Finviz картка тікера |
Sector, Industry, Country | Звичайний HTML, три поля в шапці. Найлегше джерело з чотирьох, але найчутливіше до частоти: саме воно першим починає віддавати порожнечу замість даних. | високий при частих запитах |
| GuruFocus term-сторінки |
значення з H1 + блок Annual Data + блок Quarterly Data | 15–30 окремих сторінок на один тікер (zscore, roe, ebitda-margin, fcf-per-share, eps-without-nri, eps-diluted…). Структура однакова, тому один розбірник на всі — але це ×30 запитів на кожен тікер, і саме тут вирішується, живий парсер чи забанений. | високий через кількість сторінок |
| MarketWatch holdings фонду |
блок Top 10 holdings | 3–5 сторінок на тікер фонду. Таблиця тримається на своїй розмітці, змінюється рідше за решту. | середній |
Ви написали це вимогою, і це правильна вимога. Розкладаю її на те, що реально працює, бо під цією назвою часто продають одну випадкову паузу:
Головна помилка на таких проєктах — скласти все в одну широку таблицю. Через місяць у неї не можна ні дописати нову метрику, ні перерахувати історію. Розкладаю так:
tickers id, ticker, sector, industry, country, updated_at
-- довідник; sector/industry/country з джерела 2
quotes_daily ticker, date, open, high, low, close, adj_close, volume
-- джерело 1; ключ (ticker, date) -> повторний запуск не дублює
fundamentals ticker, term, period_type, period_end, value, unit, fetched_at
-- джерело 3; period_type = annual | quarterly
-- term = zscore | roe | ebitda-margin | ...
-- ключ (ticker, term, period_type, period_end)
fund_holdings fund_ticker, rank, holding_name, weight_pct, fetched_at
-- джерело 4, Top 10 holdings
fetch_log source, ticker, url, http_status, rows, started_at, finished_at, note
-- звідки видно, що саме не забралося і чому
term. Широка таблиця на 30 колонок
вимагала б переробки бази щоразу.
Power Query добре працює з MySQL/PostgreSQL на вашому хостингу, але є два місця, де такі підключення зазвичай ламаються, і їх краще закрити одразу:
v_quotes, v_fundamentals_wide, v_holdings —
і коли всередині бази щось зміниться, ваш файл не розсиплеться: представлення
лишається тим самим.Одне з представлень зручно віддати одразу «широким», щоб у Excel не робити півот руками:
v_fundamentals_wide: ticker | period_end | roe | ebitda_margin | zscore | fcf_per_share | eps_diluted AAPL | 2025-09-30 | ... | ... | ... | ... | ...
Доступ до бази ззовні відкривається не «всім», а з вашої IP-адреси або через SSH-тунель — з боку Excel це виглядає так само просто, а база не стоїть відкритою в інтернет.
| Налаштування | Де змінюється |
|---|---|
| Список тікерів | таблиця tickers — додали рядок, наступний прохід його підхопив |
| Діапазон дат (джерело 1) | конфіг: «глибина історії» при першому завантаженні + «докачувати з останньої дати» далі |
| Періодичність оновлення | окремо по кожному джерелу: котирування — щодня після закриття, фундаментал — раз на тиждень, holdings — раз на тиждень |
| Темп / поведінка | конфіг: пауза-від, пауза-до, розмір пачки, пауза між пачками, ліміт спроб |
| Набір term-сторінок | довідник у базі — додати метрику можна без правки коду |
fetch_log як попередження, дані лишаються, але ви їх бачите.Не обіцяю, що парсер працюватиме роками без дотику. Він тримається на чужій розмітці й чужих правилах доступу: сайт змінить сторінку — розбірник треба поправити. Обіцяю інше: щоб така поломка була видимою (лог і зупинка джерела, а не тихі нулі в базі), а правка — дешевою (окремий розбірник на джерело, а не один моноліт).
Так само не обіцяю нескінченну швидкість: чим агресивніший темп, тим швидше прилетить блокування. Правильна відповідь — не «швидше», а «рівно і без зупинок».