Задать вопрос
@roman_tonkoshkurov

Как считать ID для статей?

Доброго времени суток.

Есть небольшой скрипт, который парсит новостной сайт и в JSON файл складывает новости. Проблема у меня в ID. Сейчас я их получаю из времени (убираю все символы и оставляю только числа и получается в итоге 202116061234). Это очень громоздко и я хочу просто получать ID с 0, и на каждую статья прибавлять по 1.

В первый раз проблем не возникает, статьям присваивается с 0. Но проблема у меня лично возникает при проверке на обновления. Как мне подтянуть самый последний ID, присвоить переменной номер и уже от неё плясать?

Прошу помощи. В Python у меня ну прям самый начальный уровень. Данный скрипт был взят из видео и переделан под себя.

Ниже листинг под спойлером.

test.py

import requests
from bs4 import BeautifulSoup
from datetime import datetime
import time
import json

headers = {
    # Paste User-Agent
}

url = "https://www.irk.ru/news/"
r = requests.get(url=url, headers=headers)
soup = BeautifulSoup(r.text, "lxml")
articles_cards = soup.find_all("li", class_="b-news-article-list-item")


# Функция получения новостей в первый раз
# Новости с сайта irk.ru
def get_first_news_irk():
    # Словарь для новостей с сайта irk.ru
    irk_news_dict = {}

    # Хочу ID присваивать с 0, что у каждой новости был понятный ID
    ids = 0

    for article in articles_cards:
        # Получаем заголовки новостей
        article_title = article.find("a").text.strip()
        # Получаем описание новостей
        article_desc = article.find("p").text.strip()
        # Получаем url новостей
        article_url = f'https://www.irk.ru{article.find("a").get("href")}'

        # Получаем время новостей
        article_date_time = article.find("time").get("datetime")
        # Преобразовываем время
        date_from_iso = datetime.fromisoformat(article_date_time)
        date_time = datetime.strftime(date_from_iso, "%Y-%m-%d %H:%M:%S")
        article_date_timestamp = time.mktime(datetime.strptime(date_time, "%Y-%m-%d %H:%M:%S").timetuple())

        # Делаем ID из даты новости
        # article_id = "".join(
        #     [article_date_time[i] for i in range(len(article_date_time)) if article_date_time[i] in '0123456789']
        # )

        # На каждой итерации заполняем словарь новостей
        # irk_news_dict[article_id] = {
        #     "article_date_timestamp": article_date_timestamp,
        #     "article_title": article_title,
        #     "article_url": article_url,
        #     "article_desc": article_desc
        # }

        irk_news_dict[ids] = {
            "article_date_timestamp": article_date_timestamp,
            "article_title": article_title,
            "article_url": article_url,
            "article_desc": article_desc
        }

        ids += 1

        # Записываем результат в json файл
        with open("src/test_dict.json", "w") as file:
            json.dump(irk_news_dict, file, indent=4, ensure_ascii=False)


# Функция для проверки на появление новых новостей
def check_irk_news_update():
    with open("src/test_dict.json") as file:
        irk_news_dict = json.load(file)

    # Словарь для заполнения свежими новостями
    irk_fresh_news_dict = {}
    for k, v in irk_news_dict.items():
        ids = k
    for article in articles_cards:
        article_date_time = article.find("time").get("datetime")

        # Делаем ID из даты новости
        # Глупое решение, пока не придумал чем заменить
        # article_id = "".join(
        #     [article_date_time[i] for i in range(len(article_date_time)) if article_date_time[i] in '0123456789']
        # )

        # Если id уже есть в подгружаемом словаре, то пропускаем
        # Иначе добавляем новую новость в новый словарь со свежими новостями
        # И записываем свежие новости в JSON файл
        if ids in irk_news_dict:
            continue
        else:
            article_url = f'https://www.irk.ru{article.find("a").get("href")}'

            article_title = article.find("a").text.strip()
            article_desc = article.find("p").text.strip()

            article_date_time = article.find("time").get("datetime")
            date_from_iso = datetime.fromisoformat(article_date_time)
            date_time = datetime.strftime(date_from_iso, "%Y-%m-%d %H:%M:%S")
            article_date_timestamp = time.mktime(datetime.strptime(date_time, "%Y-%m-%d %H:%M:%S").timetuple())

            irk_news_dict[ids] = {
                "article_date_timestamp": article_date_timestamp,
                "article_title": article_title,
                "article_url": article_url,
                "article_desc": article_desc
            }

            irk_fresh_news_dict[ids] = {
                "article_date_timestamp": article_date_timestamp,
                "article_title": article_title,
                "article_url": article_url,
                "article_desc": article_desc
            }

            ids += 1

    # Записываем результат в json файл
    with open("src/test_dict.json", "w") as file:
        json.dump(irk_news_dict, file, indent=4, ensure_ascii=False)

    # Функция возвращает словарь со свежими новостями
    return irk_fresh_news_dict


