AWS Scheduled Scrape с использованием Python

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

Github repo для проекта находится здесь

Шаг 1:

Первое, что я сделал, это узнал о заданиях cron.

поэтому сейчас я установил cronjob, который будет записывать логи каждые 1 минуту. просто чтобы я мог отладить программу.

вот команда для этого:

*/1 * * * * /home/dhruv/bin/python ~/Desktop/projects/newsScraper/scraper.py >> ~/Desktop/projects/newsScraper/cron.log 2>&1
Войти в полноэкранный режим Выйти из полноэкранного режима

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

Следующим шагом будет настройка скрепера и вывод текстового файла с лучшими историями.

Шаг 2:

Я решил, что выберу все подразделы рынков и получу все их главные новости.

Пока что на выходе я получаю ссылку на новость и ее название.

import requests, random
from bs4 import BeautifulSoup  # web scraping

content = ''
urls_dict = {
    'telecom': 'https://economictimes.indiatimes.com/industry/telecom',
    'transport': 'https://economictimes.indiatimes.com/industry/transportation',
    'services': 'https://economictimes.indiatimes.com/industry/services',
    'biotech': 'https://economictimes.indiatimes.com/industry/healthcare/biotech',
    'svs': 'https://economictimes.indiatimes.com/industry/indl-goods/svs',
    'energy': 'https://economictimes.indiatimes.com/industry/energy',
    'consumer_products': 'https://economictimes.indiatimes.com/industry/cons-products',
    'finance': 'https://economictimes.indiatimes.com/industry/banking/finance',
    'automobiles': 'https://economictimes.indiatimes.com/industry/auto'
}

todays_url = random.choice(list(urls_dict.values()))
response = requests.get(todays_url)
content = response.content
soup = BeautifulSoup(content, 'html.parser')
headline_data = soup.find("ul", class_="list1")
url = 'https://economictimes.indiatimes.com'
for i, news in enumerate(headline_data.find_all("li")):
    link = '%s%s' % (url, news.a.get('href'))
    print(i+1, link, news.text, end=" n")

Вход в полноэкранный режим Выйти из полноэкранного режима

Шаг 3:

Давайте украсим это, чтобы я почувствовал себя профессионалом

import random
import requests
from bs4 import BeautifulSoup

# email content placeholder
content = ''

urls_dict = {
    'telecom': 'https://economictimes.indiatimes.com/industry/telecom',
    'transport': 'https://economictimes.indiatimes.com/industry/transportation',
    'services': 'https://economictimes.indiatimes.com/industry/services',
    'biotech': 'https://economictimes.indiatimes.com/industry/healthcare/biotech',
    'svs': 'https://economictimes.indiatimes.com/industry/indl-goods/svs',
    'energy': 'https://economictimes.indiatimes.com/industry/energy',
    'consumer_products': 'https://economictimes.indiatimes.com/industry/cons-products',
    'finance': 'https://economictimes.indiatimes.com/industry/banking/finance',
    'automobiles': 'https://economictimes.indiatimes.com/industry/auto'
}


def extract_news():
    todays_url = random.choice(list(urls_dict.values()))
    response = requests.get(todays_url)
    content = response.content
    soup = BeautifulSoup(content, 'html.parser')
    headline_data = soup.find("ul", class_="list1")

    email_body = ''

    url = 'https://economictimes.indiatimes.com'
    for i, news in enumerate(headline_data.find_all("li")):
        link = '%s%s' % (url, news.a.get('href'))
        email_body += str(i + 1) + '. ' + '<a href="' + link + '">' + news.text + '</a>' + 'nnn' + '<br />'

    return email_body
Вход в полноэкранный режим Выйти из полноэкранного режима

Шаг 4:

Я хочу внести еще немного случайности в то, что я читаю. Поэтому я решил добавить все, что я получаю, в список, перетасовать его, а затем отправить мне только 5 новостей:

