Video Creator – #Parte 10: Upload do video para o Youtube

Bom dia, boa tarde, boa noite!

Essa é a décima e última parte da série sobre o projeto Video Creator, onde mostrarei como fiz o upload automático do video no o Youtube.

Se você entrou direto nesse post, te aconselho a começar por aqui, para entender exatamente do que se trata essa série.

Sobre essa parte

Para fazer o upload do video no Youtube, usei apenas algumas configurações básicas, mas vale muito a pena dar uma olhada na documentação da API, porque tem muita opção para configurar. Para esse projeto, segui o mais básico.

Requisitos:

Para essa parte, precisaremos habilitar a API do Youtube na sua conta Google Cloud, baixar o arquivo com a secret key que será gerada, fazer alguns imports e está quase tudo pronto. Isso porque 90% do código já está pronto no próprio site da API, e é ele que vamos usar como base:

https://developers.google.com/youtube/v3/guides/uploading_a_video#Sample_Code

Habilitar API do Youtube:

Visite o link abaixo e entre na sua conta, ou crie uma, é gratuíto é tão simples quando criar qualquer outra conta de serviço web.

https://cloud.google.com/

Após logado, você precisará criar um novo projeto, ao lado de Google Cloud Platform, clique no menu dropdown e a modal abaixo aparecerá, clique em Novo Projeto, preencha com o nome desejado e clique em criar. Se o projeto não ficar selecionado automaticamente, clique novamente no menu dropdown e selecione o projeto recém criado.

layout fev/2022

Agora clique nas barrinhas horizontais no canto superior esquerdo da tela, depois vá em APIs e serviços, e por fim selecione Biblioteca.

layout fev/2022

Na tela que abrir, selecione Youtube Data Api v(x):

Na tela que abrir, clique no botão ativar, e sua tela ficará assim:

layout fev/2022

Para visitar a documentação da API, clique em TESTAR ESTA API.

Clique em Gerenciar, e na tela que abrir, selecione a aba Credenciais e depois em Criar credenciais.

layout fev/2022

Selecione ID do cliente OAuth.

Em tipo de aplicativo, selecione Aplicativo da WEB:

layout fev/2022

Digite um nome, e depois em criar, aparecerá um modal com seu ID de cliente e Chave secreta de cliente. Você pode salvar esses dados em um arquivo de config, ou fazer como eu fiz, que é na listagem de credenciais, clicar no botão de download, e baixar o arquivo com esses dados.

Hora de codificar:

Com a API ativada e o arquivo com a secret key já salvo na pasta credentials, é hora de pegar o sample code e fazer algumas personalizações.

O robô inicia com a função start(), que carrega o conteúdo do arquivo content.json para dentro do objeto video_content, cria o objeto youtube, e nesse momento, o navegador abrirá perguntando para qual conta do Youtube você deseja fazer o upload. Após isso, ele chama a função create_thumbnail(), que cria as thumbnails e inicia o processo de Upload.

A função start() ficou assim:


def start():
    logging.info('--- Starting Youtube robot ---')
    video_content = rcontent.load()
    youtube = get_authenticated_service()
    try:
        create_thumbnail(video_content)
        initialize_upload(youtube, video_content)
        result = "Upload concluído!"
    except HttpError as e:
            result = "An HTTP error %d occurred:\n%s" % (e.resp.status, e.content)
    except Exception as ex:
        result = ex
    print(result)

A função create_thumbnail() ficou assim:


