惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

The Cloudflare Blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
T
The Blog of Author Tim Ferriss
G
Google Developers Blog
小众软件
小众软件
J
Java Code Geeks
V
Visual Studio Blog
The Register - Security
The Register - Security
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
罗磊的独立博客
美团技术团队
阮一峰的网络日志
阮一峰的网络日志
V
V2EX
博客园 - 叶小钗
N
Netflix TechBlog - Medium
月光博客
月光博客
aimingoo的专栏
aimingoo的专栏
大猫的无限游戏
大猫的无限游戏
T
The Exploit Database - CXSecurity.com
The Hacker News
The Hacker News
Cisco Talos Blog
Cisco Talos Blog
Hacker News: Ask HN
Hacker News: Ask HN
Hacker News - Newest:
Hacker News - Newest: "LLM"
AWS News Blog
AWS News Blog
Webroot Blog
Webroot Blog
The Last Watchdog
The Last Watchdog
T
Threatpost
I
Intezer
T
Tenable Blog
L
LINUX DO - 热门话题
T
Tailwind CSS Blog
Scott Helme
Scott Helme
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
C
Cybersecurity and Infrastructure Security Agency CISA
Engineering at Meta
Engineering at Meta
S
Schneier on Security
Recent Announcements
Recent Announcements
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
F
Fortinet All Blogs
腾讯CDC
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
T
Troy Hunt's Blog
量子位
H
Hacker News: Front Page
V2EX - 技术
V2EX - 技术
Google Online Security Blog
Google Online Security Blog
人人都是产品经理
人人都是产品经理
博客园 - 【当耐特】
博客园 - Franky
www.infosecurity-magazine.com
www.infosecurity-magazine.com

Все публикации подряд на Хабре

