01/05/2024

Consultando o WordPress, usando Python

WordPress é uma das plataformas mais populares do mundo para construção de Websites e blogs. A Ontologia da EximiaCo foi construída com WordPress.

Os consultores da EximiaCo colaboram com a produção de conteúdo que está devidamente organizado em classes.

Buscando dados do WordPress

O WordPress disponibiliza uma API RESTish que permite obtenção fácil de informações a respeito de um site.

Python
import pandas as pd
import requests
from cachetools import cached, TTLCache
from datetime import datetime


class WordPress:
    def __init__(self, url):
        self.url = url

    @cached(cache=TTLCache(maxsize=100, ttl=300))
    def get_post_types(self):
        endpoint = '/wp-json/wp/v2/types'
        api_url = f'{self.url}{endpoint}'

        response = requests.get(api_url)
        post_types = response.json()

        if response.status_code == 200:
            data = [{'key': key, 'name': value['name']} for key, value in post_types.items()]
            return pd.DataFrame(data)
        else:
            return pd.DataFrame()

    @cached(cache=TTLCache(maxsize=100, ttl=300))
    def get_users(self):
        api_url = f'{self.url}/wp-json/wp/v2/users'

        response = requests.get(api_url)

        if response.status_code == 200:
            users_data = response.json()
            df = pd.DataFrame(users_data)
            return df
        else:
            return pd.DataFrame()

    @cached(cache=TTLCache(maxsize=100, ttl=300))
    def get_posts(self, post_type_slug, start_date, end_date):

        start_iso = (datetime.strptime(start_date, '%Y-%m-%d')
                     .replace(hour=0, minute=0, second=0)
                     .strftime('%Y-%m-%dT%H:%M:%S'))
        end_iso = (datetime.strptime(end_date, '%Y-%m-%d')
                   .replace(hour=23, minute=59, second=59)
                   .strftime('%Y-%m-%dT%H:%M:%S'))

        endpoint = f'/wp-json/wp/v2/{post_type_slug}'
        api_url = f'{self.url}{endpoint}'

        params = {
            'after': start_iso,
            'before': end_iso,
            'date_gmt': ''
        }

        response = requests.get(api_url, params=params)
        posts = response.json()

        if response.status_code == 200 and isinstance(posts, list):
            data = [
                {'ID': post['id'],
                 'Title': post['title']['rendered'],
                 'Modified': post['modified'],
                 'Created': post['date_gmt'],
                 'AuthorId': post.get('author', 1)
                 } for post in posts]
            df = pd.DataFrame(data)
            return df
        else:
            return pd.DataFrame()

Tenho optado por retornar Dataframes do Pandas quase sempre. Isso torna a interação com os dados algo fácil.

Outra coisa que resolvi fazer nessa implementação foi utilizar um cache em memória mesmo. A ideia é reduzir a quantidade de “ataques” no servidor para informações que considero estáveis.

Facilitando as pesquisas envolvendo períodos semanais

Boa parte das consultas que irei fazer contra meu WordPress serão relacionadas a períodos semanais – ou seja, começando em um domingo e encerrando no próximo sábado. Para tornar a especificação desses intervalos mais fácil, criei uma classe helper.

Python
from datetime import timedelta, datetime


class Weeks:
    @staticmethod
    def get_week_dates(reference_date):
        start_of_week = reference_date - timedelta(days=reference_date.weekday() + 1)
        end_of_week = start_of_week + timedelta(days=6)
        return start_of_week.strftime('%Y-%m-%d'), end_of_week.strftime('%Y-%m-%d')

    @staticmethod
    def get_current():
        today = datetime.now()
        return Weeks.get_week_dates(today)

    @staticmethod
    def get_previous(n = 1):
        today = datetime.now()
        last_week_date = today - timedelta(days=7 * n)
        return Weeks.get_week_dates(last_week_date)

    @staticmethod
    def get_week_string_from_date(reference_date):
        start, end = Weeks.get_week_dates(reference_date)
        return Weeks.get_week_string_from_interval(start, end)

    @staticmethod
    def get_week_string_from_interval(start, end):
        star_f = datetime.fromisoformat(start).strftime('%d/%m')
        end_f = datetime.fromisoformat(end).strftime('%d/%m')
        return f'{star_f} - {end_f}'