def  create_thumbnail(video_content):
    logging.info("Creating Thumbnail...")

    # apagando as thumbs existentes
    os.system("rm -rf {}/thumb*".format(CONTENT_IMAGES_PATH))

    # criando os comandos para execução.
    # Importante: Refatorar para que a montagem do comando esteja dentro de um for

    command_thumb_default = "convert -size {}x{} -font helvetica -pointsize 24 -background 'black' -fill white -gravity center caption:'{}' ./content/images/thumb_default.png"\
        .format(YOUTUBE_VIDEO_THUMBNAILS['default']['width'],YOUTUBE_VIDEO_THUMBNAILS['default']['height'], video_content['youtube_details']['title'])
        
    command_thumb_medium = "convert -size {}x{} -font helvetica -pointsize 26 -background 'black' -fill white -gravity center caption:'{}' ./content/images/thumb_medium.png"\
        .format(YOUTUBE_VIDEO_THUMBNAILS['medium']['width'],YOUTUBE_VIDEO_THUMBNAILS['medium']['height'], video_content['youtube_details']['title'])

    command_thumb_high = "convert -size {}x{} -font helvetica -pointsize 30 -background 'black' -fill white -gravity center caption:'{}' ./content/images/thumb_high.png"\
        .format(YOUTUBE_VIDEO_THUMBNAILS['high']['width'],YOUTUBE_VIDEO_THUMBNAILS['high']['height'], video_content['youtube_details']['title'])
    
    command_thumb_standard = "convert -size {}x{} -font helvetica -pointsize 50 -background 'black' -fill white -gravity center caption:'{}' ./content/images/thumb_standard.png"\
        .format(YOUTUBE_VIDEO_THUMBNAILS['standard']['width'],YOUTUBE_VIDEO_THUMBNAILS['high']['height'], video_content['youtube_details']['title'])

    command_thumb_maxres = "convert -size {}x{} -font helvetica -pointsize 70 -background 'black' -fill white -gravity center caption:'{}' ./content/images/thumb_maxres.png"\
        .format(YOUTUBE_VIDEO_THUMBNAILS['maxres']['width'],YOUTUBE_VIDEO_THUMBNAILS['high']['height'], video_content['youtube_details']['title'])

    os.system(command_thumb_default)
    os.system(command_thumb_medium)
    os.system(command_thumb_high)
    os.system(command_thumb_standard)
    os.system(command_thumb_maxres)

Uma informação importante, é que nessa função eu faço todas as possíveis thumbnails que o Youtube permite, porém não consegui fazer funcionar o upload das thumbnails junto com o video. Precisei utilizar a função set do objeto thumbnails após o upload de video.

Abaixo, as 2 funções que fazem o processo de upload do video:


def initialize_upload(youtube, video_content):
    list_of_used_images = '\n'.join('✅ ' + img for img in video_content['images_used'])
    list_of_sentences = '\n'.join([ s['text'] for s in video_content['sentences']])
    YOUTUBE_VIDEO_DESCRIPTION = """
Conheça um pouco mais sobre {}:

{}

👉 Referências:

💥 Wikipedia
💥 Custom Search API - Bing.

👉 Imagens utilizadas no vídeo:

{}
""".format(video_content['search_term'], list_of_sentences, list_of_used_images)

    YOUTUBE_VIDEO_FILE = CONTENT_PATH + '/{}'.format(video_content['video_filename'])
        
    body= {
        "snippet": {
            "title": video_content['youtube_details']['title'],
            "description": YOUTUBE_VIDEO_DESCRIPTION,
            "tags": get_tags(video_content),
            "categoryId": video_content['youtube_details']['category_id']
        },
        "status": {
            "privacyStatus": YOUTUBE_VIDEO_PRIVACY_STATUS
        }
    }
    # Call the API's videos.insert method to create and upload the video.
    insert_request = youtube.videos().insert(
    part=",".join(body.keys()),
    body=body,
    # The chunksize parameter specifies the size of each chunk of data, in
    # bytes, that will be uploaded at a time. Set a higher value for
    # reliable connections as fewer chunks lead to faster uploads. Set a lower
    # value for better recovery on less reliable connections.
    #
    # Setting "chunksize" equal to -1 in the code below means that the entire
    # file will be uploaded in a single HTTP request. (If the upload fails,
    # it will still be retried where it left off.) This is usually a best
    # practice, but if you're using Python older than 2.6 or if you're
    # running on App Engine, you should set the chunksize to something like
    # 1024 * 1024 (1 megabyte).
    media_body=MediaFileUpload(YOUTUBE_VIDEO_FILE, chunksize=-1, resumable=True)
    )
    insert_response = resumable_upload(insert_request)
    # set thumbnail
    set_thumbnail(youtube, insert_response['id'])

    
