Вопрос или проблема
Я относительно новичок в веб-скрапинге и в настоящее время работаю над скриптом на Python, который запускаю в среде JupyterHub, интегрированной с VSCode. Моя цель – оптимизировать этот скрипт, чтобы он автоматически запускался каждый день для сбора данных, избегая дублирующихся записей.
код здесь
import os
import random
import time
import requests
import pandas as pd
from bs4 import BeautifulSoup
from urllib.parse import urljoin
import datetime
# Функция для создания директорий при необходимости
def create_directories():
base_path="/home/housnimzeali" # Основная директория
directories = ['scraped_data', 'logs', 'scraped_files'] # Список директорий для создания
# Создание директорий, если это необходимо
for directory in directories:
directory_path = os.path.join(base_path, directory)
if not os.path.exists(directory_path):
os.makedirs(directory_path)
print(f"Директория создана: {directory_path}")
else:
print(f"Директория уже существует: {directory_path}")
# Функция для случайной задержки
def random_sleep(min_seconds=1, max_seconds=3):
delay = random.uniform(min_seconds, max_seconds)
time.sleep(delay)
# Функция для загрузки скрапированных URL
def load_scraped_urls(file_path):
try:
if pd.io.common.file_exists(file_path):
df = pd.read_excel(file_path)
return set(df['URL'].tolist()) # Возвращает множество скрапированных URL
else:
return set()
except Exception as e:
print(f"Ошибка при загрузке скрапированных URL: {e}")
return set()
# Функция для сохранения скрапированных URL
def save_scraped_urls(scraped_urls, file_path):
try:
df = pd.DataFrame(list(scraped_urls), columns=['URL'])
df.to_excel(file_path, index=False)
except Exception as e:
print(f"Ошибка при сохранении скрапированных URL: {e}")
# Функция для извлечения контента, тегов и даты из статьи
def scrap_contents_tags_date(article_url, headers):
try:
response = requests.get(article_url, headers=headers)
response.raise_for_status()
soup = BeautifulSoup(response.text, 'html.parser')
main_section = soup.select_one('main#main')
content_div = main_section.select_one('.content') if main_section else None
content=" ".join([element.get_text(strip=True) for element in content_div.find_all(True)]) if content_div else 'Нет контента'
date_div = content_div.select_one('span.article-meta-date') if content_div else None
date = date_div.get_text(strip=True) if date_div else 'Нет даты'
tags_section = main_section.select_one('.outside-content-zone.below-content')
tags_div = tags_section.select_one('p.tags') if tags_section else None
tags = [a.get_text(strip=True) for a in tags_div.find_all('a')] if tags_div else []
return content, tags, date
except requests.exceptions.RequestException:
return 'Нет контента', [], 'Нет даты'
# Функция для экспорта статей в Excel файл
def export_to_excel(articles, filename):
try:
df = pd.DataFrame(articles)
df.to_excel(filename, index=False)
except Exception as e:
print(f"Ошибка при записи в файл {filename}: {e}")
# Функция для логирования обработанных файлов
def log_files(file_log):
today = datetime.date.today()
log_filename = f"/home/housnimzeali/logs/scraped_files_log_{today}.txt"
with open(log_filename, 'w') as log_file:
for file_name in file_log:
log_file.write(f"{file_name}\n")
# Основная функция для скрапинга
def scrape_article(url, file_log, scraped_urls):
article_data = []
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, как Gecko) Chrome/105.0.0.0 Safari/537.36'
}
try:
page_count = 0
while True:
random_sleep(min_seconds=2, max_seconds=5)
response = requests.get(url, headers=headers)
soup = BeautifulSoup(response.text, 'html.parser')
container = soup.select_one('main#main')
if not container:
print(f"Контент не найден для URL: {url}")
return article_data
article_section = container.select_one('div.posts.publishables-list-wrap.first-item-larger')
if not article_section:
print(f"Статьи не найдены в секции для URL: {url}")
return article_data
for article in article_section.select('.row'):
title_elem = article.select_one('h3 a')
article_link = title_elem['href'] if title_elem else None
title = title_elem.get_text(strip=True) if title_elem else 'Нет названия'
summary_div = article.select_one('p.hidden-xs.item-desc')
summary = summary_div.get_text(strip=True) if summary_div else 'Нет резюме'
if article_link:
full_article_link = urljoin(url, article_link)
if full_article_link not in scraped_urls:
content, tags, date = scrap_contents_tags_date(full_article_link, headers)
article_data.append({
'Title': title,
'Date': date,
'Summary': summary,
'Content': content,
'Tags': ', '.join(tags) if tags else 'Нет тегов',
'Source': 'Medical_news',
'URL': full_article_link
})
scraped_urls.add(full_article_link)
# Сохранение извлечённых статей в файл
if article_data:
file_name = f'/home/housnimzeali/scraped_data/medical_news_{page_count + 1}.xlsx'
export_to_excel(article_data, file_name)
file_log.append(file_name)
article_data.clear()
# Поиск ссылки на следующую страницу (игнорируя "Предыдущая")
next_page = soup.select_one('div.site-paging a:contains("Следующая")')
if next_page and 'href' in next_page.attrs:
url = urljoin(url, next_page['href'])
else:
print("Нет следующей страницы, скрапинг завершён.")
break
page_count += 1
except requests.exceptions.RequestException as e:
print(f"Ошибка во время скрапинга: {e}")
return article_data
return article_data
# Основная функция
def main():
file_log = [] # Список для отслеживания файлов
scraped_urls = load_scraped_urls('/home/housnimzeali/scraped_urls.xlsx') # Загрузка уже скрапированных URL
url = "https://www.news-medical.net/medical/news" # Пример URL для скрапинга
articles = scrape_article(url, file_log, scraped_urls)
print("Скрапинг завершён.")
# Сохранение лога файлов и скрапированных URL
log_files(file_log)
save_scraped_urls(scraped_urls, '/home/housnimzeali/scraped_urls.xlsx')
# Вызов основной функции
main()
**Контекст:
**
Я настроил скрипт скрапинга, который собирает и экспортирует данные в файлы Excel.
Я хочу запланировать его для ежедневного выполнения.
Мой скрипт использует такие библиотеки, как requests, BeautifulSoup и pandas.
Я также хочу убедиться, что скрипт правильно обрабатывает дублирующиеся записи, проверяя и храня скрапированные URL.
**Мои вопросы:
**
Какой лучший способ автоматизировать ежедневное выполнение этого скрипта в среде JupyterHub и VSCode?
Должен ли я использовать инструмент, такой как cron, на сервере, где размещён JupyterHub, или существуют конкретные решения для Jupyter/VSCode?
Какие лучшие практики вы бы порекомендовали, чтобы обеспечить надёжную работу скрипта, когда он запланирован, и для обработки ошибок или перебоев?
Как я могу оптимизировать управление дубликатами в последовательных скрапингах, чтобы избежать ненужного повторения данных?
Спасибо за ваши советы и помощь.
Ответ или решение
Автоматизация ежедневного выполнения скрипта веб-скрапинга на JupyterHub и VSCode может быть реализована несколькими способами. Далее приведены рекомендации по наиболее оптимальным методам и практикам, которые помогут вам в этом процессе.
1. Автоматизация с использованием cron на сервере
Если у вас есть прямой доступ к серверу, на котором работает JupyterHub, использование cron
является одним из наиболее простых и мощных способов автоматизации выполнения скриптов:
-
Шаг 1. Откройте crontab. В терминале выполните команду:
crontab -e
-
Шаг 2. Добавьте задачу cron. Например, чтобы запланировать выполнение скрипта каждый день в 6 утра, добавьте следующую строку:
0 6 * * * /usr/bin/python3 /path/to/your/script.py
Убедитесь, что путь к Python и скрипту указан корректно. Также можно указать путь к
virtualenv
, если вы его используете. -
Шаг 3. Проверка выполнения задач. Для проверки логов выполнения можно настроить запись вывода в файл:
0 6 * * * /usr/bin/python3 /path/to/your/script.py >> /path/to/logfile.log 2>&1
2. Использование Jupyter Notebook и nbconvert
Если вы хотите запускать скрипт непосредственно из Jupyter, вы можете использовать команду nbconvert
для преобразования вашего ноутбука в исполняемый файл:
-
Шаг 1. Сохраните ваш скрипт в формате Jupyter Notebook.
-
Шаг 2. Создайте bash-скрипт для запуска вашего Jupyter Notebook:
#!/bin/bash jupyter nbconvert --to notebook --execute /path/to/your/notebook.ipynb --output-dir /path/to/output/
-
Шаг 3. Добавьте этот скрипт в cron, как описано ранее.
3. Специфичные решения для Jupyter и VSCode
Если вы используете JupyterLab, можно рассмотреть возможность установки расширений, таких как jupyterlab-scheduler
, чтобы управлять задачами внутри среды. Это позволит вам запускать задачи по расписанию прямо из Jupyter:
-
Установите нужное расширение:
jupyter labextension install jupyterlab_scheduler
-
Создайте и настройте задачи через интерфейс.
Рекомендации по надежности скрипта
-
Запись логов. В вашем коде уже реализована функция ведения логов, но стоит дополнительно записывать ошибки выполнения, чтобы их анализировать и устранять.
-
Обработка исключений. Расширьте обработку ошибок, чтобы в случае должного сбоя автоматизация могла продолжить выполнение в случае незначительных ошибок.
-
Проверка на успешность выполнения. Добавьте механизмы проверки, такие как контрольные точки или статусы, которые помогут удостовериться в том, что скрипт выполняется корректно.
Оптимизация управления дубликатами
Ваш подход к проверке уже обработанных URL записывается в Excel-файл. Чтобы повысить степень надежности:
-
Хранение в БД. Рассмотрите использование базы данных (например, SQLite или PostgreSQL) для хранения ссылок, что позволит избежать проблем с одновременной записью и чтением из файла.
-
Проверка на дубликаты. Перед добавлением новой записи проверяйте базу данных на наличие записи с аналогичным URL. Если такой URL уже есть, просто пропустите запись.
-
Индексация. Создайте индекс по URL в базе данных, что улучшит производительность при проверке.
Заключение
Выбор метода автоматизации зависит от того, какие ресурсы доступны и как вы предпочитаете организовать свои рабочие процессы. Используя cron
или инструменты автоматизации в Jupyter, вы сможете настроить автоматическое выполнение вашего веб-скрипта. Следуя рекомендациям по обработке ошибок и предотвращению дубликатов, вы сможете повысить эффективность и надежность обработки данных.