Adicionando semântica

O WordPress é uma plataforma de propósito geral. A classe que desenvolvi consegue lidar bem com qualquer WordPress, mas deixa um bocado de interpretações a cargo do desenvolvedor.

Quase sempre, considero criar uma “camada semântica” sobre classes de propósito geral como a que desenvolvemos, adicionando significado específico para o contexto (domínio) em que estou trabalhando.

Python
import pandas as pd
from datetime import datetime

from src.wordpress import WordPress
from src.weeks import Weeks

class Ontologia:
    def __init__(self):
        self.wp = WordPress('https://ontologia.eximia.co')

    def get_classes(self):
        df = self.wp.get_post_types()
        classes = df[
            ~(df['key'].str.startswith('wp_') |
              df['key'].str.startswith('nav_') |
              df['key'].str.contains('jet-engine') |
              df['key'].str.contains('assets') |
              df['key'].str.contains('classes') |
              df['key'].str.contains('page') |
              df['key'].str.contains('post') |
              df['key'].str.contains('links') |
              df['key'].str.contains('media') |
              df['key'].str.contains('attachment') |
              df['key'].str.contains('visibility_preset') |
              df['key'].str.endswith('_links') |
              df['key'].str.endswith('-links')
              )
        ]
        return classes

    def get_authors(self):
        df = self.wp.get_users()
        return df[~(df['name'].str.contains('admin'))]

    def get_entries(self, start_date, end_date):
        classes_df = self.get_classes()
        entries_list = []

        for index, row in classes_df.iterrows():
            post_type_slug = row['key']
            posts_df = self.wp.get_posts(post_type_slug, start_date, end_date)

            posts_df['ClassKey'] = row['key']
            posts_df['ClassName'] = row['name']

            entries_list.append(posts_df)

        final_df = pd.concat(entries_list, ignore_index=True)
        final_df = final_df[~(final_df['AuthorId'] == 1)]

        user_name_map = self.get_authors().set_index('id')['name'].to_dict()
        final_df['AuthorName'] = final_df['AuthorId'].map(user_name_map)
        return final_df

    def get_summary_by_author(self, start_date, end_date):
        entries_df = self.get_entries(start_date, end_date)
        summary_df = entries_df.groupby('AuthorName').size().reset_index(name='Count')

        start_date_formatted = pd.to_datetime(start_date).strftime('%d/%m')
        end_date_formatted = pd.to_datetime(end_date).strftime('%d/%m')
        date_column_title = f"{start_date_formatted} - {end_date_formatted}"

        summary_df.columns = ['Author', date_column_title]

        return summary_df

    def get_summary_by_class(self, start_date, end_date):
        entries_df = self.get_entries(start_date, end_date)
        summary_df = entries_df.groupby('ClassName').size().reset_index(name='Count')

        start_date_formatted = pd.to_datetime(start_date).strftime('%d/%m')
        end_date_formatted = pd.to_datetime(end_date).strftime('%d/%m')
        date_column_title = f"{start_date_formatted} - {end_date_formatted}"

        summary_df.columns = ['Class', date_column_title]

        return summary_df

    def get_weekly_summary_by(self, by, alias, number_of_weeks):
        start, _ = Weeks.get_previous(number_of_weeks)
        _, end = Weeks.get_current()

        entries = self.get_entries(start, end)

        def week(row):
            ref = datetime.fromisoformat(row["Created"])
            return Weeks.get_week_string_from_date(ref)

        entries["Week"] = entries.apply(week, axis=1)

        result = pd.DataFrame(columns=[alias])

        for i in range(number_of_weeks):
            start, end = Weeks.get_previous(i)
            week = Weeks.get_week_string_from_interval(start, end)
            df = entries[entries['Week'] == week]

            summary_df = df.groupby(by).size().reset_index(name='Count')
            summary_df.columns = [alias, week]
            result = pd.merge(summary_df, result, on=alias, how='outer')

        result.fillna(0, inplace=True)

        return result