# This method implements an exponential backoff strategy to resume a
# failed upload.
def resumable_upload(insert_request):
    response = None
    error = None
    retry = 0
    while response is None:
        try:
            print ("Uploading file...")
            status, response = insert_request.next_chunk()
            if response is not None:
                if 'id' in response:
                    print ("Video id '%s' was successfully uploaded." % response['id'])
                else:
                    exit("The upload failed with an unexpected response: %s" % response)
        except HttpError as e:
            if e.resp.status in RETRIABLE_STATUS_CODES:
                error = "A retriable HTTP error %d occurred:\n%s" % (e.resp.status,e.content)
            else:
                raise
        except RETRIABLE_EXCEPTIONS as e:
            error = "A retriable error occurred: %s" % e

        if error is not None:
            print (error)
            retry += 1
            if retry > MAX_RETRIES:
                exit("No longer attempting to retry.")
            max_sleep = 2 ** retry
            sleep_seconds = random.random() * max_sleep
            print ("Sleeping %f seconds and then retrying..." % sleep_seconds)
            time.sleep(sleep_seconds)

    return response

Dentro da primeiro função initialize_upload(), comecei montando os dados que eu precisaria para fazer o upload do video, utilizei o assunto pesquisado, as sentenças e a lista de imagens usadas para compor a descrição do video e dar os devidos créditos para os sites detentores das imagens usadas.

Na hora de montar as tags, utilizei as keywords das sentenças para. Para isso, criei uma função para buscar as keywords e devolvê-las numa lista.

Ficou assim:


def get_tags(video_content):
    keywords = []

    for sentence in video_content['sentences']:
        for k in sentence['keywords']:
            if k not in keywords:
                keywords.append(k)
    
    return keywords

E após o upload, faço o set da thumbnail:


def set_thumbnail(youtube, video_id):
    print('Setting the thumbnail: {} for video: {}'.format(CONTENT_IMAGES_PATH + "/thumb_maxres.png", video_id))
    youtube.thumbnails().set(
        videoId=video_id,
        media_body=CONTENT_IMAGES_PATH + "/thumb_maxres.png"
    ).execute()

É isso!

Conclusão!

E assim encerro essa série de posts sobre o projeto Video-Creator. Muito feliz com o resultado final.

Sei que tem muitas coisas pra refatorar, pra evoluir, muitas oportunidades de novas implementações, mas o objetivo principal foi atingido: Receber um assunto e gerar um video para o Youtube automaticamente.

Espero que tenham gostado da série, qualquer dúvida, sugestão ou crítica, por favor entrem em contato. Se tiver algum assunto relacionado a essa série de posts que vocês queiram que eu me aprofunde um pouco mais na explicação, mandem um comentário pedindo, prometo trazer assim que possível.

Um grande abraço!

Video Creator – #Parte 7: Busca e download de imagens

Bom dia, boa tarde, boa noite!

Essa é a sétima parte da série sobre o projeto Video Creator, onde mostrarei como fiz a busca pelas imagens.

Se você entrou direto nesse post, te aconselho a começar por aqui, para entender exatamente do que se trata essa série.

Sobre essa parte

Basicamente o que fiz foi concatenar o assunto pesquisado com a primeira keyword da lista de keywords de cada sentença.

Bem simples!

Requisitos:

O principal requisito, é claro, é óbvio… criação do Bing Resource na Azure e a criação da instância do Bing Custom Search. Tudo isso eu mostrei no último post!