Ловим музу за клавиатуру: как айтишнику стать автором Что умеет Midjourney в 2026? Мой немного грустный разбор этого шикарного инструмента Никто не любит писать тесты, но ИИ может исправить это IPv8 выглядит как мечта. Поэтому почти наверняка не взлетит Производители вернули в продажу материнки с DDR3. Что происходит? Управление агентом с телефона через Telegram теперь в KodaCode От координации к лидерству: как меняется роль руководителя разработки Я сделала родителям бизнес вместо пенсии: зарабатываем 70 тысяч, мама не даёт продать В три раза быстрее приемка товара и оптимизация трудозатрат на 73%: как «РСТ-Инвент» помог Gulliver Group ИИ-шечный мир победил? О влиянии искусственного интеллекта на игропром Кремль снижает давление на Телеграмм пока Европа строит интернет по паспорту Как CEO, CTO и CIO за 8 часов собрали ИИ-директора, который умеет держать позицию под давлением Как (не) потерять домен за выходные Вместо 8 разных VPS: как я организовал практику студентам на одном сервере Почему твой Open Source проект не замечают? R&D: искусство управления неопределенностью в разработке AI-дефляция: вакансий для разработчиков больше, а рост зарплат — худший за 15 лет Мы отдали управление роботами OpenClaw. Что из этого вышло Галактический ID: система идентификации для всех форм разумной жизни Шесть основ бизнес-анализа: начинаем с вопроса «Кто в игре?» Код-ревью, в котором дело не в коде Данные переехали. Команда — нет Системной подход к сдаче OSWE в 2025 Почему комната управления реактором покрашена в цвет морской пены 4 YAML-файла вместо PySpark: как аналитикам строить пайплайны без разработчиков LLM-агент для поиска свободных доменов: автоматизируем подбор Когда, зачем и как правильно начинать новую сессию в Claude Code? Как я заставил нейросеть писать макросы для FreeCAD Анатомия ИИ‑агента для подбора персонала. От тысячи резюме к топ‑10 за минуты Опыт разработчика как экономика внимания Автономность как точка невозврата: кто будет субъектом в цифровом будущем Обучение ИИ в «диких» условиях: как рутинные действия превращаются в датасеты Как измерить LLM для задач кибербеза: обзор открытых бенчмарков Где хранить код? Сравнение GitHub, GitLab и Bitbucket Математика объясняет, почему нормальное распределение встречается повсюду Почему ваш FinOps не работает: 12 тезисов от практиков Как подписать проектную документацию УКЭП с использованием бесплатных лицензий Pilot Адаптивное администрирование Sigla Vision Я грузил уран в бочки, а потом 20 лет строил ИТ в атомной отрасли Чем позвонить с Эвереста? История и обзор спутниковой связи. Часть 2 Как языковая модель помогает контролировать качество инструктажей по охране труда в металлургии Как не передать на desktop свой IP в РКН Анатомия SAP Privileges: как устроено управление правами в macOS MoneyDev: Сказка про три главных слова Обновлённый токенизатор видео K-VAE 2.0 от Сбера Как сделать диспетчеризацию дома на 1284 квартиры почти бесплатно Как мы разогнали железную дорогу Мы дали агентам рутину. Теперь надо решить — что делать с освободившимся временем Токсичный контент, промпт-хакинг и защита ИИ — всё о Guardrails для LLM Умный город начинается с точного взгляда: как «Фалькон Тех» меняет пространство к лучшему Навайбкодил приложение для анализа графов Почему Дюну так интересно читать? Упрощаем работу с рутиной или как стать Гендальфом Белым Деконструкция Go: CPU, RAM и что там происходит. Go Assembler база. Часть 1.1 Какие профессии исчезнут из-за ИИ, а какие появятся? И что с этим делать Как мы построили IT-отдел, где хочется расти: архитектурные встречи, прозрачные метрики и книжные подарки Rufler: Делаем из Claude Code автономный рой через один YAML-конфиг Sing-box и белый список приложений Как построить надёжный обмен сообщениями в микросервисах: лучшие практики для enterprise OpenAI строит MLM-пирамиду, а McKinsey и Accenture помогают ей в этом Дом, который не построил Фишер (Часть 2) «Сверхзвуковой математик» против «Вдумчивого логиста»: битва алгоритмов 3D-упаковки Мультимодальные модели – грубый и дорогой инструмент Разговоры ничего не стоят. Код тоже Проверки физических лиц: с кого начнет ФНС Топ-10 бесплатных нейросетей для создания видео в 2026 году Первые слои кода: как наши решения сегодня определяют архитектуру ИИ на десятилетия Разработка нового статического анализатора: PVS-Studio JavaScript Поиск уязвимостей ПО: базовый минимум или роскошный максимум Почему оценка персонала не работает как инструмент управления Как мы разработали ИИ-ассистента и сократили рутину продуктовой команды на 50% Как я ушел из найма, нажарил косточек и продал на маркетплейсах на 168 млн в год Когда 1С:ERP уже внедрена, а нормального производственного плана всё ещё нет Как я сделал Claude мультимодальным, подключив к нему Qwen Omni Как приглашение на вакансию мечты превращается в атаку Infrastructure as Code: философия и лучшие практики IaC Тестируем Yandex Code Assistant на задаче, в которой нужно хранить секреты nxs-universal-chart v3.0: новое поколение универсального Helm-чарта Callback Injection: Техника, которая отправила Microsoft Defender в глухой нокаут «Все идеи на стол»: митап как способ вывести проект из тупика Сегодня я узнал нечто новое о GPU благодаря багу в своей игре Как заставить LLM ̶ ̶г̶а̶л̶л̶ю̶ ̶ эволюционировать Карта событий как фундамент аналитики: практический кейс для E-commerce Что выбрать для AI: x86, ARM или RISC-V? Дайджест железа за март Роль соматических мутаций в развитии аутоиммунных заболеваний: путь к избирательной терапии Mythos от Anthropic — тревожный сигнал для всех, а не только для банков Guardrails для LLM на Java: как приручить промпт‑инъекции и токсичные ответы Green-VLA: как мы собрали VLA-модель для реального антропоморфного робота и не потеряли обобщение Финансовая гонка вооружений: почему умные люди добровольно в ней участвуют Эра ИИ-агентов наступила: выбираем лучшего цифрового сотрудника # Практический опыт внедрения WinCC Redundancy на производственном предприятии Сделал MVP за 3 дня, а потом неделю прикручивал оплату. Оно того стоило? Физика против Маска: почему Starship V3 может оказаться ещё одной катастрофой Нефть Венесуэлы: крупнейшие запасы в мире, но не крупнейшая нефтяная держава JPA 4. Переосмысление Hibernate Почему зеркальная фотокамера Nikon D5 десятилетней давности идеально подошла для миссии «Артемида-2» Проект «Уровень-Спутник» или как мы сделали платформу для гидрологов «Замедлиться, чтобы ускориться»: почему ИИ повышает цену ошибок в требованиях и архитектуре Как с нуля поднять трафик IT-компании на 1657% при бюджете 55 тыс. и выжить Pixel-perfect Downsampling — идеальная отрисовка 50 миллионов точек без потерь
Основы парсинга сайтов: от HTML до готового датасета для NLP
Andrey_Biryu · 2026-05-07 · via Все публикации подряд на Хабре

