Уявіть, що ви прокидаєтеся щоранку і знаходите базу даних, повну сьогоднішніх новинних статей, вже очищених, структурованих і готових до аналізу. Ніякого ручного перегляду, ніякого копіювання-вставки, ніяких проблем з форматуванням. Просто свіжі дані, які чекають на вас.
Саме це ми і створили: універсальний скрейпер новин, який працює практично на будь-якому новинному сайті, розуміє дати природною мовою в будь-якому форматі, автоматично знаходить посилання на пагінацію, зупиняється, коли досягає вчорашніх статей, і зберігає все акуратно в локальній базі даних SQLite.
Ключова ідея полягає в тому, щоб використовувати AI не як чат-бота, а як інтелектуальний механізм парсингу. Замість того, щоб писати крихкі CSS-селектори, які ламаються кожного разу, коли сайт змінює дизайн, ми дозволяємо Gemini читати сторінку як людину і витягувати те, що важливо.
Огляд Архітектури
Система складається з трьох компонентів, що працюють локально на вашій машині:
Проксі-сервер (порт 3001) — HTTP-сервер на Node.js з двома кінцевими точками. Кінцева точка /fetch завантажує будь-який URL, видаляє скрипти та стилі, зберігає структурні HTML-теги, витягує посилання на пагінацію з сирого HTML до обрізання і повертає чистий структурований контент. Кінцева точка /ai отримує вміст сторінки та підказку, відправляє їх до Gemini API з автоматичним повтором у разі помилок обмеження швидкості і повертає відповідь моделі.
Скрипт скрейпера — скрипт на Node.js, який координує все. Він працює у двох фазах: Фаза 1 збирає всі посилання на статті зі сторінок списку, автоматично слідуючи пагінації, Фаза 2 відвідує кожен URL статті, витягує повний вміст через Gemini і зберігає в базі даних.
База даних SQLite — локальна однофайлова база даних, що зберігає статті з полями для URL (унікальний, запобігає дублюванню), заголовка, вмісту, дати, джерела та часу створення.
[Будь-який новинний сайт]
↓ HTTP-запит (заголовки, як у браузера)
[Проксі-сервер — server.js :3001]
↓ чистий HTML + посилання на пагінацію
[Gemini 2.5 Flash Lite API]
↓ структурований JSON
[scrape.js]
↓ INSERT OR IGNORE
[news.db — SQLite]
Чому Gemini, а не локальна модель?
Ми тестували локальні моделі (Llama 3.2, Mistral 7B через Ollama) для цього завдання. Результати були розчаровуючими — маленькі моделі, що працюють на CPU, занадто повільні для обробки сотень сторінок, вони вигадують посилання на пагінацію, яких не існує, і їм важко відрізнити основний вміст від віджетів бічної панелі, коли структура сторінки складна.
Gemini 2.5 Flash Lite вирішує всі ці проблеми. Він обробляє повну очищену сторінку за 1–2 секунди, правильно визначає дати статей будь-якою мовою і в будь-якому форматі, розуміє семантичну структуру HTML і коштує практично нічого — приблизно €0.55 за 200 статей.
Крок 1: Отримайте свій ключ Gemini API
Перейдіть на aistudio.google.com/api-keys і створіть новий ключ. Безкоштовний рівень надає 20 запитів на хвилину, що підходить для розробки. Для продуктивного скрейпінгу додайте спосіб оплати — коштує приблизно €0.25 на місяць при типовому щоденному використанні.
Вставте свій ключ у server.js на рядку 10:
const GEMINI_KEY = 'your_key_here';
Крок 2: Проксі-сервер (server.js)
Проксі-сервер є серцем системи. Його найважливіше завдання — витягти посилання на наступну сторінку перед видаленням атрибутів HTML — тонка, але важлива деталь.
Коли ми очищаємо HTML, ми видаляємо атрибути, такі як rel="next" і aria-label, щоб зменшити розмір вмісту для AI. Але саме ці атрибути ідентифікують посилання на пагінацію. Тому ми викликаємо extractNextPage() спочатку на сирому HTML, а потім очищаємо все інше.
Функція шукає три шаблони, які охоплюють переважну більшість новинних сайтів:
rel="next"— стандартний атрибут пагінації HTML5aria-label, що містить “next”, “далі”, “вперед”, “следующая”- Елементи з класом
is-next— поширені в CSS-фреймворках
// server.js
// [INSERT FULL server.js CODE HERE]
Функція cleanHtml() зберігає структурні теги (<main>, <article>, <section>, <aside>, <nav>, <time datetime>), видаляючи все інше. Це дає Gemini достатньо контексту, щоб відрізнити основний вміст від бічних панелей без обробки мегабайтів сирого HTML.
Функція askGemini() читає фактичний час очікування з відповіді про помилку обмеження швидкості Gemini (retry in 23.9s) і чекає саме стільки, перш ніж повторити спробу. Ніяких здогадок, ніяких фіксованих затримок.
Крок 3: Встановіть залежності та запустіть сервер
cd your-project-folder
npm install better-sqlite3
node server.js
Ви повинні побачити:
Server running at http://localhost:3001
Перевірте, відкривши цей URL у вашому браузері:
http://localhost:3001/fetch?url=https://example.com
Ви отримаєте JSON-відповідь з полями text, links і nextPage.
Крок 4: Розумне виявлення пагінації
Скрейпер ніколи не має жорстко закодованого списку URL-адрес сторінок. Він починає з одного URL і автоматично слідує за посиланням “наступна сторінка” на кожній сторінці.
Різні сайти використовують абсолютно різні шаблони пагінації:
https://site.com/news/page/2— стиль WordPresshttps://site.com/news/page-2— роздільник тире (TSN.ua як приклад для статті)https://site.com/news?page=2— параметр запитуhttps://site.com/news-2.html— плоский HTML-стиль
Проксі обробляє всі з них, оскільки шукає семантичні атрибути в HTML, а не шаблони URL. Скрейпер просто читає pageData.nextPage з відповіді проксі і слідує за ним бездумно.
Крок 5: Фільтрація дат на основі AI
Ось де підхід дійсно перевершує традиційні скрейпери. Новинні сайти відображають дати в абсолютно різних форматах:
<time datetime="2026-04-21T17:30:00+03:00">— стандартний HTML521 квітня 2026— українська довга формаСьогодні, 17:30— “Сьогодні” українською- Просто
17:30— тільки час, що означає сьогодні
Традиційний скрейпер потребував би спеціальної логіки парсингу для кожного формату на кожному сайті. Ми просто кажемо Gemini сьогоднішню дату і просимо його відфільтрувати:
Сьогодні 2026-04-21.
Витягніть посилання на новинні статті з основної області вмісту, опубліковані ТІЛЬКИ СЬОГОДНІ.
Дати можуть бути в будь-якому форматі: <time datetime>, "21.04.26", "17:30" (тільки час = сьогодні), "сьогодні" тощо.
ВИКЛЮЧИТИ: бічні панелі, "читайте також", рекламу, навігацію, сторінки категорій/тегів/авторів.
Встановіть "stop": true, якщо ви бачите статті з ВЧОРА або раніше в основному вмісті.
Поверніть ТІЛЬКИ дійсний JSON:
{"articles":[{"title":"...","url":"https://..."}],"stop":false,"reason":"..."}
Прапор stop є ключовим механізмом. Коли Gemini бачить вчорашні статті в основному вмісті, він повертає "stop": true, і скрейпер припиняє слідувати пагінації — незалежно від того, на якому номері сторінки ми знаходимося.
Крок 6: Витягнення вмісту статей
Фаза 2 відвідує кожен URL статті і витягує фактичний вміст. Підказка навмисно мінімальна:
Витягніть наступне з цієї сторінки новинної статті:
1. "title" — заголовок статті
2. "date" — дата публікації у форматі YYYY-MM-DD
3. "content" — повний текст статті, чистий, без реклами або навігації
Поверніть ТІЛЬКИ дійсний JSON без пояснень, без markdown, без тексту до або після:
{"title":"...","date":"2026-04-21","content":"..."}
Зверніть увагу, що немає поля для резюме. Спокуса генерувати резюме під час скрейпінгу, але це витрачає токени і час на те, що ви можете ніколи не використовувати. Зберігайте сирий вміст зараз, генеруйте резюме на вимогу, коли вам дійсно потрібно для аналізу.
Крок 7: Скрипт скрейпера (scrape.js)
// scrape.js
// [INSERT FULL scrape.js CODE HERE]
SQL-інструкція INSERT OR IGNORE у поєднанні з обмеженням UNIQUE на стовпці url автоматично обробляє все дублювання. Запускайте скрейпер кожну годину — він тихо пропускає будь-яку статтю, яка вже є в базі даних.
Запуск
Вам потрібні два вікна терміналу:
Термінал 1 — проксі-сервер (тримайте запущеним):
node server.js
Термінал 2 — скрейпер (запускайте, коли хочете свіжі статті):
node scrape.js
Щоб скрейпити інший новинний сайт, змініть лише один рядок на початку scrape.js:
const START = 'https://your-news-site.com/news';
Результати
Запуск проти TSN.ua (великий український новинний сайт, як приклад для статті) 21 квітня 2026 року:
- Фаза 1: зібрано 198 посилань на статті з 20 сторінок — автоматично зупинилося, коли з’явилися вчорашні статті
- Фаза 2: 198 статей завантажено, очищено і збережено
- Загальний час: ~11 хвилин
- Загальна вартість: €0.55 в кредитах Gemini API
- Розмір бази даних: ~8MB
Скрейпер правильно ігнорував віджети бічної панелі зі старими популярними статтями, гороскопами, прогнозами погоди та сторінками з курсами валют. Тільки фактичні новинні статті, опубліковані того дня, потрапили в базу даних.
Перегляд бази даних
Завантажте DB Browser for SQLite — безкоштовний, з відкритим вихідним кодом. Відкрийте news.db, і ви побачите всі статті у вигляді таблиці. Ви можете фільтрувати за датою, шукати вміст, експортувати в CSV.
Що далі
Автопублікація в WordPress — скрипт, який читає з бази даних і публікує в WordPress через REST API. У поєднанні з переписуванням контенту Клодом іспанською, німецькою або польською мовами, це стає повністю автоматизованим багатомовним новинним сайтом.
Кілька джерел — той самий сервер і скрейпер працюють на будь-якому новинному сайті. BBC, Reuters, TechCrunch, регіональні сайти будь-якою мовою — одна кодова база обробляє всі з них.
Заплановане виконання — додайте завдання Windows Task Scheduler або Linux cron для запуску node scrape.js щоранку. Прокидайтеся з повною базою даних сьогоднішніх новин.
Шар аналізу — другий скрипт читає сьогоднішні статті з SQLite, відправляє їх до Claude API і генерує ранковий брифінг: ключові історії, тенденції, наслідки. База даних стає джерелом інформації.
Створено за один день з використанням Node.js 23, Gemini 2.5 Flash Lite і better-sqlite3. Найважчою частиною було виявлення, що посилання на пагінацію зникають, коли ви видаляєте атрибути HTML — саме тому extractNextPage() повинен працювати на сирому HTML перед будь-яким очищенням.
Завантажити вихідний код
- джерела — проксі-сервер з інтеграцією Gemini + двофазний скрейпер з зберіганням у SQLite