markdown metro_notification

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了markdown metro_notification相关的知识,希望对你有一定的参考价值。

#!/usr/bin/env python3

import requests
from bs4 import BeautifulSoup
from time import sleep


IFTTT_WEBHOOKS_URL = 'https://maker.ifttt.com/trigger/metro_notification/with/key/<TOKEN>'
last_status_data = {}


def get_latest_metro_status():
    response = requests.get("http://www.viaquatro.com.br/")

    soup = BeautifulSoup(response.text, 'html.parser')

    html_data = soup.find_all('div', class_='open-modal')

    lines = {}

    for container in html_data:
        # Line Number
        number = container.find('span', class_='circle').text

        # Line Name
        name = container.find('span', class_='title').text

        # Line Status
        status = container.select_one('span[class*="status"]').text

        lines[number] = {'name': name, 'status': status}

    return lines


def post_ifttt_webhook(number, name, status):
    data = {
        'value1': number,
        'value2': name,
        'value3': status
    }

    requests.post(IFTTT_WEBHOOKS_URL, json=data)


def check_status():
    def is_new_status(number, status):
        if number not in last_status_data or last_status_data[number] != status:
            last_status_data[number] = status
            return True

        return False

    data = get_latest_metro_status()
    for number, data in data.items():
        name = data['name']
        status = data['status']

        if is_new_status(number, status):
            post_ifttt_webhook(number, name, status)


def main():
    while True:
        check_status()
        sleep(60)


if __name__ == '__main__':
    main()
## Configurando o Ambiente
Primeiro precisamos criar um virtualenv e ativa-la, para isolarmos as dependencias de python somente para esse projeto.

```sh
$ python3 -m venv $HOME/.venvs/metro_notify
$ source $HOME/.venvs/metro_notify/bin/activate
```

Depois é necessário instalarmos as bibliotecas necessárias para fazermos o webscrappin e o BOT no IFTTT:  e Requests

```sh
$ python3 -m pip install beautifulsoup4 requests
```

## Coletando informações

O primeiro passo pro webscrapping é inspecionarmos as paginas que queremos obter as informações, grande parte dos navegadores possuem uma ferramenta chamada **Developer Tools** usada justamente para verificar o comportamentos e estruturas de páginas da web. Uma das coisas uteis em usar uma ferramenta de **Developer Tools**, é que conforme você vai selecionando o componente HTML, ele vai mostrando em que parte da pagina você esta vendo, o que facilita muito o trabalho de inspeção.

Veja que o box que esta contendo todas as informações de status das linhas de metro/trem é uma tag html chamada **section** com uma classe de css chamada **operacao**.

//

Se aprofundarmos um pouco mais vemos que cada uma das linhas e seus status, estão dentro de uma tag **div** com a classe **open-modal**, e é justamente ela que pegaremos para inspecionar.

```python
import requests
from bs4 import BeautifulSoup

def get_latest_metro_status():
    response = requests.get("http://www.viaquatro.com.br/")

    soup = BeautifulSoup(response.text)

    html_data = soup.find_all('div', class_='open-modal')
```

No código acima, criamos uma função onde ela será responsável por criar um dicionario com os status de todas as linhas metro/trem de SP. Usando a biblioteca **requests** fazemos uma requisição para o site http://www.viaquatro.com.br/ e depois pegamos o conteúdo html que é retornado pela página e passamos ele para a biblioteca **BeautifulSoup**.

Nesse trecho repare que estamos indo atrás de todas as divs que contenham a classe **open-modal**.
FOTO /screenshots/webscrapping/2

```python
html_data = soup.find_all('div', class_='open-modal')
```

Agora precisamos pegar o nome da linha e o status dela no html.

FOTO /screenshots/webscrapping/3
FOTO /screenshots/webscrapping/4

```python
import requests
from bs4 import BeautifulSoup

def get_latest_metro_status():
    response = requests.get("http://www.viaquatro.com.br/")

    soup = BeautifulSoup(response.text, 'html.parser')

    html_data = soup.find_all('div', class_='open-modal')

    lines = {}

    for container in html_data:
        # Line Number
        number = container.find('span', class_='circle').text

        # Line Name
        name = container.find('span', class_='title').text

        # Line Status
        status = container.select_one('span[class*="status"]').text

        lines[number] = {'name': name, 'status': status}

    return lines
```

Ok, agora temos novos trechos de código:
A propriedade `.text` nos retornará o texto que esta dentro da tag alvo.

```python
name = container.find('span', class_='title').text
```

Agora temos um problema, toda vez que uma linha muda de status, ela tabém muda a classe de status, como podemos ver na imagem abaixo:

/screenshots/webscrapping/5

Para resolvermos essa problema temos que usar um ***query selector***, ele é bem conhecido entre programadores frontend. A codnição abaixo nos diz para retornar tag primeira tag que for um **span** que contenha uma classe que comece com **status**, isso resolverá nosso problema do status mudar de classe dependendo de seu texto.

```python
status = container.select_one('span[class*="status"]').text
```

Agora nossa função esta completa, ela percorre toda a lista de objetos e cria um dicionario contendo o status e o nome da linha, usando o numero da linha como índice dela.

```python
lines[number] = {'name': name, 'status': status}
```

## Criando o Bot