Уровень сложностиПростой

Время на прочтение9 мин

Охват и читатели340

Туториал

Вы освоили машинное обучение, знаете, чем transformer отличается от LSTM, но где брать данные для своих проектов? Готовые датасеты — это хорошо, но они общие. А если вам нужны посты из конкретного Telegram‑канала, отзывы с узкопрофильного форума или корпус текстов по редкой теме?

Парсинг сайтов — это навык, который превращает интернет в вашу персональную фабрику данных. Без него даже самая умная модель останется без «топлива». В этой статье мы рассмотрим весь путь: от первого запроса к сайту до готового датасета, пригодного для обучения.

Мы будем двигаться от простого к сложному. Вы узнаете, как парсить статические страницы, обходить базовые блокировки и организовывать масштабный сбор данных.

📍 Прежде чем переходить к практике, пройдите короткий бесплатный тест по NLP и языковым трансформерным моделям. Он поможет понять, в каких темах вы уже уверены, а что стоит подтянуть. ➞ Пройти тест

С чего всё начинается

Прежде чем писать код, нужно понять, как устроен веб. Представьте, что интернет — это огромная библиотека, а ваш браузер — библиотекарь, который ходит за книгами. Парсер — это робот‑библиотекарь, который делает это быстро и по заданному алгоритму.

Всё начинается с HTTP‑запроса. Когда вы вводите адрес сайта, ваш браузер отправляет серверу запрос: «Дай мне, пожалуйста, содержимое страницы». Сервер отвечает HTML‑кодом — это «скелет» страницы, размеченный тегами.

Пример простого HTML‑фрагмента:

<div class="product">
    <h2>Название товара</h2>
    <span class="price">1000 ₽</span>
    <p class="description">Описание товара...</p>
</div>

Парсер должен найти этот блок (div class="product") и извлечь из него нужные данные: заголовок (h2), цену (span.price) и описание (p.description).

GET и POST являются двумя основными типами запросов. GET используется для получения данных. Когда вы открываете страницу товара, браузер отправляет GET‑запрос. В свою очередь POST используется для отправки данных на сервер, например, при заполнении формы поиска или авторизации. На начальном этапе вам почти всегда будет достаточно GET‑запросов.

Requests + BeautifulSoup

Это стандартная связка для парсинга, известная как «золотая середина» для большинства задач, потому что requests скачивает страницу, а BeautifulSoup помогает находить в ней данные.

Почему они хороши вместе? Requests выступает в роли курьера, доставляя вам HTML‑код, а BeautifulSoup — в роли аналитика, который этот код изучает и находит в нём закономерности. requests идеально подходит для базовых HTTP‑операций, а BeautifulSoup — для навигации по HTML‑дереву и поиска элементов.

Для установки необходимо выполнить следующее:

pip install requests beautifulsoup4 lxml

Здесь lxml — это быстрый парсер, который мы передадим BeautifulSoup для ускорения работы. Теперь давайте напишем скрипт, который загружает страницу и извлекает заголовки статей.

import requests
from bs4 import BeautifulSoup

# 1. Отправляем GET-запрос к сайту
url = "https://example.com/blog"

# Для реальных проектов всегда указывайте User-Agent, чтобы не походить на бота
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
}
response = requests.get(url, headers=headers)

# 2. Проверяем, успешно ли прошёл запрос (код 200 означает "OK")
if response.status_code == 200:
    # 3. Передаём HTML-код страницы BeautifulSoup для анализа
    soup = BeautifulSoup(response.text, 'lxml')

    # 4. Находим все элементы, содержащие заголовки.

    # Предположим, заголовки статей находятся в теге <h2> с классом "post-title"
    titles = soup.find_all('h2', class_='post-title')

    # 5. Извлекаем и выводим текст из каждого найденного элемента
    for title in titles:
        print(title.text.strip())