Utilizei também 2 imports praticamente pradrões nesse projeto:

import json
import requests

rimage.py

A parte da busca e do download das imagens, ficou no robô rimage.py.

A chamada ao endpoint do ping resolvi colocar dentro de uma função que recebe 2 parâmetros: a query de pesquisa e a quantidade de imagens que o serviço irá devolver. Ficou assim:

# implementando busca de imagens pelo Bing
def search_images_on_bing(query, count="1"):
    logging.info("Searching images on Bing with custom bing image search")

    url = credentials['bing_endpoint'] + "?q=" + query + "&count="+ count +"&customconfig=" + credentials['bing_custom_config_id'] +"&licence=ShareCommercially&size=Large"
    r = requests.get(url, headers={'Ocp-Apim-Subscription-Key': credentials['azure_subscription_key']})
    response = json.loads(r.text)
    if 'value' in response:
        result = [d['contentUrl'] for d in response['value']]
    else:
        result = []
    
    return result

Notem que essa função é bem simples, recebe uma query e a quantidade que ela deve retornar de resultado, ai foi só bater na api passando esses parâmetros, fazer o parser do json e extrair somente os links das imagens para enviar como retorno.

Para esse projeto eu utilizei os seguintes parâmetros:

  • licence=ShareCommercially
    • Retornará imagens que podem ser usadas com propósito pessoal ou comercial
  • size=Large
    • Retornará imagens de no mínimo 500×500 pixels

A Api do bing é realmente fantástica. Existem inúmeros parâmetros que podem ser usados para refinar a busca. Quem quiser personalizar ainda mais a busca, só ver os parametros disponíveis na página oficial da api:

https://docs.microsoft.com/en-us/rest/api/cognitiveservices-bingsearch/bing-custom-images-api-v7-reference

Criei uma outra função responsável por iterar nas sentenças, montar a query de pesquisa e chamar a função acima. Ficou assim:


def fetch_images_from_sentences():
    logging.info("Fetching images from sentences...")
    print("Fetching images from sentences", end='\n\n')
    # loading content
    logging.info("Get sentences from object saved")
    print("Loading content from content.json")
    video_content = rcontent.load()
    for sentence in video_content['sentences']:
        if len(sentence['keywords'])>0:
            if video_content['search_term'] != sentence['keywords'][0]:
                sentence['image_search_query'] = "{} {}".format(video_content['search_term'], sentence['keywords'][0])
                sentence['images'] = search_images_on_bing(sentence['image_search_query'], "5")
                time.sleep(1.5)
    rcontent.save(video_content)

Três pontos importantes aqui:

O primeiro é sobre o atributo sentence['image_search_query'], onde eu armazeno o termo que eu utilizei para buscar as imagens, e ele é composto pelo assunto do video + a primeira keyword da lista. Isso para evitar que seja buscado imagens com uma keyword muito genérica que não tenha ligação com o assunto principal.

O segundo é sobre como foi construído o fluxo das coisas. O robô de imagem funciona completamente independente dos demais. O que ele precisa é que exista um arquivo content.json na estrutura esperada. Por isso quando rodamos o rimage.py, ele utiliza a função load() do rcontent.py para buscar o conteúdo do video e efetuar a busca das imagens. Após encontrar as imagens, ele gera uma lista com os links e grava dentro do atributo images, dentro de sentences.

O terceiro ponto é o time.sleep(1.5) no final da função, que precisei incluir para respeitar os limites de Free Tier do Bing Resource. Com isso, eu garanto que só vou fazer 1 chamada por segundo.

Download das imagens

Para o download das imagens, inclui todos os passos dentro de uma função que eu chamei de download_images(). Ficou assim:


