main.py 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. """
  2. 目的:
  3. 流量週報圖表自動化更新,可以往回查詢。
  4. 參考:
  5. ECHARTS: https://echarts.apache.org/zh/tutorial.html#5%20%E5%88%86%E9%92%9F%E4%B8%8A%E6%89%8B%20ECharts
  6. templates: https://fastapi.tiangolo.com/advanced/templates/
  7. """
  8. from fastapi import FastAPI, Request
  9. from fastapi.responses import HTMLResponse
  10. from fastapi.staticfiles import StaticFiles
  11. from fastapi.templating import Jinja2Templates
  12. import dataset
  13. import numpy as np
  14. import pandas as pd
  15. from starlette.responses import Response
  16. from pprint import pprint
  17. app = FastAPI()
  18. app.mount("/static", StaticFiles(directory="static"), name="static")
  19. templates = Jinja2Templates(directory="templates")
  20. WEEK_NUM = 31
  21. def update_weekly_data():
  22. """
  23. 一週更新一次。
  24. """
  25. pass
  26. def get_hhh_weekly_data():
  27. """ 取得此table的資料作為後續畫圖使用。 """
  28. db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/hhh?charset=utf8mb4')
  29. table = db['hhh_weekly_report']
  30. df = pd.DataFrame(table)
  31. int_columns = ['id', 'ga:users', 'ga:newusers', 'ga:sessions', 'ga:pageviews', 'ga:isoWeek']
  32. float_columns = ['ga:bounceRate', 'ga:pageviewsPerSession']
  33. str_columns = ['category']
  34. for column in int_columns:
  35. df[column] = df[column].apply(func=lambda x: int(x))
  36. for column in float_columns:
  37. df[column] = df[column].apply(func=lambda x: float(x))
  38. for column in str_columns:
  39. df[column] = df[column].apply(func=lambda x: str(x))
  40. return df
  41. def get_dates(df, weeknum):
  42. """ 從df得到當週日期當作X-axis給Echart使用。 """
  43. dates = df[df['ga:isoWeek'] == weeknum]['ga:date']
  44. return sorted(list(set(dates)))
  45. def get_users(df, category='organic', weeknum=26, is_new=True):
  46. if is_new:
  47. users = df[(df['category'] == category) & (df['ga:isoWeek'] == weeknum)]['ga:users']
  48. else:
  49. users = df[(df['category'] == category) & (df['ga:isoWeek'] == weeknum)]['ga:newusers']
  50. return list(users)
  51. ##########################
  52. df = get_hhh_weekly_data()
  53. dates = get_dates(df, 25)
  54. users_social = get_users(df, 'organic', 25, True)
  55. print(df)
  56. print(dates)
  57. print(users_social)
  58. db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/hhh?charset=utf8mb4')
  59. query = f"""
  60. select
  61. A.query, A.clicks, A.ctr, A.impressions, A.weeknum,
  62. B.weeknum as last_wk_weeknum, B.clicks as last_wk_clicks, B.ctr as last_wk_ctr, B.impressions as last_wk_impressions,
  63. ((A.clicks-B.clicks) / B.clicks)*100 as clicks_growth
  64. from
  65. ((select query, clicks, ctr, impressions, weeknum
  66. from hhh.hhh_weekly_keywords
  67. where weeknum={WEEK_NUM+1} and clicks >=5) as A
  68. inner join (select query, clicks, ctr, impressions, weeknum from hhh.hhh_weekly_keywords where weeknum={WEEK_NUM} and clicks >= 5) as B
  69. on A.query=B.query)
  70. order by
  71. clicks_growth desc
  72. limit 20;
  73. """
  74. keywords_data = db.query(query)
  75. keywords_data = pd.DataFrame(keywords_data, columns=['query', 'clicks', 'ctr', 'impressions', 'weeknum', 'p_weeknum', 'p_clicks', 'p_ctr', 'p_impressions', 'clicks_growth'])
  76. # keywords_data = pd.read_csv('keywords_growth_ckover5.csv')
  77. print(keywords_data)
  78. ###########################
  79. @app.get('/', response_class=HTMLResponse)
  80. def index(request: Request):
  81. return templates.TemplateResponse(
  82. name='index.html',
  83. context={'request': request, 'dates': dates, 'users': users_social, 'keywords_table_html': keywords_data.to_html()}
  84. )
  85. # 要改
  86. @app.get('/keywords/table/{weeknum}', response_class=HTMLResponse) # https://fastapi.tiangolo.com/advanced/custom-response/
  87. def get_keywords_table(weeknum: int, request: Request, response: Response):
  88. resp = keywords_data.copy()
  89. resp.index = range(1, len(resp)+1)
  90. resp = resp[['query', 'clicks_growth', 'ctr', 'clicks', 'impressions']]
  91. resp.loc[:, 'clicks_growth'] = resp.loc[:, 'clicks_growth'].apply(func=lambda x: '{:.2f}'.format(x))
  92. resp.loc[:, 'ctr'] = resp.loc[:, 'ctr'].apply(func=lambda x: str(round(x*100, 4))[:str(x).index('.')+4] + ' %')
  93. pprint(request)
  94. pprint(response)
  95. return resp.to_html(justify='center')
  96. @app.get('/users/{category}/{weeknum}/{is_new}')
  97. def get_users_data(category: str, weeknum: int, is_new: bool):
  98. dates = get_dates(df, weeknum)
  99. users = get_users(df, category, weeknum, is_new)
  100. return {
  101. 'dates': dates,
  102. 'users': users
  103. }
  104. @app.get('/users/{weeknum}')
  105. def get_users_overview(weeknum: int):
  106. dates = get_dates(df, weeknum)
  107. organic_newusers = get_users(df, 'organic', weeknum, True)
  108. organic_users = get_users(df, 'organic', weeknum, False)
  109. social_newusers = get_users(df, 'social', weeknum, True)
  110. social_users = get_users(df, 'social', weeknum, False)
  111. return {
  112. 'dates': dates,
  113. 'organic_newusers': organic_newusers,
  114. 'organic_users': organic_users,
  115. 'social_newusers': social_newusers,
  116. 'social_users': social_users
  117. }
  118. @app.get('/keywords/{weeknum}')
  119. def get_keywords_sorted(weeknum: int):
  120. keywords = list(keywords_data.loc[:, 'query'])
  121. # print(keywords)
  122. keywords_growth = list(keywords_data.loc[:, 'clicks_growth'])
  123. return {'keywords': keywords, 'keywords_growth': keywords_growth}