else:
    print(f"Ошибка загрузки страницы. Код: {response.status_code}")

Краткий разбор полётов:

  • requests.get(url, headers=headers) загружает страницу.

  • BeautifulSoup(response.text, 'lxml') создаёт объект, с которым удобно работать.

  • soup.find_all('h2', class_='post-title') ищет все теги <h2> с классом post-title. Это один из самых мощных методов библиотеки.

  • title.text.strip() достаёт текст внутри тега и удаляет лишние пробелы и переносы строк.

Продвинутый поиск: CSS‑селекторы

Метод find_all — это конечно хорошо, но иногда удобнее использовать CSS‑селекторы. Это мощный язык запросов к элементам HTML. Давайте посмотрим несколько примеров использования.

Найдем все ссылки внутри элементов с классом «product»

links = soup.select('.product a')

Теперь поищем элемент с id=«main-content»

main_content = soup.select_one('#main-content')

Найдем все изображения внутри блока с классом «gallery»

images = soup.select('.gallery img')

Метод .select() возвращает список всех подходящих элементов, а.select_one() — первый подходящий. Это делает код более читаемым, особенно при работе со сложной вложенностью.

Когда страницы оживают: Playwright для SPA и React‑сайтов

Современный интернет — это уже не просто набор HTML‑страниц. Многие сайты (особенно с технологиями React, Vue, Angular) — это одностраничные приложения (SPA). Они загружают пустой «скелет», а весь контент подтягивается скриптами уже после загрузки.

Вы можете получить HTML‑код такой страницы через requests, но красивого текста с данными в нём не будет. Вам нужен инструмент, который может не просто скачать файл, а запустить браузер и выполнить весь JavaScript‑код, как это делает обычный пользователь. И здесь на сцену выходит Playwright.

Playwright — это библиотека для автоматизации браузеров (Chrome, Firefox, Safari). Она запускает настоящее браузерное окно (или «голову», headless‑режим) и выполняет все действия, которые может делать человек: кликать, скроллить, вводить текст. После того как страница полностью загружена и все скрипты отработали, мы можем получить её финальный HTML‑код и спокойно распарсить его уже знакомым BeautifulSoup. Это незаменимый инструмент для сбора данных с SPA, сайтов с бесконечной прокруткой (infinite scroll) и для обхода несложной защиты от ботов.

Для установки выполним следующее:

pip install playwright

playwright install # Скачивает браузеры (chromium, firefox, webkit)

Далее рассмотрим пример скрипта для динамической страницы:

import asyncio
from playwright.async_api import async_playwright
from bs4 import BeautifulSoup
 
async def scrape_dynamic_site():
    async with async_playwright() as p:
        # Запускаем браузер (headless=False, чтобы увидеть окно браузера)
        browser = await p.chromium.launch(headless=True)
        page = await browser.new_page()
        
        # Переходим на сайт и ждём, пока загрузится сеть (важно для SPA!)
        await page.goto("https://quotes.toscrape.com/scroll")
        await page.wait_for_load_state("networkidle")
        
        # Симулируем прокрутку вниз для подгрузки новых элементов (если нужно)
        for _ in range(3):
            await page.evaluate("window.scrollTo(0, document.body.scrollHeight)")
            await page.wait_for_timeout(1000)  # Ждём подгрузки
        
        # Получаем HTML-код полностью отрисованной страницы
        html = await page.content()
        
        # Закрываем браузер
        await browser.close()
        
        # Теперь можно парсить этот HTML через BeautifulSoup
        soup = BeautifulSoup(html, 'lxml')
        quotes = soup.select('.quote')
    
        for quote in quotes:
            text = quote.select_one('.text').text
            author = quote.select_one('.author').text
            print(f"{author} said: {text[:50]}...")

asyncio.run(scrape_dynamic_site())

В этом коде мы не просто скачиваем страницу, а эмулируем поведение пользователя: ждём загрузки, прокручиваем вниз, даём время подгрузиться новым элементам, и только потом забираем готовый HTML.

Пайплайн для качественного датасета

Получить сырой текст с сайта — это только полдела. Чтобы он превратился в полезный датасет для NLP, ему нужна обработка. Это похоже на добычу нефти: сначала идёт бурение (парсинг), а потом — сложная переработка (очистка), чтобы получить бензин (датасет).

