<jupyter_start><jupyter_text>Написать приложение, которое собирает основные новости с сайтов mail.ru, lenta.ru, yandex.newsДля парсинга использовать xpath. Структура данных должна содержать:* название источника,* наименование новости,* ссылку на новость,* дата публикации<jupyter_code>from pymongo import MongoClient
from pymongo import ASCENDING
from pymongo import DESCENDING
from hashlib import md5
from pprint import pprint
from lxml import html
from datetime import datetime, timedelta
import requests
import json
import time
import random
import re
def initDB(name):
    client = MongoClient('localhost', 27017)
    return client[name]
def saveRow(row, client):
    collection = client['news']
    collection.insert_one(row)
def printRows(client, limit=10):
    collection = client['news']
    for item in collection.find().limit(limit):
        pprint(item)
def getRoot(url):
    uagent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36"
    root = None
    try:
        root = html.fromstring(requests.get(url, headers = {'user-agent': uagent}).text)
    except Exception as e:
        print(e)
    return root
def getFromMailPage(url):
    page = getRoot(url)
    article = page.xpath("//div[contains(@class, 'breadcrumbs')]")
    date = None
    source = None
    if len(article) > 0:
        article = article[0]
        date = article.xpath(".//span[@datetime]/@datetime")
        if len(date) > 0:
            date = date[0]
            date = datetime.strptime(date, "%Y-%m-%dT%H:%M:%S%z")
        else:
            date = None
        source = article.xpath(".//span[@class='link__text']/text()")
        if len(source) > 0:
            source = source[0]
        else:
            source = None
    return { 'date': date, 'source': source }
def loadFromMail(db):
    print('LOADING FROM MAIL.RU...')
    mailru = getRoot('https://mail.ru/?from=m')
    news_block = mailru.xpath("//a[@class='list__item']")
    for item in news_block:
        href = item.xpath("./@href")
        if len(href) > 0:
            href = href[0]
        else:
            href = None
        title = item.xpath(".//span[@class='list__item__title']/text()")
        if len(title) > 0:
            title = title[0]
            title = title.replace('\xa0', ' ')
        row = { 'title': title, 'url': href }
        if href:
            tmp = getFromMailPage(href)
            row['date'] = tmp['date']
            row['source'] = tmp['source']
            time.sleep(random.randint(1, 2))
        saveRow(row, db)
    print('LOADED')
def getFromLentaPage(url):
    page = getRoot(url)
    header = page.xpath("//div[contains(@class, 'b-topic__header')]")
    if len(header) > 0:
        header = header[0]
    else:
        return { 'date': None, 'title': None, 'source': 'lenta.ru', 'url': url }
    date = header.xpath(".//div[contains(@class,'b-topic__info')]/time[@datetime]/@datetime")
    if len(date) > 0:
        date = date[0]
        date = datetime.strptime(date, "%Y-%m-%dT%H:%M:%S%z")
    else:
        date = None
    title = header.xpath(".//*[contains(@itemprop, 'headline')]/text()")
    if len(title) > 0:
        title = title[0]
        title = title.replace('\xa0', ' ')
    else:
        title = None
    return { 'date': date, 'title': title, 'source': 'lenta.ru', 'url': url }
def loadFromLenta(db):
    print('LOADING FROM LENTA...')
    lenta = getRoot('https://lenta.ru')
    pages = lenta.xpath("//div[contains(@class,'item')]/a[contains(@href,'news')]/@href")
    pages = map(lambda item: f'https://lenta.ru{item}', pages)
    for page in pages:
        row = getFromLentaPage(page)
        saveRow(row, db)
        time.sleep(random.randint(1,2))
    print('LOADED')
def getDateAndSource(substring):
    match = re.search(r'вчера.+', substring)
    date = None
    source = None
    if match:
        source = re.sub(r'вчера.+', '', substring)
        date = match.group()
        date = re.search(r'\d{2}:\d{2}', date)
        date = date.group()
        date = f"{datetime.strftime(datetime.now() - timedelta(1), '%Y-%m-%d')}T{date}:00+03:00"
        date = datetime.strptime(date, "%Y-%m-%dT%H:%M:%S%z")
    else:
        match = re.search(r'\d{1,2}.+\d{2}:\d{2}', substring)
        if match:
            source = re.sub(r'\d{1,2}.+\d{2}:\d{2}', '', substring)
            date = match.group()
            mlist = [ 'января', 'февраля','марта','апреля',
                     'мая', 'июня','июля','августа',
                     'сентрября','октября','ноября','декабря' ]
            month = 1
            for m in mlist:
                if re.search(m, date):
                    break
                month += 1
            day = re.search(r'^\d{1,2}', date).group()
            if int(day) < 10:
                day = f'0{day}'
            if month < 10:
                month = f'0{month}'
            year = datetime.strftime(datetime.now(), '%Y')
            dtime = re.search(r'\d{2}:\d{2}$', date).group()
            dtime = f'{dtime}:00+03:00'
            date = f'{year}-{month}-{day}T{dtime}'
        else:
            source = re.sub(r'\d{2}:\d{2}', '', substring)
            dtime = re.search(r'\d{2}:\d{2}', substring).group()
            hour =  re.search(r'^\d{2}', dtime).group()
            minute =  re.search(r'\d{2}$', dtime).group()
            now = datetime.now()
            now.replace(minute=int(minute))
            now.replace(hour=int(hour))
            date = now
    return { 'source': source, 'date': date }
