- Home »

Работа с веб-данными с помощью Requests и Beautiful Soup в Python 3
Всем привет! Сегодня копаемся в одном из самых мощных и популярных инструментов для работы с веб-данными в Python — связке Requests и Beautiful Soup. Если ты администрируешь серверы, настраиваешь мониторинг или просто хочешь автоматизировать рутинные задачи по сбору информации с веб-ресурсов, эта статья для тебя. Мы разберём, как правильно парсить сайты, обрабатывать HTTP-запросы и извлекать нужные данные без лишних танцев с бубном.
Requests + Beautiful Soup — это классическая комбинация для веб-скрапинга, которая позволяет быстро создавать мощные скрипты для сбора данных. Особенно полезно это для системных администраторов, которым нужно мониторить статусы сервисов, собирать метрики с веб-интерфейсов или автоматизировать проверку доступности ресурсов.
Как это работает под капотом
Requests — это HTTP-библиотека для Python, которая делает работу с HTTP-запросами человекочитаемой. Beautiful Soup — парсер HTML/XML, который умеет извлекать данные из разметки как настоящий ниндзя. Вместе они образуют мощный тандем:
- Requests получает HTML-страницу через HTTP/HTTPS
- Beautiful Soup парсит полученную разметку и позволяет искать нужные элементы
- Python обрабатывает и сохраняет данные в нужном формате
Архитектура работы выглядит так: твой скрипт отправляет HTTP-запрос → сервер возвращает HTML → Beautiful Soup создаёт DOM-дерево → ты извлекаешь нужные данные через селекторы.
Быстрая настройка и первые шаги
Начнём с установки необходимых пакетов. На продакшн-сервере рекомендую использовать виртуальное окружение:
# Создаём виртуальное окружение
python3 -m venv venv_scraper
source venv_scraper/bin/activate
# Устанавливаем пакеты
pip install requests beautifulsoup4 lxml
# Для работы с HTTPS может понадобиться
pip install certifi
Первый рабочий пример — проверим доступность сайта и извлечём заголовок:
import requests
from bs4 import BeautifulSoup
def get_page_title(url):
try:
# Отправляем GET-запрос
response = requests.get(url, timeout=10)
response.raise_for_status() # Проверяем статус-код
# Парсим HTML
soup = BeautifulSoup(response.content, 'html.parser')
# Извлекаем заголовок
title = soup.find('title')
return title.text if title else "Title not found"
except requests.RequestException as e:
return f"Error: {e}"
# Тестируем
url = "https://httpbin.org/html"
print(get_page_title(url))
Практические примеры и кейсы
Давай разберём несколько реальных сценариев, которые пригодятся в работе.
Мониторинг статуса сервисов
Создадим скрипт для проверки доступности нескольких сервисов:
import requests
from bs4 import BeautifulSoup
import json
from datetime import datetime
def check_service_status(services):
results = []
for service in services:
try:
start_time = datetime.now()
response = requests.get(service['url'], timeout=5)
end_time = datetime.now()
response_time = (end_time - start_time).total_seconds()
# Проверяем наличие ключевых слов на странице
soup = BeautifulSoup(response.content, 'html.parser')
page_content = soup.get_text().lower()
status = "UP" if service.get('keyword', '').lower() in page_content else "DOWN"
results.append({
'service': service['name'],
'url': service['url'],
'status': status,
'response_time': response_time,
'http_code': response.status_code,
'timestamp': datetime.now().isoformat()
})
except requests.RequestException as e:
results.append({
'service': service['name'],
'url': service['url'],
'status': "ERROR",
'error': str(e),
'timestamp': datetime.now().isoformat()
})
return results
# Конфигурация сервисов
services = [
{
'name': 'Web Server',
'url': 'https://example.com',
'keyword': 'welcome'
},
{
'name': 'API Endpoint',
'url': 'https://api.example.com/health',
'keyword': 'ok'
}
]
# Проверяем статус
status_results = check_service_status(services)
print(json.dumps(status_results, indent=2))
Парсинг логов и метрик
Многие веб-интерфейсы показывают метрики в HTML-формате. Вот пример извлечения данных из веб-интерфейса мониторинга:
import requests
from bs4 import BeautifulSoup
import re
def parse_server_metrics(url, auth=None):
headers = {
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36'
}
session = requests.Session()
if auth:
session.auth = auth
try:
response = session.get(url, headers=headers, timeout=10)
response.raise_for_status()
soup = BeautifulSoup(response.content, 'html.parser')
metrics = {}
# Ищем таблицы с метриками
for table in soup.find_all('table'):
for row in table.find_all('tr'):
cells = row.find_all(['td', 'th'])
if len(cells) >= 2:
metric_name = cells[0].get_text(strip=True)
metric_value = cells[1].get_text(strip=True)
# Попытка извлечь числовое значение
number_match = re.search(r'(\d+\.?\d*)', metric_value)
if number_match:
metrics[metric_name] = float(number_match.group(1))
else:
metrics[metric_name] = metric_value
return metrics
except requests.RequestException as e:
return {'error': str(e)}
# Пример использования
metrics = parse_server_metrics('http://localhost:8080/metrics')
print(f"CPU Usage: {metrics.get('CPU Usage', 'N/A')}")
print(f"Memory Usage: {metrics.get('Memory Usage', 'N/A')}")
Продвинутые техники и оптимизация
Для серьёзной работы с веб-данными нужно знать несколько продвинутых техник:
Работа с сессиями и куками
import requests
from bs4 import BeautifulSoup
class WebScraper:
def __init__(self):
self.session = requests.Session()
self.session.headers.update({
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36'
})
def login(self, login_url, username, password):
# Получаем страницу входа
login_page = self.session.get(login_url)
soup = BeautifulSoup(login_page.content, 'html.parser')
# Ищем CSRF-токен
csrf_token = soup.find('input', {'name': 'csrf_token'})
token_value = csrf_token['value'] if csrf_token else None
# Данные для входа
login_data = {
'username': username,
'password': password
}
if token_value:
login_data['csrf_token'] = token_value
# Отправляем POST-запрос для входа
response = self.session.post(login_url, data=login_data)
return response.status_code == 200
def scrape_protected_page(self, url):
response = self.session.get(url)
if response.status_code == 200:
return BeautifulSoup(response.content, 'html.parser')
return None
# Использование
scraper = WebScraper()
if scraper.login('https://example.com/login', 'admin', 'password'):
protected_content = scraper.scrape_protected_page('https://example.com/dashboard')
Обработка AJAX и динамического контента
Некоторые данные загружаются через AJAX. Вот как можно это обработать:
import requests
from bs4 import BeautifulSoup
import json
import time
def scrape_with_ajax(base_url, ajax_endpoint):
session = requests.Session()
# Получаем основную страницу
main_page = session.get(base_url)
soup = BeautifulSoup(main_page.content, 'html.parser')
# Ищем данные для AJAX-запроса
ajax_data = {}
for script in soup.find_all('script'):
if script.string and 'ajax' in script.string.lower():
# Здесь можно парсить JavaScript для получения параметров
pass
# Делаем AJAX-запрос
ajax_response = session.get(f"{base_url}{ajax_endpoint}",
headers={'X-Requested-With': 'XMLHttpRequest'})
if ajax_response.status_code == 200:
try:
return ajax_response.json()
except json.JSONDecodeError:
return BeautifulSoup(ajax_response.content, 'html.parser')
return None
# Пример использования
ajax_data = scrape_with_ajax('https://example.com', '/api/data')
Сравнение с альтернативными решениями
Вот сравнение популярных инструментов для веб-скрапинга:
Инструмент | Скорость | Простота | JavaScript | Ресурсы | Лучше для |
---|---|---|---|---|---|
Requests + BeautifulSoup | Высокая | Очень простая | Нет | Низкие | Статический контент |
Scrapy | Очень высокая | Средняя | Ограниченно | Средние | Крупные проекты |
Selenium | Низкая | Средняя | Да | Высокие | Динамический контент |
Playwright | Средняя | Средняя | Да | Высокие | Современные SPA |
Полезные библиотеки и расширения
Для расширения возможностей рекомендую изучить эти библиотеки:
- requests-html — объединяет Requests и PyQuery для более удобного парсинга
- httpx — современная асинхронная альтернатива Requests
- selectolax — быстрый парсер HTML, альтернатива Beautiful Soup
- fake-useragent — генерация случайных User-Agent для обхода блокировок
- requests-cache — кеширование HTTP-запросов
Пример использования с кешированием:
import requests_cache
from bs4 import BeautifulSoup
# Создаём кешированную сессию
session = requests_cache.CachedSession(
'scraping_cache',
expire_after=3600 # Кеш на час
)
def cached_scrape(url):
response = session.get(url)
return BeautifulSoup(response.content, 'html.parser')
# Первый запрос — с сервера, второй — из кеша
soup1 = cached_scrape('https://example.com')
soup2 = cached_scrape('https://example.com') # Из кеша
Автоматизация и интеграция
Для автоматизации скрапинга в продакшн-среде создай systemd-сервис:
# /etc/systemd/system/web-scraper.service
[Unit]
Description=Web Scraper Service
After=network.target
[Service]
Type=simple
User=scraper
WorkingDirectory=/opt/scraper
ExecStart=/opt/scraper/venv/bin/python /opt/scraper/main.py
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
Основной скрипт с логированием:
import requests
from bs4 import BeautifulSoup
import logging
import json
import time
from datetime import datetime
# Настройка логирования
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('/var/log/scraper.log'),
logging.StreamHandler()
]
)
class ProductionScraper:
def __init__(self, config_file):
with open(config_file, 'r') as f:
self.config = json.load(f)
self.session = requests.Session()
self.session.headers.update(self.config.get('headers', {}))
def scrape_and_save(self):
for target in self.config['targets']:
try:
logging.info(f"Scraping {target['name']}")
response = self.session.get(target['url'], timeout=10)
response.raise_for_status()
soup = BeautifulSoup(response.content, 'html.parser')
# Извлекаем данные по селекторам
data = {}
for selector_name, selector in target['selectors'].items():
element = soup.select_one(selector)
data[selector_name] = element.get_text(strip=True) if element else None
# Сохраняем в файл
timestamp = datetime.now().isoformat()
output_file = f"/var/data/{target['name']}_{timestamp}.json"
with open(output_file, 'w') as f:
json.dump(data, f, indent=2)
logging.info(f"Data saved to {output_file}")
except Exception as e:
logging.error(f"Error scraping {target['name']}: {e}")
time.sleep(self.config.get('delay', 1))
if __name__ == "__main__":
scraper = ProductionScraper('/etc/scraper/config.json')
while True:
scraper.scrape_and_save()
time.sleep(3600) # Каждый час
Производительность и оптимизация
Для высокопроизводительного скрапинга используй асинхронные запросы:
import asyncio
import aiohttp
from bs4 import BeautifulSoup
async def fetch_and_parse(session, url):
try:
async with session.get(url) as response:
content = await response.text()
soup = BeautifulSoup(content, 'html.parser')
return {
'url': url,
'title': soup.find('title').get_text(strip=True),
'status': response.status
}
except Exception as e:
return {'url': url, 'error': str(e)}
async def bulk_scrape(urls):
async with aiohttp.ClientSession() as session:
tasks = [fetch_and_parse(session, url) for url in urls]
results = await asyncio.gather(*tasks)
return results
# Пример использования
urls = [
'https://example.com',
'https://httpbin.org/html',
'https://httpbin.org/json'
]
results = asyncio.run(bulk_scrape(urls))
for result in results:
print(f"{result['url']}: {result.get('title', result.get('error'))}")
Деплой и хостинг
Для деплоя скрапинга-скриптов рекомендую использовать выделенный сервер или VPS. Если нужен надёжный хостинг для таких задач, обрати внимание на VPS-решения или выделенные серверы.
Для контейнеризации создай Dockerfile:
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["python", "scraper.py"]
Заключение и рекомендации
Requests + Beautiful Soup — это мощная и гибкая связка для работы с веб-данными. Она отлично подходит для:
- Мониторинга — проверка статуса сервисов и извлечение метрик
- Автоматизации — регулярный сбор данных с веб-интерфейсов
- Интеграции — получение данных из систем без API
- Анализа — исследование структуры сайтов и извлечение информации
Главные принципы работы:
- Всегда проверяй robots.txt и соблюдай rate limits
- Используй сессии для сохранения куков и повышения производительности
- Обрабатывай ошибки и реализуй retry-логику
- Логируй всё для отладки и мониторинга
- Тестируй на dev-окружении перед продакшном
Для простых задач статического парсинга Requests + Beautiful Soup — идеальный выбор. Для более сложных сценариев с JavaScript стоит рассмотреть Selenium или Playwright. Но в большинстве случаев для системных администраторов и автоматизации этой связки более чем достаточно.
В этой статье собрана информация и материалы из различных интернет-источников. Мы признаем и ценим работу всех оригинальных авторов, издателей и веб-сайтов. Несмотря на то, что были приложены все усилия для надлежащего указания исходного материала, любая непреднамеренная оплошность или упущение не являются нарушением авторских прав. Все упомянутые товарные знаки, логотипы и изображения являются собственностью соответствующих владельцев. Если вы считаете, что какой-либо контент, использованный в этой статье, нарушает ваши авторские права, немедленно свяжитесь с нами для рассмотрения и принятия оперативных мер.
Данная статья предназначена исключительно для ознакомительных и образовательных целей и не ущемляет права правообладателей. Если какой-либо материал, защищенный авторским правом, был использован без должного упоминания или с нарушением законов об авторском праве, это непреднамеренно, и мы исправим это незамедлительно после уведомления. Обратите внимание, что переиздание, распространение или воспроизведение части или всего содержимого в любой форме запрещено без письменного разрешения автора и владельца веб-сайта. Для получения разрешений или дополнительных запросов, пожалуйста, свяжитесь с нами.