def main():
    # 1я функция вызывается единожды для получения новостей
    # get_first_news_irk()
    # 2я функция проверяет обновления на сайте
    # Если новости нет в json то добавляет в словарь и выводит на печать
    print(check_irk_news_update())


if __name__ == '__main__':
    main()

  • Вопрос задан
  • 140 просмотров
Подписаться 1 Простой Комментировать
Решения вопроса 1
Я бы исходил из источника: у них статья идентифицируется датой и коротким словом (slag): например, /news/20210619/party/ – тут «ключ» статьи 20210619/party – почему бы и вам не брать это как уникальный ключ. К тому же, лексикографическая сортировка расставит статьи в хронологическом порядке, по датам.

При следующем запуске смотрите, за какую самую последнюю дату уже есть скачанные материалы. И далее тащить, начиная с этого же дня. Пропускать или перезаписывать уже имеющиеся статьи этого дня.
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
danila763
@danila763
Учу python, sql
Тут проблема в том, что когда вы запускаете скрипт повторно, он создаёт у старых новостей id по их дате и проверяет по нему есть ли новость в словаре. Конечно можно каждый раз при запуске скрипта продолжать id по порядку (как вы и хотите), но тогда как проверить, есть ли новость уже в словаре?

Мой вариант вашего кода, упрощенный

import requests
from bs4 import BeautifulSoup
import json


headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36',
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'
}

def get_news_info(card):
    """
    Функция для получения информации об одной новости
    """

    # Получаем заголовки новости
    article_title = card.find("a").text.strip()

    # Получаем описание новости
    article_desc = card.find("p").text.strip()

    # Получаем url новости
    article_url = f'https://www.irk.ru{card.find("a").get("href")}'

    # Получаем время новости
    article_date_time = card.find("time").get("datetime")

    id = article_date_time.replace(' ', '').replace('-', '').replace(':', '')

    news = {
            "article_date_timestamp": article_date_time,
            "article_title": article_title,
            "article_url": article_url,
            "article_desc": article_desc
        }

    return (id, news)


def get_site_news(file_news_dict, articles_cards):
    """
    Функция для добавления новых новостей в словарь,
    возвращает словари со всеми новостями и с новыми новостями
    """

    new_news_dict = dict()

    for article in articles_cards:

        id, news = get_news_info(article)

        if id not in file_news_dict.keys():

            file_news_dict[id] = news

            new_news_dict[id] = news

    return (file_news_dict, new_news_dict)



def main():
    url = "https://www.irk.ru/news/"
    r = requests.get(url=url, headers=headers)
    soup = BeautifulSoup(r.text, "lxml")
    articles_cards = soup.find_all("li", class_="b-news-article-list-item")

    # Открываем файл с новостями
    with open("src/test_dict.json", "r+") as news_file:

        # Получаем словарь новостей из файла
        try:
            file_news_dict = json.load(news_file)
        except:
            # Если в файле не словарь, создаем пустой словарь
            file_news_dict = dict()

        # Обновляем новости
        file_news_dict, new_news_dict = get_site_news(file_news_dict, articles_cards)

        # Сохраняем новости
        json.dump(file_news_dict, news_file, indent=4, ensure_ascii=False)

        print(new_news_dict)


if __name__ == '__main__':
    main()

Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы