Explore o novo chatbot do Developer Center! O MongoDB AI chatbot pode ser acessado na parte superior da sua navegação para responder a todas as suas perguntas sobre o MongoDB .

Saiba por que o MongoDB foi selecionado como um líder no 2024 Gartner_Magic Quadrupnt()
Desenvolvedor do MongoDB
Central de desenvolvedor do MongoDBchevron-right
Produtoschevron-right
Atlaschevron-right

Raspador da web da bolsa de valores de Nairóbi

Kennedy Mwaura19 min read • Published May 09, 2023 • Updated Apr 02, 2024
AtlasPython
APLICATIVO COMPLETO
Ícone do FacebookÍcone do Twitterícone do linkedin
Avalie esse Tutorial
star-empty
star-empty
star-empty
star-empty
star-empty
Procurando construir um web scraper usando Python e MongoDB para a Bolsa de Valores de Nairobi? Nosso tutorial abrangente fornece um guia passo a passo sobre como configurar o ambiente de desenvolvimento, criar um spider Scrapy, analisar o site e armazenar os dados no MongoDB.
Também abordamos práticas recomendadas para trabalhar com MongoDB e dicas para solucionar problemas comuns. Além disso, dê uma olhada no uso do MongoDB Atlas para Atlas Charts. Por fim, ative as notificações de texto usando a API Africas Talking (sinta-se à vontade para mudar para o seu provedor preferido). Obtenha todo o código no Github e simplifique seu fluxo de trabalho hoje mesmo!

Pré-requisitos

Foi verificado que os pré-requisitos abaixo funcionam no Linux. A implementação em outros sistemas operacionais pode ser diferente. Por gentileza, verifique as instruções de instalação.

Sumário

  • O que é web scraping?
  • Layout do projeto
  • Configuração do projeto
  • Iniciando um projeto Scrapy
  • Criando uma aranha
  • Executando o scraper
  • Ativando alertas de texto
  • Dados no MongoDB Atlas
  • Gráficos no MongoDB Atlas
  • CI/CD com ações do GitHub
  • Conclusão

O que é web scraping?

Web scraping é o processo de extração de dados de sites. É uma forma de mineração de dados, que automatiza a recuperação de dados da web. A raspagem da Web é uma técnica para acessar e extrair automaticamente grandes quantidades de informações de um site ou plataforma, o que pode economizar muito tempo e esforço. Você pode salvar esses dados localmente em seu computador ou em um banco de dados na nuvem.

O que é o Scrapy?

O Scrapy é um framework de rastreamento da web gratuito e de código aberto escrito em Python. Ele extrai os dados de que você precisa de sites de forma rápida, simples, mas extensível. Ele pode ser usado para uma ampla variedade de fins, desde coleta de dados até monitoramento e testes automatizados.

O que é o MongoDB Atlas?

MongoDB Atlas é uma plataforma de banco de dados em nuvem totalmente gerenciada que hospeda seus dados na AWS, GCPou Azure. É um banco de dados totalmente gerenciado como serviço (DBaaS) que fornece uma infraestrutura de banco de dados altamente disponível, distribuída globalmente e escalável. Leia nosso tutorial para começar a usar uma instância gratuita do MongoDB Atlas.
Você também pode acessarDocs para saber mais sobre como limitar o acesso ao seu cluster a IP especificados. Esta etapa aumenta a segurança seguindo as melhores práticas.

Layout do projeto

Abaixo está um diagrama que fornece uma visão geral de alto nível do projeto.
Uma visualização do diagrama do projeto
O diagrama acima mostra como o projeto é executado, bem como a estrutura geral. Vamos detalhá-lo:
  • O projeto Scrapy (spiders) rastreia os dados do site afx (portal de dados para dados de ações).
  • Como o Scrapy é uma estrutura completa, nós o usamos para extrair e limpar os dados.
  • Os dados são enviados para o MongoDB Atlas para armazenamento.
  • A partir daqui, podemos conectá-lo facilmente ao MongoDB Charts para visualizações.
  • Empacotamos nosso raspador da web usando o Docker para facilitar a implantação na nuvem.
  • O código é hospedado no GitHub e criamos um pipeline CI/CD usando ações do GitHub.
  • Por fim, temos um script de notificação de texto que é executado quando as condições definidas são atendidas.

Configuração do projeto

Vamos configurar nosso projeto. Primeiro, criaremos um novo diretório para nosso projeto. Abra seu terminal e navegue até o diretório onde deseja criar o projeto. Em seguida, execute o seguinte comando para criar um novo diretório e alterá-lo.
1mkdir nse-stock-scraper && cd nse-stock-scraper
Em seguida, criaremos um ambiente virtual para nosso projeto. Isso nos ajudará a isolar as dependências do nosso projeto do resto do nosso sistema. Execute o comando a seguir para criar um ambiente virtual. Estamos usando o módulo Ppython venvincorporado para criar o ambiente virtual. Ative o ambiente virtual executando o script activateno diretóriobin.
1python3 -m venv venv
2source venv/bin/activate
Agora, instalaremos as dependências necessárias. Usaremos opip para instalar as dependências. Execute o seguinte comando para instalar as dependências necessárias:
1pip install scrapy pymongo[srv] dnspython python-dotenv beautifulsoup4
2pip freeze > requirements.txt

Iniciando um projeto Scrapy

Scrapy é um framework completo. Assim, tem uma visão opinativa sobre a estrutura de seus projetos. Ele vem com uma ferramenta CLI para começar rapidamente. Agora, iniciaremos um novo projeto Scrapy. Execute o seguinte comando.
1scrapy startproject nse_scraper .
Isso criará um novo diretório com o nome nse_scraper e alguns arquivos. O diretórionse_scraper é o pacote Python real para nosso projeto. Os arquivos são os seguintes:
  • items.py - Esse arquivo contém a definição dos itens que serão extraídos.
  • middlewares.py — Este arquivo contém a definição dos middlewares que usaremos.
  • pipelines.py — Contém a definição dos pipelines que usaremos.
  • settings.py — Contém a definição das configurações que usaremos.
  • spiders — Este diretório contém os spiders que usaremos.
  • scrapy.cfg — Este arquivo contém a configuração do projeto.

Criando uma aranha

Uma aranha é uma classe que define como um determinado site será raspado. Ela deve subclassificar scrapy.Spider e definir as solicitações iniciais a serem feitas — e, opcionalmente, como seguir os links nas páginas e analisar o conteúdo da página baixada para extrair dados.
Vamos criar uma aranha para raspar o siteafx. Execute o comando a seguir para criar um spider. Mude para a pastanse_scraperque está dentro da nossa pasta raiz.
1cd nse_scraper
2scrapy genspider afx_scraper afx.kwayisi.org
Isso criará um novo arquivo afx_scraper.py no diretóriospiders. Abra o arquivo e substitua o conteúdo pelo seguinte código:
1from scrapy.settings.default_settings import CLOSESPIDER_PAGECOUNT, DEPTH_LIMIT
2from scrapy.spiders import CrawlSpider, Rule
3from bs4 import BeautifulSoup
4from scrapy.linkextractors import LinkExtractor
5
6
7class AfxScraperSpider(CrawlSpider):
8 name = 'afx_scraper'
9 allowed_domains = ['afx.kwayisi.org']
10 start_urls = ['https://afx.kwayisi.org/nse/']
11 user_agent = 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36'
12 custom_settings = {
13 DEPTH_LIMIT: 1,
14 CLOSESPIDER_PAGECOUNT: 1
15 }
16
17 rules = (
18 Rule(LinkExtractor(deny='.html', ), callback='parse_item', follow=False),
19 Rule(callback='parse_item'),
20 )
21
22 def parse_item(self, response, **kwargs):
23 print("Processing: " + response.url)
24 # Extract data using css selectors
25 row = response.css('table tbody tr ')
26 # use XPath and regular expressions to extract stock name and price
27 raw_ticker_symbol = row.xpath('td[1]').re('[A-Z].*')
28 raw_stock_name = row.xpath('td[2]').re('[A-Z].*')
29 raw_stock_price = row.xpath('td[4]').re('[0-9].*')
30 raw_stock_change = row.xpath('td[5]').re('[0-9].*')
31
32 # create a function to remove html tags from the returned list
33 def clean_stock_symbol(raw_symbol):
34 clean_symbol = BeautifulSoup(raw_symbol, "lxml").text
35 clean_symbol = clean_symbol.split('>')
36 if len(clean_symbol) > 1:
37 return clean_symbol[1]
38 else:
39 return None
40
41 def clean_stock_name(raw_name):
42 clean_name = BeautifulSoup(raw_name, "lxml").text
43 clean_name = clean_name.split('>')
44 if len(clean_name[0]) > 2:
45 return clean_name[0]
46 else:
47 return None
48
49 def clean_stock_price(raw_price):
50 clean_price = BeautifulSoup(raw_price, "lxml").text
51 return clean_price
52
53 # Use list comprehension to unpack required values
54 stock_name = [clean_stock_name(r_name) for r_name in raw_stock_name]
55 stock_price = [clean_stock_price(r_price) for r_price in raw_stock_price]
56 ticker_symbol = [clean_stock_symbol(r_symbol) for r_symbol in raw_ticker_symbol]
57 stock_change = [clean_stock_price(raw_change) for raw_change in raw_stock_change]
58 if ticker_symbol is not None:
59 cleaned_data = zip(ticker_symbol, stock_name, stock_price)
60 for item in cleaned_data:
61 scraped_data= {
62 'ticker_symbol': item[0],
63 'stock_name': item[1],
64 'stock_price': item[2],
65 'stock_change': stock_change }
66 # yield info to scrapy
67 yield scraped_data
Vamos decompor o código acima. Primeiro, importamos os módulos e classes necessários. Em nosso caso, usaremos _CrawlSpider _and Rule de scrapy.spiders e LinkExtractor de scrapy.linkextractors. Também usaremos o prettySoup da bs4 para limpar os dados raspados.
A classeAfxScraperSpiderherda da CrawlSpider, que é uma subclasse da Spider. A classe Spider é o núcleo do Scrapy. Ela define como um determinado site (ou um grupo de sites) será extraído. Ela contém uma lista inicial de URLs para download e regras para seguir links nas páginas e extrair dados delas. Neste caso, usaremos o CrawlSpider para rastrear o site e seguir os links para a próxima página.
O atributo name define o nome do spider. Esse nome deve ser exclusivo dentro de um projeto — ou seja, você não pode definir o mesmo nome para spiders diferentes. Ele será usado para identificar o spider quando você o executar na linha de comando.
O atributo allowed_domains é uma lista de domínios que esse spider tem permissão para rastrear. Se não for especificado, nenhuma restrição de domínio será aplicada. Isso é útil se você quiser restringir o rastreamento a um domínio específico (ou subdomínio) enquanto raspa vários domínios no mesmo projeto. Você também pode usá-lo para evitar o rastreamento do mesmo domínio várias vezes ao usar vários spiders.
O atributo start_urls é uma lista de URL de onde o spider começará a rastrear. Quando nenhum start_URLs for definido, as URL iniciais serão lidas do arquivo sitemap.xml (se existir) do primeiro domínio na lista allow_domains. Se você não quiser começar a partir de um mapa do site, poderá definir uma URL inicial neste atributo. Este atributo é opcional e pode ser omitido.
O atributo user_agent é usado para definir o agente do usuário para o spider. Isso é útil quando você deseja fazer o scraping de um site que bloqueia spiders que não têm um agente de usuário. Neste caso, usaremos um agente de usuário para o Chrome. Também podemos definir o agente de usuário no arquivo settings.py. Isso é fundamental para dar ao site de destino a ilusão de que somos um navegador real.
O atributo custom_settings é usado para definir configurações personalizadas para o indexador. Nesse caso,definiremos DEPTH_LIMIT como 1 e Closespider_PAGECOUNT como 1. O atributo DEPTH_LIMIT limita a profundidade máxima que será permitido rastrear para qualquer site. Profundidade refere-se ao número de página(s) que a indexação pode rastrear. O atributo CLOSESPIDER_PAGECOUNT é usado para fechar a aranha após rastrear o número especificado de páginas.
O atributo rules define as regras para a aranha. Usaremos a classe Rule para definir as regras para extrair links de uma página e processá-los com um retorno de chamada ou segui-los e copiá-los usando outra aranha.
A classe Rule usa um objeto LinkExtractor como primeiro argumento. A classe LinkExtractor é usada para extrair links de páginas da web. Ele pode extrair links que correspondam a expressões regulares específicas ou que usem atributos específicos, como href ou src.
O argumento deny é usado para negar a extração de links que correspondam à expressão regular especificada. O argumento callback specifies é usado para especificar a função de callback a ser chamada na resposta dos links extraídos.
O argumento follow especifica se os links extraídos devem ser seguidos ou não. Usaremos o argumento callback para especificar a função de callback a ser chamada na resposta dos links extraídos. Também usaremos o argumentofollow para especificar se os links extraídos devem ser seguidos ou não.
Em seguida, definimos uma funçãoparse_item que recebe a resposta como um argumento. A funçãoparse_item é usada para analisar a resposta e extrair os dados necessários. Usaremos o métodoxpath para extrair os dados necessários. O métodoxpath extrai dados utilizando expressões xPath.
Obtemos expressões xpath inspecionando o site de destino. Básicamente, clicamos com o botão direito do mouse no elemento do qual queremos extrair dados e clicamos em inspect. Isso abrirá as ferramentas para desenvolvedores. Em seguida, clicamos no botão copy e selecionamos copy xpath. Cole a expressão xpath no métodoxpath.
O métodore extrai dados utilizando expressões regulares. Em seguida, usamos as funçõesclean_stock_symbol, clean_stock_namee clean_stock_price para limpar os dados extraídos. Utilize a funçãozip para combinar os dados extraídos em uma única lista. Em seguida, use um loopfor para iterar a lista e fornecer os dados ao Scrapy.
As funções clean_stock_symbol, clean_stock_name e clean_stock_price são usadas para limpar os dados extraídos. A função clean_stock_symbol usa o símbolo bruto como argumento. A classeBeautifulSoup limpa o símbolo bruto. Em seguida, ela usa o método split para dividir o símbolo limpo em uma lista. Uma instrução if verifica se o comprimento da lista é maior que 1. Se for, ele retorna o segundo item da lista. Se não for, ele retorna None.
A função clean_stock_name usa o nome bruto como argumento. Ele usa a classe prettySoup para limpar o nome bruto. Em seguida, ele usa o método split para dividir o nome limpo em uma lista. Novamente, uma instrução if verificará se o tamanho da lista é maior que 1. Se for, ela retornará o primeiro item da lista. Se não for, retornará Nenhum. A função limpeza_estoque_price usa o preço bruto como argumento. Em seguida, ele usa a classe BeautifulSoup para limpar o preço bruto e retornar o preço limpo.
A funçãoclean_stock_change usa a alteração bruta como argumento. Ela usa a classe BeautifulSoup para limpar a alteração bruta e retornar os dados limpos.

Atualizando o arquivo items.py

Dentro da raiz do nosso projeto, temos o arquivoitems.py. Um item é um contêiner que será carregado com os dados extraídos. Funciona de forma semelhante a um dicionário com recursos adicionais, como declarar seus campos e personalizar sua exportação. Usaremos a classe Item para criar nossos itens. A classe Item é a classe base para todos os itens. Ele fornece os mecanismos gerais para lidar com dados de páginas raspadas. É uma classe abstrata e não pode ser instanciada diretamente. Usaremos a classe Field para criar nossos campos.
Adicione o seguinte código ao arquivo nse_scraper/items.py :
1from scrapy.item import Item, Field
2
3
4class NseScraperItem(Item):
5 # define the fields for your item here like:
6 ticker_symbol = Field()
7 stock_name = Field()
8 stock_price = Field()
9 stock_change = Field()
A classe NseScraperItem cria nosso item. Os campos ticker_symbol, stock_name, stock_price e stock_change armazenam o símbolo do ticker, o nome da ação, o preço da ação e a alteração da ação, respectivamente. Leia mais sobre os itens aqui.

Atualizando o arquivo pipelines.py

Dentro da raiz do nosso projeto, temos o arquivopipelines.py. Um pipeline é um componente que processa os itens extraídos dos spiders. Ele pode limpar, validar e armazenar os dados extraídos em um banco de dados. Usaremos a classe Pipeline para criar nossos pipelines. A classe Pipeline é a classe base para todos os pipelines. Ela fornece os métodos e as propriedades gerais que o pipeline usará.
Adicione o seguinte código ao arquivopipelines.py:
1# pipelines.py
2# useful for handling different item types with a single interface
3import pymongo
4from scrapy.exceptions import DropItem
5
6from .items import NseScraperItem
7
8
9class NseScraperPipeline:
10 collection = "stock_data"
11
12 def __init__(self, mongodb_uri, mongo_db):
13 self.db = None
14 self.client = None
15 self.mongodb_uri = mongodb_uri
16 self.mongo_db = mongo_db
17 if not self.mongodb_uri:
18 raise ValueError("MongoDB URI not set")
19 if not self.mongo_db:
20 raise ValueError("Mongo DB not set")
21
22 @classmethod
23 def from_crawler(cls, crawler):
24 return cls(
25 mongodb_uri=crawler.settings.get("MONGODB_URI"),
26 mongo_db=crawler.settings.get('MONGO_DATABASE', 'nse_data')
27 )
28
29 def open_spider(self, spider):
30 self.client = pymongo.MongoClient(self.mongodb_uri)
31 self.db = self.client[self.mongo_db]
32
33 def close_spider(self, spider):
34 self.client.close()
35
36 def clean_stock_data(self,item):
37 if item['ticker_symbol'] is None:
38 raise DropItem('Missing ticker symbol in %s' % item)
39 elif item['stock_name'] == 'None':
40 raise DropItem('Missing stock name in %s' % item)
41 elif item['stock_price'] == 'None':
42 raise DropItem('Missing stock price in %s' % item)
43 else:
44 return item
45
46 def process_item(self, item, spider):
47 """
48 process item and store to database
49 """
50
51 clean_stock_data = self.clean_stock_data(item)
52 data = dict(NseScraperItem(clean_stock_data))
53 print(data)
54 # print(self.db[self.collection].insert_one(data).inserted_id)
55 self.db[self.collection].insert_one(data)
56
57 return item
Primeiro, importamos o módulopymongo. Em seguida, importamos a classe DropItem do móduloscrapy.Exceptions. Em seguida, importe a classeNseScraperItem do módulo de itens.
A classeNseScraperPipeline cria nosso pipeline. A variável dacollection armazena o nome da collection que usaremos. O métodoinit inicializa o pipeline. Ele aceita mongodb_uri e mongo_db como argumentos. Em seguida, ele usa uma declaração if para verificar se mongodb_uri está definido. Caso contrário, gera um ValueError. Em seguida, ele usa uma declaração if para verificar se mongo_db está definido. Caso contrário, gera um ValueError.
O método from_crawler cria uma instância do pipeline. Ele usa o rastreador como argumento. Em seguida, ele retorna uma instância do pipeline. O método open_spider abre o spider. Ele usa a spider como argumento. Em seguida, ele cria uma instância MongoClient e a armazena na variável do cliente. Ele utiliza a instância do cliente para se conectar ao banco de dados e o armazena na variável db.
O método close_spider fecha a aranha. Toma a aranha como argumento. Em seguida, ele fecha a instância do cliente. O método clean_stock_data limpa os dados extraídos. Ele usa o item como argumento. Em seguida, ele usa uma instrução if para verificar se o ticker_symbol é None. Se for, ele gera um DropItem. Em seguida, ele usa uma instrução if para verificar se o stock_name é None. Se for, ele gera um DropItem. Em seguida, ele usa uma instrução if para verificar se o stock_price é None. Se for, ele gera um DropItem. Se nenhuma das instruções if for verdadeira, ele retornará o item.
O métodoprocess_item processa os dados extraídos. Ele usa o item e a aranha como argumentos. Em seguida, ele usa o métodoclean_stock_data para limpar os dados copiados. Ele usa a função dict para converter o item em um dicionário. Em seguida, ele imprime os dados no console. Em seguida, ele usa a instância de banco de dados para inserir os dados no banco de dados. Ele devolve o item.