def download_images():
    logging.info("Downloading images from each sentences")
    #os.chdir('./')
    path = CONTENT_IMAGES_PATH

    # create directory
    os.makedirs(path, exist_ok=True)
    # limpando a pasta
    os.system("rm -rf {}/*".format(path))
    video_content = rcontent.load()

    list_img = []

    for idx_s, sentence in enumerate(video_content['sentences']):
        for idx_i, image in enumerate(sentence['images']):
            if image not in list_img:
                # if an image doesn't downloaded, try another one
                try:
                    print("Trying to download: ", image)
                    image_filename = "{}/{}_original.jpg".format(path,idx_s)
                    wget.download(image,image_filename)
                    list_img.append(image)
                    print("")
                    break
                except Exception as ex:
                    logging.error(ex)
                    continue
    
    video_content['images_used'] = list_img
    rcontent.save(video_content)

O que essa função faz é basicamente:

  1. verificar se a pasta onde ficará as imagens já existe, se não… cria…
  2. Remover todas as imagens existentes na pasta
  3. Carrega o conteúdo da content.json para buscar os links das imagens buscadas
  4. Itera nas sentenças e nas imagens encontradas.
  5. Faz uma verificação se a imagem já não foi baixada
  6. Tenta realizar o download da imagem, se por algum motivo ele não conseguir, ele tenta a próxima imagem.
  7. Grava o link das imagens baixadas dentro do atributo images_used e salva o objeto em content.json

Next steps?!

Com conteúdo textual e imagens devidamente providenciadas, é hora de começar a montar o video.

Mostro como fiz, no próximo post!

Abraço!

Python na prática: Projeto Video Creator – #Parte 3: Buscando o assunto escolhido na Wikipedia

Bom dia, boa tarde, boa noite!

Essa é a terceira parte da série sobre o projeto Video Creator, onde mostrarei a escolha pelo assunto, e a busca na Wikipedia.

Se você entrou direto nesse post, te aconselho a começar por aqui, para entender exatamente do que se trata essa série.

Sobre essa parte

Para essa versão inicial do projeto, segui a idéia do projeto original e minha fonte de dados textuais será apenas o Wikipedia. Mas já tenho algumas idéias pra evolução desse projeto :D.

Requisitos:

O consumo da API da Wikipedia também é bastante simples, precisei apenas da lib requests:

import requests

A URL que iremos consumir é a seguinte:

https://{language}.wikipedia.org/w/api.php?action=query&format=json&prop=extracts&exintro=1&exlimit=1&titles={subject}&explaintext=1&formatversion=2

Onde {language} é o idioma, neste caso coloquei como uma variável, pois é possível trocar e escolher outros idiomas. E {subject} é o assunto que iremos pesquisar.

A function que busca o conteúdo na wikipedia ficou assim:

def get_wikipedia_content(subject, lang):
    logging.info("Searching about the content choosen on wikipedia")
    print("")
    print("---------------------------------------------------------------------------------------------")
    print("Buscando conteúdo na wikipedia para assunto escolhido: {}".format(subject), end="\n\n")
    try:
        # main subject
        #url = "https://{}.wikipedia.org/api/rest_v1/page/summary/{}".format(lang, subject)
        main_url = WIKIPEDIA_MAIN_URL.format(lang, urllib.parse.unquote(subject))
        main_content = requests.get(main_url)
        main_content_json = main_content.json()
        main_result = main_content_json['query']['pages'][0]
        if  'missing' in main_content_json:
            return main_content_json['missing']
        # media
        media_url = "https://{}.wikipedia.org/api/rest_v1/page/media-list/{}?redirect=false".format(lang, subject)
        media_content = requests.get(media_url)
        media_content_json = media_content.json()
        # get images if there is
        if 'items' in media_content_json:
            media_result = media_content_json['items']
            # incluindo imagens no payload principal
            main_result['images'] = media_result
        # removing unnecessary keys
        main_result.pop('pageid', None)
        main_result.pop('ns', None)

        if 'extract' in main_result:
            return main_result['extract']
        else:
            raise ValueError("Conteúdo não encontrado")

    except Exception as ex:
        logging.error(ex)
        print(ex)