def getFromYandexItem(item):
    title = item.xpath(".//*[@class='story__title']")
    if len(title) > 0:
        title = title[0]
    else:
        return None
    href = title.xpath(".//a[contains(@class,'link')]/@href")
    if len(href) > 0:
        href = href[0]
        href = f'https://yandex.ru{href}'
    text = title.xpath(".//a[contains(@class,'link')]/text()")
    if len(text) > 0:
        text = text[0]
    src = item.xpath(".//div[@class='story__date']/text()")
    source = None
    date = None
    if len(src) > 0:
        src = getDateAndSource(src[0])
        source = src['source']
        date = src['date']
    return { 'date': date, 'title': text, 'source': source, 'url': href }
def loadFromYandex(db):
    print('LOADING FROM YANDEX...')
    yandex = getRoot('https://yandex.ru/news')
    items = yandex.xpath("//*[@class='stories-set__item']")
    for item in items:
        row = getFromYandexItem(item)
        saveRow(row, db)
    print('LOADED')
client = initDB('news')
loadFromYandex(client)
loadFromLenta(client)
loadFromMail(client)<jupyter_output>LOADING FROM MAIL.RU...
LOADED<jupyter_text>Проверим что все загрузилось в БД:<jupyter_code>printRows(client, 5)<jupyter_output>{'_id': ObjectId('5e1a52c3f40bd4b52ad00abb'),
 'date': datetime.datetime(2020, 1, 12, 1, 57, 7, 84000),
 'source': 'Вести.Ru ',
 'title': 'Маршал Хафтар объявил о прекращении боевых действий в Ливии',
 'url': 'https://yandex.ru/news/story/Marshal_KHaftar_obyavil_o_prekrashhenii_boevykh_dejstvij_v_Livii--000398f40637e7583a7033afca9d27d4?lr=213&lang=ru&stid=r9l56MIjaMKhTLn0PanL&persistent_id=84548103&rubric=index&from=index'}
{'_id': ObjectId('5e1a52c3f40bd4b52ad00abc'),
 'date': datetime.datetime(2020, 1, 12, 1, 57, 7, 101000),
 'source': 'Известия ',
 'title': 'Турчинов призвал наказать Россию за сбитый в Иране Boeing',
 'url': 'https://yandex.ru/news/story/Turchinov_prizval_nakazat_Rossiyu_za_sbityj_v_Irane_Boeing--8f4f999ed3c05a1c4801247da2acea20?lr=213&lang=ru&stid=9yoYR6dBsA9OLgUKEKXp&persistent_id=84517637&rubric=index&from=index'}
{'_id': ObjectId('5e1a52c3f40bd4b52ad00abd'),
 'date': datetime.datetime(2020, 1, 12, 1, 57, 7, 102000),
 'source': 'РИА Новости ',
 'title': 'Зеленски[...]<jupyter_text>**Всего записей:**<jupyter_code>collection = client['news']
print(collection.count_documents({}))<jupyter_output>119<jupyter_text>**Посмотрим что в вдругих записях, сделав сортировку по дате:**<jupyter_code>for item in collection.find().sort('date', ASCENDING).limit(15):
    pprint(item)<jupyter_output>{'_id': ObjectId('5e1a5304f40bd4b52ad00b21'),
 'date': None,
 'source': None,
 'title': '3 удивительных примера использования Microsoft Excel',
 'url': 'https://r.mail.ru/n318027693?&test_id=63&rnd=716408491'}
{'_id': ObjectId('5e1a5306f40bd4b52ad00b22'),
 'date': None,
 'source': None,
 'title': 'Новинка Apple удивит возможностями',
 'url': 'https://r.mail.ru/n318027694?&test_id=63&rnd=716408491'}
{'_id': ObjectId('5e1a5308f40bd4b52ad00b23'),
 'date': None,
 'source': None,
 'title': 'Почему борьба за экологию — сплошной фейк',
 'url': 'https://r.mail.ru/n317956428?&test_id=63&rnd=716408491'}
{'_id': ObjectId('5e1a530af40bd4b52ad00b24'),
 'date': None,
 'source': None,
 'title': 'Новый топовый Xiaomi полностью раскрыт',
 'url': 'https://r.mail.ru/n317955908?&test_id=63&rnd=716408491'}
{'_id': ObjectId('5e1a530bf40bd4b52ad00b25'),
 'date': None,
 'source': None,
 'title': '«Качельки» громкости уходят в прошлое. Что придет на замену',
 'url': 'https://r.mail.ru/n317932675?&test_id=63&rn[...]
{'fraction_non_alphanumeric': 0.17498622589531682, 'fraction_numerical': 0.047933884297520664, 'mean_word_length': 3.1160997732426305, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 25, 'https://': 12, 'lorem ipsum': 0, 'www.': 0, 'xml': 1}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '4', 'dir': 'jupyter-structured-clean-dedup', 'id': '229344', 'license': 'Unlicense', 'n_tokens_mistral': 3651, 'n_tokens_neox': 3477, 'n_words': 636, 'path': 'homework04.ipynb', 'repo_name': 'Selen34/scraping', 'size': '9075'}