Atualizando o

settings.py

arquivo

Dentro da raiz do nosso projeto, temos o arquivosettings.py. Este arquivo é usado para armazenar as configurações do nosso projeto. Adicione o seguinte código ao arquivosettings.py:
1# settings.py
2import os
3from dotenv import load_dotenv
4
5load_dotenv()
6BOT_NAME = 'nse_scraper'
7
8SPIDER_MODULES = ['nse_scraper.spiders']
9NEWSPIDER_MODULE = 'nse_scraper.spiders'
10
11# MONGODB SETTINGS
12MONGODB_URI = os.getenv("MONGODB_URI")
13MONGO_DATABASE = os.getenv("MONGO_DATABASE")
14
15ITEM_PIPELINES = {
16 'nse_scraper.pipelines.NseScraperPipeline': 300,
17}
18LOG_LEVEL = "INFO"
19
20# USER_AGENT = 'nse_scraper (+http://www.yourdomain.com)'
21
22# Obey robots.txt rules
23ROBOTSTXT_OBEY = False
24
25
26# Override the default request headers:
27DEFAULT_REQUEST_HEADERS = {
28 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
29 'Accept-Language': 'en',
30}
31
32# Enable and configure HTTP caching (disabled by default)
33# See https://docs.scrapy.org/en/latest/topics/downloader-middleware.html#httpcache-middleware-settings
34HTTPCACHE_ENABLED = True
35HTTPCACHE_EXPIRATION_SECS = 360
36HTTPCACHE_DIR = 'httpcache'
37# HTTPCACHE_IGNORE_HTTP_CODES = []
38HTTPCACHE_STORAGE = 'scrapy.extensions.httpcache.FilesystemCacheStorage'
Primeiro, importamos os módulosos e load_dotenv . Chamamos então a funçãoload_dotenv. Não utiliza argumentos. Esta função carrega as variáveis de ambiente do arquivo.env.
nse_scraper.spiders. Anexamos a variávelMONGODB_URI e a definimos para a variável de ambiente MONGODB_URI . Em seguida, criamos a variávelMONGODB_DATABASE e a definimos para a variável de ambienteMONGO_DATABASE .
Depois, criamos a variávelITEM_PIPELINES e a configuramos como nse_scraper.pipelines.NseScraperPipeline. Em seguida, criamos a variávelLOG_LEVEL e a configuramos como INFO. A variávelDEFAULT_REQUEST_HEADERS está definida como um dicionário. A seguir, criamos a variávelHTTPCACHE_ENABLED e a configuramos como True.
Altere a variável HTTPCACHE_EXPIRATION_SECSe defina-a para360. Crie a variável HTTPCACHE_DIRe defina-a comohttpcache. Finalmente, crie a variável HTTPCACHE_STORAGEe defina-a parascrapy.extensions.httpcache.FilesystemCacheStorage.

Estrutura do projeto

A estrutura do projeto é a seguinte:
1├ nse_stock_scraper
2 ├ nse_scraper
3 ├── __init__.py
4 │ ├── items.py
5 │ ├── middlewares.py
6 │ ├── pipelines.py
7 │ ├── settings.py
8 ├─ stock_notification.py
9 │ └── spiders
10 │ ├── __init__.py
11 │ └── afx_scraper.py
12 ├── README.md
13 ├── LICENSE
14 ├── requirements.txt
15 └── scrapy.cfg
16 ├── .gitignore
17 ├── .env

Executando o scraper

Para executar o scraper, precisaremos abrir um terminal e navegar até o diretório do projeto. Em seguida, precisaremos ativar o ambiente virtual, se ele ainda não estiver ativado. Podemos fazer isso executando o seguinte comando:
1source venv/bin/activate
Crie um arquivo.env na raiz do projeto (em /nse_scraper/). Adicione o seguinte código ao arquivo.env:
1MONGODB_URI=mongodb+srv://
2MONGODB_DATABASE=
3at_username=
4at_api_key=
5mobile_number=
Adicione seu URI do MongoDB, o nome do banco de dados, o nome de usuário do Africas Talking, a chave da API e o número do celular ao .env arquivo do seu URI do MongoDB. Você pode usar a camada gratuita do MongoDB Atlas. Obtenha seu URI no connectpainel do Atlas, no botão . Ele deve ter a seguinte aparência:
1mongodb+srv://<username>:<password>@<cluster-name>.mongodb.net/<database-name>?retryWrites=true&w=majority
Precisamos executar o seguinte comando para executar o scraper enquanto estiver na pasta do projeto:
(/nse_scraper/):
1scrapy crawl afx_scraper