Mas como ocorre a escolha do assunto?

Para selecionar um assunto e chamar a function que buscará o conteúdo na wikipedia, eu encapsulei todo esse fluxo dentro de uma function chamada ask_for_a_subject(), que é responsável por buscar os trending topics do Google e do Twitter, mostrar no terminal o primeiro colocado de cada um e ainda uma terceira opção caso eu deseje digitar um assunto.

Abaixo segue como ficou a função:

def ask_for_a_subject():
    try:
        print("Getting google Trends...")
        gsubject = get_google_trends()
        print("Getting Twitter Trends...", end="\n\n")
        tsubject = get_twitter_trends()

        options = {}
        options[1] = gsubject[0]['title']
        options[2] = tsubject[0]['name']
        options[3] = "Outro"

        # log
        logging.info("--- Asking for content ---")
        # define variable
        content_choosen = "Nenhuma opção escolhida"
        print("Escolha uma das opções", end="\n\n")
        for k in options:
            print("{}) {}".format(k, options[k]))
        
        while content_choosen not in options:
            user_input = int(input("Digite o numero do conteúdo desejado: "))
            if user_input in options:
                content_choosen = options[int(user_input)]
                if content_choosen == 'Outro':
                    content_choosen = input("Digite um termo para ser pesquisado: ")
                    break    
                break
            else:
                print("Escolha uma opção válida")
    except Exception as ex:
        return ex

    return str(content_choosen)

Após a escolha do assunto, é solicitado a escolha da categoria desse conteúdo. Essa categoria será usada no upload do video.

A lista de categorias disponíveis coloquei fixo mesmo, dentro do arquivo rconfig.py. Ficou assim:

# FOR YOUTUBE
YOUTUBE_CATEGORY_LIST = [
        (1, 'Film & Animation'),
        (2, 'Autos & Vehicles'),
        (10, 'Music'),
        (15, 'Pets & Animals'),
        (17, 'Sports'),
        (18, 'Short Movies'),
        (19, 'Travel & Events'),
        (20, 'Gaming'),
        (21, 'Videoblogging'),
        (22, 'People & Blogs'),
        (23, 'Comedy'),
        (24, 'Entertainment'),
        (25, 'News & Politics'),
        (26, 'Howto & Style'),
        (27, 'Education'),
        (28, 'Science & Technology'),
        (29, 'Nonprofits & Activism'),
        (30, 'Movies'),
        (31, 'Anime/Animation'),
        (32, 'Action/Adventure'),
        (33, 'Classics'),
        (34, 'Comedy'),
        (35, 'Documentary'),
        (36, 'Drama'),
        (37, 'Family'),
        (38, 'Foreign'),
        (39, 'Horror'),
        (40, 'Sci-Fi/Fantasy'),
        (41, 'Thriller'),
        (42, 'Shorts'),
        (43, 'Shows'),
        (44, 'Trailers')
    ]

A função ficou assim:

def ask_for_a_category():
    # log
    logging.info("--- Asking for a category ---")
    print("Qual a categoria do conteúdo? ", end="\n\n")

    category_choosen = 0
    available_options = []
    for category in YOUTUBE_CATEGORY_LIST:
        print("{}) {}".format(category[0], category[1]))
        available_options.append(category[0])
    
    while category_choosen == 0:
        user_input = int(input("Digite o numero da categoria escolhida: "))
        if user_input in available_options:
            category_choosen = user_input
            break
        else:
            print("Escolha uma opção válida")

    return str(category_choosen)

Uma coisa importante, é que o id da categoria apesar de ser um numero inteiro, na API do Youtube, o atributo category_id espera receber uma string.

Após a escolha da categoria, a função get_wikipedia_content() é invocada passando o assunto escolhido e o idioma:


def get_wikipedia_content(subject, lang):
    logging.info("Searching about the content choosen on wikipedia")
    print("")
    print("---------------------------------------------------------------------------------------------")
    print("Buscando conteúdo na wikipedia para assunto escolhido: {}".format(subject), end="\n\n")
    try:
        # main subject
        #url = "https://{}.wikipedia.org/api/rest_v1/page/summary/{}".format(lang, subject)
        main_url = WIKIPEDIA_MAIN_URL.format(lang, urllib.parse.unquote(subject))
        main_content = requests.get(main_url)
        main_content_json = main_content.json()
        main_result = main_content_json['query']['pages'][0]
        if  'missing' in main_content_json:
            return main_content_json['missing']
        # media
        media_url = "https://{}.wikipedia.org/api/rest_v1/page/media-list/{}?redirect=false".format(lang, subject)
        media_content = requests.get(media_url)
        media_content_json = media_content.json()
        # get images if there is
        if 'items' in media_content_json:
            media_result = media_content_json['items']
            # incluindo imagens no payload principal
            main_result['images'] = media_result
        # removing unnecessary keys
        main_result.pop('pageid', None)
        main_result.pop('ns', None)

        if 'extract' in main_result:
            return main_result['extract']
        else:
            raise ValueError("Conteúdo não encontrado")

    except Exception as ex:
        logging.error(ex)
        print(ex)

No próximo post, mostrarei como fiz para a limpeza e interpretação do texto.

Um abraço e até o próximo post!

Python na prática: Projeto Video Creator – #Parte 2: Idéias de conteúdo

Bom dia, boa tarde, boa noite!

Este é o segundo post da série sobre o projeto Video Creator, onde mostrarei o consumo de RSS do Google trends e a busca pelos Trending topics do Twitter para sugerir conteúdos para o video.

Se você entrou direto nesse post, te aconselho a começar por aqui, para entender exatamente do que se trata essa série.

Sobre essa parte

Para esse projeto, resolvi mostrar apenas o primeiro colocado do Google e do Twitter, porém os serviços retornam bem mais informações que vocês podem consumir e utilizar para personalizar o robô de vocês.

Lembrem-se, esse projeto é apenas uma POC… um start pra coisas maiores.

Requisitos

Essa parte é bastante simples, pois o Google possui um serviço de RSS aberto onde você consegue ver os assuntos mais buscados do dia. E o Twitter possui uma API bastante simples de consumir, onde também faremos uso do de uma requisição simples a uma URL, a diferença é que para o Twitter, precisaremos de uma API KEY.

Para o Google, utilizei a seguinte URL:

https://trends.google.com.br/trends/trendingsearches/daily/rss?geo=BR

Ao consultar a URL, temos o documento XML seguinte:

Isso é muito legal! 😀

Para o Twitter, utilizei URL padrão da api, passando como parâmetro o id referente ao Brasil, assim, o resultado será apenas os trending topics do Brasil:

https://api.twitter.com/1.1/trends/place.json?id=23424768

Então basicamente o que precisei fazer, foi bater nessas URLs e fazer o parser para dentro do meu código para extrair os dados que eu queria, que nesse caso, foi apenas o atributo title do Google Trends, e o atributo name do Trending Topics do primeiro colocado.

Pra isso utilizei as libs requests e xmltodict:

import requests
import xmltodict

Para o Google trends, encapsulei a requisição e o parser na função abaixo:

def get_google_trends():

    def parser_xml(v_xml):
        key_words = []
        # parser
        content_xml = xmltodict.parse(v_xml)

        for i in content_xml['rss']['channel']['item']:
            
            rel_news = []

            for j in i['ht:news_item']:
                
                if not isinstance(j, str):
                    rel_news.append(j['ht:news_item_title'])

            obj = {
                "title": "{}".format(i['title']), 
                "traffic": "{}".format(i['ht:approx_traffic']),
                "pubDate": "{}".format(i['pubDate']),
                "description": "{}".format(i['description']),
                "related_news": rel_news,
                "dateInsert": datetime.datetime.now()
                }
            key_words.append(obj)
        
        return key_words

    logging.info("--- Getting GOOGLE TRENDS ---")
    # URL do trending topics do Google
    url = "https://trends.google.com.br/trends/trendingsearches/daily/rss?geo=BR"

    content = requests.get(url)
    return parser_xml(content.text)