Aqui, a classe semântica substitui a ideia de “usuários” por “autores”, “tipos de postagem” por “classes”, “postagem” por “entradas”.

Além disso, adicionei algumas consultas de sumarização.

Deixe seu comentário

Subscribe
Notify of
0 Comentários
Oldest
Newest Most Voted
Feedbacks interativos
Ver todos os comentários

Últimos posts

Curso Reputação e Marketing Pessoal

Masterclasses

01

Introdução do curso

02

Por que sua “reputação” é importante?

03

Como você se apresenta?

04

Como você apresenta suas ideias?

05

Como usar Storytelling?

06

Você tem uma dor? Eu tenho o alívio!

07

Escrita efetiva para não escritores

08

Como aumentar (e manter) sua audiência?

09

Gatilhos! Gatilhos!

10

Triple Threat: Domine Produto, Embalagem e Distribuição

11

Estratégias Vencedoras: Desbloqueie o Poder da Teoria dos Jogos

12

Análise SWOT de sua marca pessoal

13

Soterrado por informações? Aprenda a fazer gestão do conhecimento pessoal, do jeito certo

14

Vendo além do óbvio com a Pentad de Burkle

15

Construindo Reputação através de Métricas: A Arte de Alinhar Expectativas com Lag e Lead Measures

16

A Tríade da Liderança: Navegando entre Líder, Liderado e Contexto no Mundo do Marketing Pessoal

17

Análise PESTEL para Marketing Pessoal

18

Canvas de Proposta de Valor para Marca Pessoal

19

Método OKR para Objetivos Pessoais

20

Análise de Competências de Gallup

21

Feedback 360 Graus para Autoavaliação

22

Modelo de Cinco Forças de Porter

23

Estratégia Blue Ocean para Diferenciação Pessoal

24

Análise de Tendências para Previsão de Mercado

25

Design Thinking para Inovação Pessoal

26

Metodologia Agile para Desenvolvimento Pessoal

27

Análise de Redes Sociais para Ampliar Conexões

Lições complementares

28

Apresentando-se do Jeito Certo

29

O mercado remunera raridade? Como evidenciar a sua?

30

O que pode estar te impedindo de ter sucesso

Recomendações de Leituras

31

Aprendendo a qualificar sua reputação do jeito certo

32

Quem é você?

33

Qual a sua “IDEIA”?

34

StoryTelling

35

Você tem uma dor? Eu tenho o alívio!

36

Escrita efetiva para não escritores

37

Gatilhos!

38

Triple Threat: Domine Produto, Embalagem e Distribuição

39

Estratégias Vencedoras: Desbloqueie o Poder da Teoria do Jogos

40

Análise SWOT de sua marca pessoal

Inscrição realizada com sucesso!

No dia da masterclass você receberá um e-mail com um link para acompanhar a aula ao vivo. Até lá!

A sua subscrição foi enviada com sucesso!

Aguarde, em breve entraremos em contato com você para lhe fornecer mais informações sobre como participar da mentoria.

Masterclass
15/07

Pare de dar a solução certa para o problema errado

Muita gente boa quebra a cabeça por dias tentando resolver o que não estava quebrado, simplesmente por tentar dar a resposta certa pro problema errado, mas precisa realmente ser assim?

Crie sua conta

Preencha os dados para iniciar o seu cadastro no plano anual do Clube de Estudos:

Crie sua conta

Preencha os dados para iniciar o seu cadastro no plano mensal do Clube de Estudos:

0
Quero saber a sua opinião, deixe seu comentáriox
× Precisa de ajuda?