Primeio é necessário ter uma conta no [IFTTT](https://ifttt.com/)

> IFTTT is the free way to get all your apps and devices talking to each other. Not everything on the internet plays nice, so we're on a mission to build a more connected world.

Após criar a sua conta, é necessario criar um **applet**, só ir na sessão [My Applets](https://ifttt.com/my_applets), depois clicar no botão **New Applet**.

Escolhemos um serviço, para o nosso caso, usaremos o **Webhooks**.
FOTO /screenshots/create_applet/2
FOTO /screenshots/create_applet/3
FOTO /screenshots/create_applet/4

Temos que dar um nome para o evento webhook que será executado, coloque `metro_notification`, é através dele que enviaremos nossos dados para o bot.
FOTO /screenshots/create_applet/5

Depois temos que escolher próximo serviço.
FOTO /screenshots/create_applet/6
FOTO /screenshots/create_applet/7

Agora temos que definir o texto da mensagem que será recebida.
No campo `Message text`, coloque:

```text
Linha: <b>{{Value1}} - {{Value2}}</b><br>
Status: <b>{{Value3}}</b>
```

FOTO /screenshots/create_applet/8

E por fim clicamos no botão ```Create action```

FOTO /screenshots/create_applet/9

Certo agora temos nossa action criada, precisamos do token do webhook, você irá consegui-lo na documentação do [Webhook](https://ifttt.com/maker_webhooks)
FOTO /screenshots/create_applet/10

## Criando integração com o Telegram

Primeiro é necessário baixar o aplicativo do IFTTT, [Play Store](https://play.google.com/store/apps/details?id=com.ifttt.ifttt&hl=pt_BR) ou na [Apple Store](https://itunes.apple.com/br/app/ifttt/id660944635?mt=8)

Após isso procure pelo serviço ´Telegram´
FOTO
Clique em ´Connect´
FOTO
Ele irá redirecionar você para um brower e depois abrir o aplicativo ´Telegram´, é só seguir as instruções.


## Enviando a chamada para o Bot

Resumindo, o processo do bot será o seguinte:

1. Pegamos as informações do site viaquatro
2. Comparamos para ver se não há nenhuma mudança de status
3. Se houver mudanças, enviamos pro webhook IFTTT para que ele dispare as mensagens pro Telegram.

No escopo global colocaremos uma variavel onde será armazenado os status das linhas
```python
last_status_data = {}
```

Agora criaremos uma função para checar se há alguma alteração de status nas Linhas

```python
def check_status():
    def is_new_status(number, status):
        if number not in last_status_data or last_status_data[number] != status:
            last_status_data[number] = status
            return True

        return False

    data = get_latest_metro_status()
    for number, data in data.items():
        name = data['name']
        status = data['status']

        if is_new_status(number, status):
            post_ifttt_webhook(number, name, status)
```

Calma, iremos passar em cada trecho.

Criamos uma função dentro da função principal `check_status()` que verifica a variável global `last_status_data` não tem a Linha, ou se o status de uma Linha já existente mudou, caso uma dessas condições seja atendida, ela atualiza a variavel global e retorna um valor booleano **True**, caso o contrario, ela considera que não houve alterações de status e retorna **False**. Essa checagem é essencial pro nosso BOT para que ele não fique disparando constantemente status repetidos.

```python
    def is_new_status(number, status):
        if number not in last_status_data or last_status_data[number] != status:
            last_status_data[number] = status
            return True

        return False
```

Olhando para o loop ao final da função `check_status`, ele verifica se há um novo status  na listagem enviada pelo webscrapping feito na função `get_latest_metro_status`, depois ele verifica se o status é um novo status, se for ele chamará a função `post_ifttt_webhook`.

```python
    data = get_latest_metro_status()
    for number, data in data.items():
        name = data['name']
        status = data['status']

        if is_new_status(number, status):
            post_ifttt_webhook(number, name, status)
```

Agora vamos escrever a função para fazer o envio para o webhook.
Lembra do **token** que pegamos no site do IFTTT, pois então, substitua seu **token** na URL da varialvel **IFTTT_WEBHOOKS_URL**

Lembra também que definimos algumas variaveis no texto da mensagem do Telegram, devemos montar o json para o envio do **IFTTT**.

E por fim enviamos através da biblioteca `requests`.

```python
IFTTT_WEBHOOKS_URL = 'https://maker.ifttt.com/trigger/metro_notification/with/key/<TOKEN>'

def post_ifttt_webhook(number, name, status):
    data = {
        'value1': number,
        'value2': name,
        'value3': status
    }

    requests.post(IFTTT_WEBHOOKS_URL, json=data)
```

Agora precisamos colocar nosso código para executar de tempos em tempos.

```python
from time import sleep

def main():
    while True:
        check_status()
        sleep(60)


if __name__ == '__main__':
    main()
```

**Shebang**
Quando queremos executar um código em python como um programa comum, é só adicionar no começo do arquivo o comentário

```python
#!/usr/bin/env python3
```

E no terminal simplesmente executamos

```sh
$ notify.py
```

以上是关于markdown metro_notification的主要内容,如果未能解决你的问题,请参考以下文章

转换rst到markdown总结

markdown [Markdown HowTo]作为Markdown语法的秘籍

python markdown干啥用的

markdown前端渲染

如何用markdown生成目录

markdown排版示例