Habilitando alertas de texto (usando Africas Talking)

Instale o móduloafricastalking executando o seguinte comando no terminal:
1pip install africastalking
Crie um novo arquivo chamado stock_notification.py no diretório nse_scraper. Adicione o seguinte código ao arquivo
stock_notification.py
:
1# stock_notification.py
2import africastalking as at
3import os
4from dotenv import load_dotenv
5import pymongo
6
7load_dotenv()
8
9at_username = os.getenv("at_username")
10at_api_key = os.getenv("at_api_key")
11mobile_number = os.getenv("mobile_number")
12mongo_uri = os.getenv("MONGODB_URI")
13
14# Initialize the Africas sdk py passing the api key and username from the .env file
15at.initialize(at_username, at_api_key)
16sms = at.SMS
17account = at.Application
18
19
20ticker_data = []
21
22# Create a function to send a message containing the stock ticker and price
23def stock_notification(message: str, number: int):
24 try:
25 response = sms.send(message, [number])
26 print(account.fetch_application_data())
27 print(response)
28 except Exception as e:
29 print(f" Houston we have a problem: {e}")
30
31# create a function to query mongodb for the stock price of Safaricom
32def stock_query():
33 client = pymongo.MongoClient(mongo_uri)
34 db = client["nse_data"]
35 collection = db["stock_data"]
36 # print(collection.find_one())
37 ticker_data = collection.find_one({"ticker": "BAT"})
38 print(ticker_data)
39 stock_name = ticker_data["name"]
40 stock_price = ticker_data["price"]
41 sms_data = { "stock_name": stock_name, "stock_price": stock_price }
42 print(sms_data)
43
44 message = f"Hello the current stock price of {stock_name} is {stock_price}"
45 # check if Safaricom share price is more than Kes 39 and send a notification.
46 if int(float(stock_price)) >= 38:
47 # Call the function passing the message and mobile_number as a arguments
48 print(message)
49 stock_notification(message, mobile_number)
50 else:
51 print("No notification sent")
52
53 client.close()
54
55 return sms_data
56
57stock_query()
O código acima importa o móduloafricastalking . Importe os módulosos e load_dotenv . Passamos a chamar a funçãoload_dotenv. Não são necessários argumentos. Essa função carrega as variáveis de ambiente do arquivo.env .
  • Criamos a variávelat_usernamee a definimos como a variável de ambienteat_username. Em seguida, criamos a variávelat_api_keye a definimos como a variável de ambienteat_api_key. Crie a variávelmobile_number e defina-a como a variável de ambientemobile_number. E crie a variávelmongo_urie defina-a como a variável de ambienteMONGODB_URI.
  • Inicializamos o móduloafricastalking passando as variáveisat_username e at_api_key como argumentos. Crie a variávelsms e defina-a como at.SMS. Crie a variávelaccount e defina-a como at.Application.
  • Crie a variável ticker_datae defina-a como uma lista vazia. Crie a funçãostock_notification. São necessários dois argumentos: message e number. Em seguida, tentamos enviar a mensagem para o número e imprimir a resposta. Procure por exceções e exiba-as.
  • Criamos a funçãostock_query. Em seguida, criamos a variável cliente a definimos para um objeto pymongo.MongoClient . Crie a variável dbe defina-a para o banco de dadosnse_data. Em seguida, crie a variávelcollection e defina-a para a coleçãostock_data e crie a variávelticker_data e defina-a para o métodocollection.find_one. Aceita um dicionário como argumento.
A variávelstock_name é definida como a chavenameno dicionárioticker_data. Crie a variávelstock_price e defina-a como a chavepriceno dicionárioticker_data. Crie a variávelsms_data e defina-a como um dicionário. Ele contém as variáveis stock_namee stock_price .
A variávelmessage é definida como uma string contendo o nome e o preço da ação. Verificamos se o preço da ação é maior ou igual a 38. Se for, chamamos a funçãostock_notification e passamos as variáveismessage e mobile_number como argumentos. Caso contrário, imprimimos uma mensagem no console.
Feche a conexão com o banco de dados e retorne a variável sms_data . Chame a funçãostock_query.
Precisamos adicionar o seguinte código ao afx_scraper.py arquivo :
1# afx_scraper.py
2from nse_scraper.stock_notification import stock_query
3
4# ...
5
6# Add the following code to the end of the file
7stock_query()
Se tudo estiver configurado corretamente, você deverá ver algo assim:

Dados no MongoDB Atlas

Precisamos criar um novo cluster no MongoDB Atlas. Podemos fazer isso por:
  • Clicar no botãoBuild a Cluster.
  • Selecionando a opçãoShared Clusters.
  • Selecionando a opçãoFree Tier.
  • Selecionando a opçãoCloud Provider & Region.
  • Selecionando a opçãoAWS. (Selecionei a opção AWS Cape Town.)
  • Selecionando a opçãoCluster Name.
  • Dando um nome ao cluster. (Podemos chamá-lo de nse_data.)
Vamos configurar um usuário para acessar o cluster seguindo as etapas abaixo:
  • Selecione a opçãoDatabase Access.
  • Clique na opçãoAdd New User.
  • Dê ao usuário um nome de usuário. (Eu usei nse_user.).
  • Dê ao usuário uma senha. (Eu usei nse_password).
  • Selecione a opçãoNetwork Access.
  • Selecione a opçãoAdd IP Address.
  • Selecione a opçãoAllow Access from Anywhere.
  • Selecione a opçãoCluster. Em seguida, será necessário selecionar a opçãoCreate Cluster.
Clique na opçãoCollections e depois no botão+ Create Database. Dê um nome ao banco de dados. Podemos chamá-lo nse_data. Clique no botão+ Create Collection. Dê um nome à collection. Podemos chamar isso stock_data. Se tudo estiver configurado corretamente, você deverá ver algo assim:
Registros do banco de dados exibidos no MongoDB Atlas
Se você vir uma collection vazia, execute novamente o projeto no terminal para preencher os valores no MongoDB. Em caso de erro, leia a saída do terminal. Problemas comuns podem ser:
  • O IP aAddress não foi adicionado no painel.
  • Falta de credenciais ou credenciais incorretas em seuarquivo.env.
  • Um erro de sSyntax no seu código.
  • Verifique sua conexão com a Internet.
  • A lFalta de permissões apropriadas para seu usuário.

Métricas no MongoDB Atlas

Go ver como visualizar métricas relacionadas ao(s) nosso(s) banco(s) de dados.
  • Clique na opção **Metrics.
  • Clique no botão+ Add Metric.
  • Selecione a opçãoDatabase.
  • Selecione a opçãonse_data.
  • Selecione a opçãoCollection.
  • Selecione a opçãostock_data.
  • Selecione a opçãoMetric.
  • Selecione a opçãoDocuments.
  • Selecione a opçãoTime Range.
  • Selecione a opçãoLast 24 Hours.
  • Selecione a opçãoGranularity.
  • Selecione a opção1 Hour.
  • Clique no botãoAdd Metric.
Se tudo estiver configurado corretamente, ficará assim:
Métricas de cluster mostradas no MongoDB Atlas

Gráficos no MongoDB Atlas

MongoDB Atlas oferece Atlas Charts que podem ser utilizados para visualizar os dados no banco de dados. Clique na opçãoCharts. Em seguida, clique no botão + Add Chart. Selecione a opçãoDatabase. Abaixo está uma captura de tela de exemplos de Atlas Charts para dados NSE:
Dados exibidos no MongoDB Atlas Charts

Controle de versão com Git e GitHub

Certifique-se de ter o Git instalado em seu computador, junto com uma conta do GitHub.
Execute o seguinte comando no seu terminal para inicializar um repositório git:
1git init
Crie um arquivo.gitignore. Podemos fazer isso executando o seguinte comando em nosso terminal:
1touch .gitignore
Vamos adicionar o arquivo .env ao arquivo .gitignore. Adicione o seguinte código ao arquivo.gitignore:
1# .gitignore
2.env
Adicione os arquivos à área de preparação executando o seguinte comando em nosso terminal:
1git add .
Confirme os arquivos no repositório executando o seguinte comando em nosso terminal:
1git commit -m "Initial commit"
Crie um novo repositório no GitHub clicando no ícone+ no canto superior direito da página e selecionando New repository. Dê um nome ao repositório. Podemos chamá-lo nse-stock-scraper. Selecione Public como a visibilidade do repositório. Selecione Add a README file e Add .gitignore, e selecione Python no menu suspenso. Clique no botãoCreate repository.
Adicione o repositório remoto ao nosso repositório local executando o seguinte comando em seu terminal:
1git remote add origin
Envie os arquivos para o repositório remoto executando o seguinte comando no seu terminal:
1git push -u origin master