E para o trending topics do Twitter:

def get_twitter_trends():
    logging.info("--- Getting TWITTER TRENDS ---")
    
    headers = {"Authorization": "Bearer {}".format(credentials['api_bearer_token'])}
    url = "https://api.twitter.com/1.1/trends/place.json?id=23424768"
    response = requests.get(url, headers=headers)
    
    content = []
    
    for i in response.json():
        for j in i['trends']:
            content.append({
                "at": datetime.datetime.now(),
                "as_of": i['as_of'],
                "location": i['locations'][0]['name'],
                "name": j['name'],
                "tweet_volume": j['tweet_volume']
            })
    return content

Essas 2 funções são chamadas dentro de uma outra função que detalharei no próximo post onde falarei sobre a busca pelo conteúdo desejado na wikipedia.

Até o próximo post!

Abraços!

Gerando videos para o Youtube com linguagem Python

Navegando pelo Youtube a mais ou menos 2 anos atrás, me deparei com uma playlist do canal Filipe Deschamps onde ele mostrava como havia programado 4 robôs para automatizar a criação de videos para o Youtube fornecendo apenas o assunto para o robô.

Para quem quiser conferir, esse é o link do primeiro video da série:

Programei 4 robôs que criam vídeos para mim no YouTube

Bom, na época havia começado minha jornada de aprendizado em Python, e resolvi que faria um projeto similar, utilizando Python, e ferramentas alternativas as utilizadas no projeto original.

Pelos meses seguinte, a idéia não saiu do papel, por diversas razões que não precisam ser citadas aqui.

Até que no final de 2021, resolvi que tiraria esse projeto do papel, apenas por diversão e para praticar um pouco de Python… foi bem divertido :D.

O projeto ficou pronto e pode ser conferido no repositório que postarei mais abaixo. Porém não foi fácil concluí-lo. Diversas coisas no projeto segui o exatamente o que ele fez, outras nem tanto. Também utilizei muito do conhecimento passado nos videos do Filipe Deschamps, porém ele usou Node.js e como resolvi fazer em Python, muitas coisas precisei pesquisar como poderia fazer, quais libs poderia usar, etc.

Então para registrar o conhecimento que adquiri com esse pequeno projeto, resolvi escrever uma série de posts, cada qual abordando um pedaço do projeto, assim como o Filipe fez em video.

O objetivo principal é para reforçar, por meio do repasse, o aprendizado adquirido. Espero que estes posts possam ajudar vocês de alguma forma, seja com o conteúdo técnico ou simplesmente motivando-os a iniciarem seus projetos pessoais. É a melhor forma de aprender, e como o Filipe falou nos videos, são nesses projetos, que podemos usar toda e qualquer tecnologia que temos vontade, sem nos preocupar se é viável ou não.

Repositório com o projeto concluído:
https://github.com/thmlima87/videocreator

O que foi usado no projeto?

Apesar de parecer simples, o projeto envolveu bastante coisa legal:

Bora começar!

Abaixo os links de todos os posts para facilitar a navegação.

Parte 1: Arquitetura da aplicação
Parte 2: Idéias de conteúdo!
Parte 3: Buscando o assunto escolhido na Wikipedia
Parte 4: Limpeza e interpretação do texto
Parte 5: Persistência do conteúdo
Parte 6: Bing Custom Search
Parte 7: Busca e download de imagens
Parte 8: Tratamento das imagens
Parte 9: Renderização do video
Parte 10: Upload para o Youtube

Exit mobile version