def extract_news():
    todays_url = random.choice(list(urls_dict.values()))
    response = requests.get(todays_url)
    content = response.content
    soup = BeautifulSoup(content, 'html.parser')
    headline_data = soup.find("ul", class_="list1")

    email_body = ''

    email_body += 'Good Morning kiddo. Today we read Economics Times. Heres whats happening today: <br />n <br />n'

    all_news = []

    url = 'https://economictimes.indiatimes.com'
    for i, news in enumerate(headline_data.find_all("li")):
        body = ''
        link = '%s%s' % (url, news.a.get('href'))
        body += '<a href="' + link + '">' 
                + news.text + '</a>' + '<br />n' + '<br />n'
        # add items to a list
        all_news.append(body)

    # shuffle the list
    random.shuffle(all_news)

    n = 5
    # iterate over the first 5 elements of the randomized list
    for i in itertools.islice(all_news, n):
        email_body += '- ' + i

    email_body += '<br>---------------------------------<br>'
    email_body += '<br><br>Thats all for today. Byeeee'

    return email_body
Войти в полноэкранный режим Выйти из полноэкранного режима

Шаг 5:

Теперь пришло время отправлять SMTP-почту

Google изменил свою политику, поэтому я перешел сюда и перенастроил параметры своей учетной записи

https://support.google.com/accounts/answer/6010255?hl=en-GB&visit_id=637970887869842501-2539226343&p=less-secure-apps&rd=1

после этого я сохранил свой пароль в файле .env и —.

import os
from dotenv import load_dotenv
import smtplib

# email body
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
# system date and time manipulation
import datetime

now = datetime.datetime.now()
load_dotenv()


def send_mail(news_body):
    SERVER = 'smtp.gmail.com'
    PORT = 587
    FROM = 'homesanct@gmail.com'
    TO = 'dhrvmohapatra@gmail.com'
    PASSWORD = os.getenv('password')

    msg = MIMEMultipart()
    msg['Subject'] = 'Good Morning Champ' + ' ' + str(now.day) + '-' + str(now.month) + '-' + str(
        now.year)
    msg['From'] = FROM
    msg['To'] = TO
    msg.attach(MIMEText(news_body, 'html'))

    print('initializing server')

    server = smtplib.SMTP(SERVER, PORT)
    server.set_debuglevel(1)
    server.ehlo()
    server.starttls()
    server.login(FROM, PASSWORD)
    server.sendmail(FROM, TO, msg.as_string())

    print('Email Sent...')

    server.quit()
Вход в полноэкранный режим Выйти из полноэкранного режима

Шаг 5:

Я закончил с классическим pypy

if __name__ == "__main__":
    data = extract_news()
    send_mail(data)
Войти в полноэкранный режим Выйти из полноэкранного режима

Шаг 6:

И последнее, но не менее важное: мне нужно было настроить правильный cronjob.

Я изменил местоположение проекта, поэтому все немного изменилось, но теперь я буду получать случайную выборку новостей из Economics Times в 6:55 утра в понедельник и четверг!

55 6 * * 1,4 /home/dhruv/Desktop/projects/toolbox/newsScraper/venv/bin/python ~/Desktop/projects/toolbox/newsScraper/newsReader01.py
Вход в полноэкранный режим Выход из полноэкранного режима

Я также писал скрипты для Times Of India и Reuters, но это было бы излишне добавлять сюда.

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

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

Затем пришло время загрузить скрипт…

и все рухнуло

около 100 раз

пока я, наконец, не разобрался. В общем,

вот шаги.

Шаг 7:

Сначала войдите в AWS

затем откройте Lambda

затем нажмите Create Function

введите имя функции, выберите python runtime

и создайте функцию

Шаг 8:

После того как функция создана, прокрутите вниз до окна источника кода и немного отредактируйте наш предыдущий код, чтобы он соответствовал шаблону AWS

import json
import random
import requests
from bs4 import BeautifulSoup
import os
import smtplib
import itertools

# email body
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
# system date and time manipulation
import datetime

now = datetime.datetime.now()

def lambda_handler(event, context):
    # email content placeholder
    content = ''

    urls_dict = {
        'telecom': 'https://economictimes.indiatimes.com/industry/telecom',
        'transport': 'https://economictimes.indiatimes.com/industry/transportation',
        'services': 'https://economictimes.indiatimes.com/industry/services',
        'biotech': 'https://economictimes.indiatimes.com/industry/healthcare/biotech',
        'svs': 'https://economictimes.indiatimes.com/industry/indl-goods/svs',
        'energy': 'https://economictimes.indiatimes.com/industry/energy',
        'consumer_products': 'https://economictimes.indiatimes.com/industry/cons-products',
        'finance': 'https://economictimes.indiatimes.com/industry/banking/finance',
        'automobiles': 'https://economictimes.indiatimes.com/industry/auto'
    }


    def extract_news():
        todays_url = random.choice(list(urls_dict.values()))
        response = requests.get(todays_url)
        content = response.content
        soup = BeautifulSoup(content, 'html.parser')
        headline_data = soup.find("ul", class_="list1")

        email_body = ''

        email_body += 'Good Morning kiddo. Today we read Economics Times: <br />n <br />n'

        all_news = []

        url = 'https://economictimes.indiatimes.com'
        for i, news in enumerate(headline_data.find_all("li")):
            body = ''
            link = '%s%s' % (url, news.a.get('href'))
            body += '<a href="' + link + '">' 
                    + news.text + '</a>' + '<br />n' + '<br />n'
            # add items to a list
            all_news.append(body)

        # shuffle the list
        random.shuffle(all_news)

        n = 3
        # iterate over the first 5 elements of the randomized list
        for i in itertools.islice(all_news, n):
            email_body += '- ' + i

        email_body += '<br>---------------------------------<br>'
        email_body += '<br><br>Thats all for today. Byeeee'

        return email_body

    def send_mail(news_body):
        SERVER = 'smtp.gmail.com'
        PORT = 587
        FROM = 'homesanct@gmail.com'
        TO = 'dhrvmohapatra@gmail.com'
        PASSWORD = os.environ.get('password')

        msg = MIMEMultipart()
        msg['Subject'] = 'Economic Times' + ' ' + str(now.day) + '-' + str(now.month) + '-' + str(
            now.year)
        msg['From'] = FROM
        msg['To'] = TO
        msg.attach(MIMEText(news_body, 'html'))

        print('initializing server')

        server = smtplib.SMTP(SERVER, PORT)
        server.set_debuglevel(1)
        server.ehlo()
        server.starttls()
        server.login(FROM, PASSWORD)
        server.sendmail(FROM, TO, msg.as_string())

        print('Email Sent...')

        server.quit()

    news_body = extract_news()
    send_mail(news_body)
Войдите в полноэкранный режим Выйдите из полноэкранного режима

сохраните и нажмите test, чтобы проверить код.

Появится окно конфигурации тестового события.

Дайте новому событию имя и сохраните его.

Запустите функцию снова, и она выдаст ошибку

потому что не хватает двух вещей

Шаг 9:

Первое, чего не хватает, это пароля в переменных окружения.

мы добавим его, перейдя на вкладку конфигурации и добавив переменную окружения здесь

Следующее, чего не хватает — это все пакеты, необходимые для скриптинга. Requests и BeautifulSoup просто живут в облаке AWS, поэтому нам нужно добавить их в наш проект.

Это тоже заняло некоторое время, чтобы разобраться.

Вот мое решение

Шаг 10:

Я перешел в каталог, в котором локально был написан мой проект, и создал каталог с именем packages.

все еще находясь в директории проекта, я открыл терминал и выполнил команду

$ pip install -t packages requests
$ pip install -t packages beautifulsoup4
Войти в полноэкранный режим Выйти из полноэкранного режима

теперь я скопировал код из источника кода AWS и создал новый файл в каталоге ‘packages’, назвав его lambda_function.py

теперь мы готовы.

Я нажал Ctrl+A, чтобы выделить все и сжать в zip-папку.

В консоли AWS Lambda есть опция Upload From (прямо над IDE). Загрузите эту zip-папку. Теперь вы видите следующее

Шаг 11:

Теперь, когда я нажал кнопку проверки, в моем почтовом ящике появилось сообщение
WOOHOO

Но оставалось еще кое-что.

Мне нужно было автоматизировать эту задачу

Поэтому перейдем к Amazon EventBridge.

здесь в подменю Rules я создал новое правило

Теперь я вернулся в консоль AWS Lambdas и увидел, что триггер EventBridge был добавлен к моей функции. Сладкий соус.

Время для последнего шага

Шаг 12:

Нажмите Deploy.

Последнее замечание для любопытных: журналы всех функций можно посмотреть в консоли Amazon CloudWatch Console

аааа… это было все. Мне нужно узнать о docker и прочем, потому что я слышал, что загрузка изображений намного более плавная, так что, возможно, я потрачу некоторое время на это.

Также, надеюсь, читать новости будет так же весело, как и создавать этот проект ✌️

Оцените статью
devanswers.ru
Добавить комментарий