CI/CD com ações do GitHub

Crie uma nova pasta — .github — e uma pastaworkflows dentro, no diretório raiz do projeto. Podemos fazer isso executando o seguinte comando em nosso terminal. Dentro do workflows file, precisaremos criar um novo arquivo chamado scraper-test.yml. Podemos fazer isso executando o seguinte comando em nosso terminal:
1touch .github/workflows/scraper-test.yml
Dentro do
scraper-test.yml
arquivo, precisaremos adicionar o seguinte código:
1name: Scraper test with MongoDB
2
3on: [push]
4
5jobs:
6 build:
7
8 runs-on: ubuntu-latest
9 strategy:
10 matrix:
11 python-version: [3.8, 3.9, "3.10"]
12 mongodb-version: ['4.4', '5.0', '6.0']
13
14 steps:
15 - uses: actions/checkout@v2
16 - name: Set up Python ${{ matrix.python-version }}
17 uses: actions/setup-python@v1
18 with:
19 python-version: ${{ matrix.python-version }}
20 - name: Set up MongoDB ${{ matrix.mongodb-version }}
21 uses: supercharge/mongodb-github-action@1.8.0
22 with:
23 mongodb-version: ${{ matrix.mongodb-version }}
24 - name: Install dependencies
25 run: |
26 python -m pip install --upgrade pip
27 pip install -r requirements.txt
28 - name: Lint with flake8
29 run: |
30 pip install flake8
31 # stop the build if there are Python syntax errors or undefined names
32 flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
33 # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
34 flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
35 - name: scraper-test
36 run: |
37 cd nse_scraper
38 export MONGODB_URI=mongodb://localhost:27017
39 export MONGO_DATABASE=nse_data
40 scrapy crawl afx_scraper -a output_format=csv -a output_file=afx.csv
41 scrapy crawl afx_scraper -a output_format=json -a output_file=afx.json
Vamos detalhar o código acima. Criamos um novo fluxo de trabalho chamado Scraper test with MongoDB. Em seguida, definimos o eventooncomo push. Crie um novo trabalho chamado build. Defina o runs-on para ubuntu-latest. Defina o strategy como uma matriz. Ele contém as variáveispython-version e mongodb-version . Defina o python-version para 3.8, 3.9e 3.10. Defina o mongodb-version como 4.4, 5.0e 6.0.
Crie uma nova etapa chamada Checkout. Configure o uses para actions/checkout@v2. Crie uma nova etapa chamada Set up Python ${{ matrix.python-version }} e defina uses como actions/setup-python@v1. Defina python-version como ${{ matrix.python-version }}. Crie uma nova etapa chamada Set up MongoDB ${{ matrix.mongodb-version }}. Isso configura diferentes versões do Python e versões do MongoDB para teste.
A etapaInstall dependencies instala as dependências. Crie uma nova etapa chamada Lint with flake8. Esta etapa liga o código. Crie uma nova etapa chamada scraper-test. Esta etapa executa o raspador e o testa.
Confirme as alterações no repositório executando o seguinte comando no seu terminal:
1git add .
2git commit -m "Add GitHub Actions"
3git push
Go para a abaActionsno seu repositório. Você deve ver algo assim:
Exibindo o processo de construção

Conclusão

Neste tutorial, construímos um raspador de preço de ações usando Python e Scrapy. Em seguida, usamos o MongoDB para armazenar os dados raspados. Usamos o Africas Talking para enviar notificações por SMS. Por fim, implementamos um pipeline de CI/CD usando o GitHub Actions.
Existem melhorias definitivas que podem ser feitas neste projeto. Por exemplo, podemos adicionar mais bolsas de valores. Também podemos adicionar mais canais de notificação. Este projeto deve servir como um bom ponto de partida.
Graças para ler até agora., espero que você tenha obtido informações ou expiração para seu próximo projeto com o MongoDB Atlas. Sinta-se à vontade para comentar abaixo ou entrar em contato para solicitar novas melhorias. Gostaríamos muito de ouvir você! Este projeto é oOpen sSource e está disponível no GitHub —, clone ou fork it !, Estou ansioso para ver o que você cria.

Ícone do FacebookÍcone do Twitterícone do linkedin
Avalie esse Tutorial
star-empty
star-empty
star-empty
star-empty
star-empty
Relacionado
Artigo

Como pausar e retomar clusters do Atlas de maneira fácil


Sep 11, 2024 | 5 min read
Artigo

Como otimizar sua fatura de instância sem servidor com indexação


Sep 13, 2023 | 6 min read
Tutorial

Modelagem de dados em várias linguagens do Atlas Search


Sep 09, 2022 | 2 min read
Tutorial

Introdução ao MongoDB Atlas, NodeJS e o Azure App Service


Apr 02, 2024 | 5 min read
Sumário