← Назад к вопросам

Что может заблокировать parsing HTML-страницы?

2.3 Middle🔥 71 комментариев
#Node.js и JavaScript#Кэширование и производительность

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI30 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Факторы, которые могут заблокировать парсинг HTML

Парсинг HTML — это не просто загрузка и разбор текста. Есть много причин, по которым процесс может замедлиться, зависнуть или вообще сломаться. Расскажу про наиболее частые проблемы.

1. Сетевые проблемы (Most Common)

Медленное подключение или таймауты:

const axios = require('axios');
const cheerio = require('cheerio');

async function parseHTML(url) {
  try {
    const response = await axios.get(url, {
      timeout: 5000,
    });
    const $ = cheerio.load(response.data);
    return $('body').text();
  } catch (error) {
    if (error.code === 'ECONNABORTED') {
      console.error('Таймаут: сервер не ответил');
    }
  }
}

DNS резолюция: если DNS медленно работает, запрос может зависнуть. Решение — использовать публичные DNS (8.8.8.8) или увеличить таймаут.

2. Очень большой HTML (Blocking)

Если страница весит 100+ МБ, загрузка её в память может заблокировать весь процесс:

const fs = require('fs');
const { pipeline } = require('stream');

axios.get(url, { responseType: 'stream' })
  .then(response => {
    return new Promise((resolve, reject) => {
      pipeline(
        response.data,
        fs.createWriteStream('page.html'),
        (err) => {
          if (err) reject(err);
          else resolve();
        }
      );
    });
  });

3. JavaScript на странице (Critical!)

Современные страницы генерируют контент через JavaScript. Парсер, который просто загружает HTML, получит пустую страницу:

const puppeteer = require('puppeteer');

async function parseWithJS(url) {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto(url);
  await page.waitForSelector('.content');
  const content = await page.$eval('.content', el => el.textContent);
  await browser.close();
  return content;
}

Puppeteer открывает полноценный браузер, поэтому заблокирует потребление памяти и CPU. Нужна оптимизация если много параллельных запросов.

4. Неправильная кодировка символов

Если страница в кодировке, которую мы не указали, парсинг будет неправильным:

const iconv = require('iconv-lite');
const response = await axios.get(url, { responseType: 'arraybuffer' });
const html = iconv.decode(response.data, 'windows-1251');
const $ = cheerio.load(html);

5. Защита от парсинга (Anti-Scraping)

Сайт может блокировать парсеры через User-Agent проверку:

const response = await axios.get(url, {
  headers: {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
  }
});

IP блокировка: если делаю слишком много запросов, мой IP забанят. Решение — использовать прокси или delay:

async function parseWithDelay(urls) {
  for (const url of urls) {
    const response = await axios.get(url);
    await new Promise(r => setTimeout(r, 1000));
  }
}

6. Синтаксические ошибки в HTML

Если HTML некорректный, парсер может глючить. Cheerio обычно справляется автоматически, но лучше валидировать.

7. Неэффективные селекторы

Если выбираю элементы неправильно, операция может быть медленной:

const links = $('a');

links.each((i, el) => {
  // работаем с уже выбранными элементами
});

8. Recursive parsing без лимита

Если страница имеет глубокую вложенность:

function parseRecursive(element, depth = 0) {
  if (depth > 100) return;
}

Пример надежного парсера

async function robustParse(url) {
  const maxRetries = 3;
  let lastError;
  
  for (let i = 0; i < maxRetries; i++) {
    try {
      const response = await axios.get(url, { timeout: 10000 });
      const $ = cheerio.load(response.data);
      return { success: true, data: $('body').text() };
    } catch (error) {
      lastError = error;
      await new Promise(r => setTimeout(r, 1000 * (i + 1)));
    }
  }
  
  return { success: false, error: lastError.message };
}

Лучшие практики

  1. Всегда используй таймауты (5-30 сек)
  2. Streaming для больших файлов
  3. Для JS-контента используй Puppeteer/Playwright с лимитом параллельных экземпляров
  4. Кэширование результатов
  5. Обработка ошибок и retry логика с exponential backoff
  6. Мониторинг — сколько времени занимает, какие ошибки
Что может заблокировать parsing HTML-страницы? | PrepBro