Вот основные шаги по превращению «грязных» веб‑данных в пригодные для обучения модели:

  1. Извлечение (Extraction): Мы уже это умеем. Получаем HTML и вытаскиваем из него нужные поля (текст, даты, теги).

  2. Очистка (Cleaning): Удаляем HTML‑теги, которые могли остаться. Убираем мусор: специальные символы (&nbsp;, \xa0, \u200b), лишние пробелы и переносы строк.

  3. Нормализация (Normalization): Приводим текст к единому виду. Например, все даты приводим к формату ГГГГ‑ММ‑ДД, имена и названия очищаем от случайных символов.

Предобработка для NLP (Preprocessing): Этот шаг зависит от вашей задачи. Он может включать:

  • Токенизацию (разбиение на слова).

  • Удаление стоп‑слов (очень частых слов, не несущих смысла: «и», «в», «на»).

  • Лемматизацию или стемминг (приведение слов к начальной форме: «бежал», «бежит», «бегут» → «бежать»).

Теперь давайте рассмотрим пример кода, который дополняет наш пайплайн, превращая сырой HTML в чистый текст.

import re
import pandas as pd
from bs4 import BeautifulSoup
from nltk.corpus import stopwords
from nltk.stem import WordNetLemmatizer

# Не забудьте скачать ресурсы NLTK: nltk.download('stopwords'), nltk.download('wordnet')
lemmatizer = WordNetLemmatizer()
stop_words = set(stopwords.words('russian'))
 
def clean_text(html_content):
    # 1. Извлечение текста из HTML
    soup = BeautifulSoup(html_content, 'lxml')
    text = soup.get_text(separator=' ')
    
    # 2. Приведение к нижнему регистру и удаление спецсимволов
    text = text.lower()
    text = re.sub(r'[^а-яa-z0-9\s]', '', text)  # Оставляем только буквы, цифры и пробелы
    
    # 3. Токенизация (разбиение на слова)
    tokens = text.split()
    
    # 4. Удаление стоп-слов и коротких слов
    tokens = [token for token in tokens if token not in stop_words and len(token) > 2]
    
    # 5. Лемматизация
    tokens = [lemmatizer.lemmatize(token) for token in tokens]
   
    # 6. Сборка обратно в строку
    clean_text = ' '.join(tokens)
    return clean_text

# Пример использования в вашем пайплайне
raw_data = []  # список словарей, полученных после парсинга

for item in raw_data:
    item['cleaned_content'] = clean_text(item['raw_html'])

df = pd.DataFrame(raw_data)
df.to_csv('my_dataset.csv', index=False)  # Сохраняем готовый датасет

Следуя этому пайплайну, вы превратите ворох сырых HTML‑страниц в структурированный, чистый датасет, готовый для обучения моделей классификации, генерации текста или построения RAG‑систем.

Заключение

Парсинг сайтов — это фундаментальный навык для любого специалиста по данным, который хочет работать с реальными, неигрушечными задачами. Мы прошли путь от базовых HTTP‑запросов до запуска браузеров и очистки данных. Теперь у вас есть инструментарий, чтобы создавать собственные датасеты для самых смелых NLP‑проектов.

Когда нужно не просто «поиграться с LLM», а встроить языковые модели в реальный продукт, быстро выясняется: базового понимания ChatGPT уже недостаточно. Нужно разбираться, как работают трансформеры, embeddings, RAG, тонкая настройка моделей и оценка качества, иначе проект легко превращается в набор красивых демо без стабильного результата.

Курс «Языковые трансформенные модели / NLP» помогает перейти от поверхностного использования нейросетей к инженерному пониманию NLP‑систем: как выбирать подходящую архитектуру, готовить данные, работать с текстовыми корпусами и собирать решения, которые можно применять в рабочих задачах.

Если вы уже пробовали работать с LLM, но хотите перейти от промптов и демо к более инженерному пониманию моделей, начните с бесплатного открытого урока:

20 мая в 20:00. «Основы парсинга сайтов».
Разберём, как с помощью Python скачивать информацию с сайтов, извлекать нужные данные и собирать основу для собственного датасета, который затем можно использовать в NLP‑задачах.

Полный список бесплатных уроков мая смотрите в дайджесте.