From f4e7750bd2f9be23861f7122a437f9ee7992e069 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9F=B3=E7=A5=9E?= <3162475700@qq.com> Date: Mon, 22 Jul 2024 10:55:44 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=9A=88=E9=87=87=E7=94=A8fastAPI=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0=E5=90=8E=E7=AB=AF=EF=BC=8C=E6=94=BE=E5=BC=83Flask?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- deploy.sh | 2 +- .../__pycache__/__init__.cpython-311.pyc | Bin 187 -> 187 bytes .../__pycache__/get_info.cpython-311.pyc | Bin 11514 -> 11835 bytes friend_circle_lite/get_info.py | 5 +- grab.log | 3 + run.py | 2 +- server.py | 74 ++++++++++++++---- 7 files changed, 66 insertions(+), 20 deletions(-) create mode 100644 grab.log diff --git a/deploy.sh b/deploy.sh index 4105e35..b5bb679 100644 --- a/deploy.sh +++ b/deploy.sh @@ -1,2 +1,2 @@ #!/bin/bash -nohup python server.py > grab.log 2>&1 & +nohup python3 server.py > grab.log 2>&1 & diff --git a/friend_circle_lite/__pycache__/__init__.cpython-311.pyc b/friend_circle_lite/__pycache__/__init__.cpython-311.pyc index 995bb7a51e59a9cb99e70ef5755e2a98bc6416e0..a8eadd549cdf9d993858d950fc3eb0e64c41ce5d 100644 GIT binary patch delta 19 ZcmdnZxSNrCIWI340}woYFnc2R1^_gk1^WO1 delta 19 ZcmdnZxSNrCIWI340}$|aG*9H-001p~1hfDE diff --git a/friend_circle_lite/__pycache__/get_info.cpython-311.pyc b/friend_circle_lite/__pycache__/get_info.cpython-311.pyc index ead2e1a3d648ab1f585b1a46567bc7067715286e..f4f17c4eec5ecebc0d9e3a9794ecf0aea2227de4 100644 GIT binary patch delta 2476 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 KHS^0Qbn_pdM=S0C diff --git a/friend_circle_lite/get_info.py b/friend_circle_lite/get_info.py index 8657b31..235fb92 100644 --- a/friend_circle_lite/get_info.py +++ b/friend_circle_lite/get_info.py @@ -207,6 +207,7 @@ def fetch_and_process_data(json_url, count=5): error_friends = 0 total_articles = 0 article_data = [] + error_friends_info = [] with ThreadPoolExecutor(max_workers=10) as executor: future_to_friend = { @@ -224,9 +225,11 @@ def fetch_and_process_data(json_url, count=5): total_articles += len(result['articles']) else: error_friends += 1 + error_friends_info.append(friend) except Exception as e: print(f"处理 {friend} 时发生错误: {e}") error_friends += 1 + error_friends_info.append(friend) result = { 'statistical_data': { @@ -242,7 +245,7 @@ def fetch_and_process_data(json_url, count=5): print("数据处理完成") print("总共有 %d 位朋友,其中 %d 位博客可访问,%d 位博客无法访问" % (total_friends, active_friends, error_friends)) - return result + return result, error_friends_info def sort_articles_by_time(data): """ diff --git a/grab.log b/grab.log new file mode 100644 index 0000000..33c61ed --- /dev/null +++ b/grab.log @@ -0,0 +1,3 @@ +2024-07-22 10:21:56,649 - INFO - ʼץȡ... +2024-07-22 10:21:56,653 - INFO - ڴ https://blog.qyliu.top/friend.json лȡÿͻȡ 5 ƪ +2024-07-22 10:22:32,855 - INFO - ץȡɹ diff --git a/run.py b/run.py index ad9fc80..c3ed6a2 100644 --- a/run.py +++ b/run.py @@ -15,7 +15,7 @@ if config["spider_settings"]["enable"]: json_url = config['spider_settings']['json_url'] article_count = config['spider_settings']['article_count'] print("正在从 {json_url} 中获取,每个博客获取 {article_count} 篇文章".format(json_url=json_url, article_count=article_count)) - result = fetch_and_process_data(json_url=json_url, count=article_count) + result, _ = fetch_and_process_data(json_url=json_url, count=article_count) sorted_result = sort_articles_by_time(result) with open("all.json", "w", encoding="utf-8") as f: json.dump(sorted_result, f, ensure_ascii=False, indent=2) diff --git a/server.py b/server.py index f497f56..c41c543 100644 --- a/server.py +++ b/server.py @@ -1,21 +1,19 @@ -from flask import Flask, jsonify -from flask_apscheduler import APScheduler +from fastapi import FastAPI +from fastapi.responses import JSONResponse, HTMLResponse +from apscheduler.schedulers.asyncio import AsyncIOScheduler from threading import Lock import logging import os +import json +import random from friend_circle_lite.get_info import fetch_and_process_data, sort_articles_by_time from friend_circle_lite.get_conf import load_config -app = Flask(__name__) +app = FastAPI() # 配置APScheduler -class Config: - SCHEDULER_API_ENABLED = True - -app.config.from_object(Config()) -scheduler = APScheduler() -scheduler.init_app(app) +scheduler = AsyncIOScheduler() scheduler.start() # 配置日志记录 @@ -23,11 +21,15 @@ log_file = "grab.log" logging.basicConfig(filename=log_file, level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') # 全局变量 -articles_data = [] +articles_data = { + "statistical_data": {}, + "article_data": [] +} +error_friends_info = [] data_lock = Lock() def fetch_articles(): - global articles_data + global articles_data, error_friends_info logging.info("开始抓取文章...") config = load_config("./conf.yaml") if config["spider_settings"]["enable"]: @@ -35,27 +37,65 @@ def fetch_articles(): article_count = config['spider_settings']['article_count'] logging.info(f"正在从 {json_url} 中获取,每个博客获取 {article_count} 篇文章") try: - result = fetch_and_process_data(json_url=json_url, count=article_count) + result, errors = fetch_and_process_data(json_url=json_url, count=article_count) sorted_result = sort_articles_by_time(result) with data_lock: articles_data = sorted_result + error_friends_info = errors logging.info("文章抓取成功") except Exception as e: logging.error(f"抓取文章时出错: {e}") # 每四个小时抓取一次文章 -scheduler.add_job(id='Fetch_Articles_Job', func=fetch_articles, trigger='interval', hours=4) +scheduler.add_job(fetch_articles, 'interval', hours=4) -@app.route('/all', methods=['GET']) -def get_all_articles(): +@app.get("/", response_class=HTMLResponse) +async def root(): + html_content = """ + + + + Friend Circle Lite + + +

欢迎使用 Friend Circle Lite

+

这是一个轻量版友链朋友圈,有两种部署方式,其中自部署使用 fastAPI,还有 github action 部署方式,可以很方便的从友链中获取文章并展示到前端。

+ + + + """ + return HTMLResponse(content=html_content) + +@app.get('/all') +async def get_all_articles(): with data_lock: - return jsonify(articles_data) + return JSONResponse(content=articles_data) + +@app.get('/errors') +async def get_error_friends(): + with data_lock: + return JSONResponse(content=error_friends_info) + +@app.get('/random') +async def get_random_article(): + with data_lock: + if articles_data["article_data"]: + random_article = random.choice(articles_data["article_data"]) + return JSONResponse(content=random_article) + else: + return JSONResponse(content={"error": "No articles available"}, status_code=404) if __name__ == '__main__': + import uvicorn + # 清空日志文件 if os.path.exists(log_file): with open(log_file, 'w'): pass fetch_articles() # 启动时立即抓取一次 - app.run(port=1223) + uvicorn.run(app, host='0.0.0.0', port=1223)