Skip to content

Commit 3c7a6be

Browse files
committed
Multy user
1 parent 4366db8 commit 3c7a6be

4 files changed

Lines changed: 133 additions & 30 deletions

File tree

main.py

Lines changed: 10 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import argparse
2-
from src import make_extract, transform_article_debug, transform_article_web, load_news, init_database, create_news_tables
2+
from src import make_extract, transform_article_debug, transform_article_web, load_news, init_database, create_news_tables, load_web_pipeline, make_extract_web, make_extract_debug
33
import logging
44

55
logging.basicConfig(
@@ -54,19 +54,19 @@ def pipeline_for_web_user(user_id: int, search_request_id: int, key_word: str, l
5454
while num_of_news < limit:
5555
remaining = limit - num_of_news
5656
if debug:
57-
raw_file_name, raw_articles_count = make_extract(key_word, page, page_size)
57+
raw_file_name, raw_articles_count = make_extract_debug(key_word, page, page_size)
5858
if raw_articles_count == 0:
5959
logger.warning("there is no more artical")
6060
break
6161
clean_file_name = transform_article_debug(raw_file_name, key_word, page)
6262
result_num_of_news = load_news(clean_file_name, max_rows=remaining)
63-
64-
payload, raw_articles_count = make_extract(key_word, page, page_size)
65-
if raw_articles_count == 0:
66-
logger.warning("there is no more artical")
67-
break
68-
clean_file_name = transform_article_web(payload, key_word, page)
69-
result_num_of_news = load_news(clean_file_name, max_rows=remaining)
63+
else:
64+
payload, raw_articles_count = make_extract_web(key_word, page, page_size)
65+
if raw_articles_count == 0:
66+
logger.warning("there is no more artical")
67+
break
68+
clean_data, stats = transform_article_web(payload)
69+
result_num_of_news = load_web_pipeline(user_id, search_request_id, clean_data, stats)
7070

7171
num_of_news += result_num_of_news
7272
page += 1
@@ -78,23 +78,11 @@ def main()-> None:
7878
try:
7979
init_database()
8080
create_news_tables()
81-
loaded = pipeline()
82-
logger.info("Pipline finished. loaded rows: %s", loaded)
83-
except Exception as e:
84-
logger.exception("pipeline failed: %s", e)
85-
raise
86-
87-
def main2(user_id, search_request_id, key_word)-> None:
88-
logger.info("Starting pipeline, init database, build table..")
89-
try:
90-
init_database()
91-
create_news_tables()
92-
loaded = pipeline_for_web_user(user_id,search_request_id, key_word, 20, 50)
81+
loaded = pipeline_for_web_user()
9382
logger.info("Pipline finished. loaded rows: %s", loaded)
9483
except Exception as e:
9584
logger.exception("pipeline failed: %s", e)
9685
raise
9786

98-
9987
if __name__ == "__main__":
10088
main()

src/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from .extract import make_extract
1+
from .extract import make_extract_debug, make_extract_web
22
from .transform import transform_article_web, transform_article_debug
3-
from .load import load_news
3+
from .load import load_news, load_web_pipeline
44
from .db import init_database, create_news_tables

src/extract.py

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,42 @@ def import_to_raw_json(data:dict[str, Any], key_word: str, page: int) -> str:
2323

2424

2525

26-
def make_extract( key_word: str, page: int = 1, page_size: int = 100, debug_mode: bool = False) -> tuple[dict,int]:
26+
def make_extract_debug( key_word: str, page: int = 1, page_size: int = 100) -> str:
27+
params = {
28+
"apiKey": settings.KEY_API,
29+
"language":settings.langueage,
30+
"q": key_word,
31+
"pageSize" : page_size,
32+
"page" : page,
33+
"sortBy": settings.sortBy
34+
}
35+
try:
36+
data = r.get(settings.NEWS_URL, params=params, timeout=15)
37+
data.raise_for_status()
38+
payload = data.json()
39+
logger.info(f"raise of status: {data.status_code}")
40+
payload["fetched_at"] = datetime.now().isoformat()
41+
payload["language"] = settings.langueage
42+
payload["key_word"] = key_word
43+
articles_count = len(payload.get("articles", []))
44+
if articles_count == 0:
45+
logger.info("There are no more articles")
46+
new_file_name = import_to_raw_json(payload, key_word, page)
47+
return new_file_name, articles_count
48+
except r.exceptions.Timeout:
49+
logger.error("Error: NewsAPI reauest time out")
50+
raise
51+
except r.exceptions.ConnectionError:
52+
logger.error("Error: no internet connection or API is not available")
53+
raise
54+
except r.exceptions.HTTPError as e:
55+
logger.error(f"Error HTTP: {e}")
56+
raise
57+
except ValueError:
58+
logger.error("Error: sorry we can't parse JSON")
59+
raise
60+
61+
def make_extract_web( key_word: str, page: int = 1, page_size: int = 100) -> tuple[dict,int]:
2762
params = {
2863
"apiKey": settings.KEY_API,
2964
"language":settings.langueage,
@@ -43,11 +78,7 @@ def make_extract( key_word: str, page: int = 1, page_size: int = 100, debug_mode
4378
articles_count = len(payload.get("articles", []))
4479
if articles_count == 0:
4580
logger.info("There are no more articles")
46-
if debug_mode:
47-
new_file_name = import_to_raw_json(payload, key_word, page)
48-
return new_file_name, articles_count
4981
return payload, articles_count
50-
5182
except r.exceptions.Timeout:
5283
logger.error("Error: NewsAPI reauest time out")
5384
raise

src/load.py

Lines changed: 85 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,4 +45,88 @@ def load_news(clean_news:str, max_rows: Optional[int] = None)-> int:
4545
num_of_news += 1
4646
conn.commit()
4747
return num_of_news
48-
48+
49+
def upsert_article(cur, article: dict) -> int:
50+
query = """
51+
INSERT INTO articles (
52+
url,
53+
source_name,
54+
author,
55+
title,
56+
description,
57+
published_at
58+
)
59+
VALUES (%s,%s,%s,%s,%s,%s)
60+
ON CONFLICT (url) DO UPDATE
61+
SET
62+
source_name = EXCLUDED.source_name,
63+
author = EXCLUDED.author,
64+
title = EXCLUDED.title,
65+
description = EXCLUDED.description,
66+
published_at = EXCLUDED.published_at
67+
RETURNING id;
68+
"""
69+
cur.execute(query,
70+
(
71+
article["url"],
72+
article["source_name"],
73+
article["author"],
74+
article["title"],
75+
article["description"],
76+
article["published_at"],
77+
),
78+
)
79+
row = cur.fetchone()
80+
return row["id"]
81+
82+
83+
def load_user_news(cur, user_id: int, search_request_id: int, article_id: int, keyword: str, fetched_at: str)-> int:
84+
query = """
85+
INSERT INTO user_news (
86+
user_id,
87+
search_request_id,
88+
article_id,
89+
keyword,
90+
fetched_at
91+
)
92+
values(%s,%s,%s,%s,%s)
93+
ON CONFLICT DO NOTHING;
94+
"""
95+
cur.execute(query,(user_id, search_request_id, article_id, keyword, fetched_at))
96+
return cur.rowcount
97+
98+
def load_request_stats(cur, search_request_id: int, stats: dict) -> None:
99+
query = """
100+
INSERT INTO request_stats (
101+
search_request_id,
102+
income_articles,
103+
accepted_articles,
104+
rejected_articles,
105+
reasons_counts,
106+
prime_reason
107+
)
108+
VALUES (%s,%s,%s,%s,%s,%s)
109+
"""
110+
cur.execute(query, (
111+
search_request_id,
112+
stats["income_articles"],
113+
stats["accepted_articles"],
114+
stats["rejected_articles"],
115+
json.dumps(stats["reasons_counts"]),
116+
json.dumps(stats["prime_reason"])
117+
))
118+
return None
119+
120+
def load_web_pipeline(user_id: int, search_request_id: int, clean_data: list[dict], stats: dict) -> int:
121+
loaded_count = 0
122+
with get_cursor(settings.db_news) as (conn, cur):
123+
for article in clean_data:
124+
keyword = article["key_word"]
125+
fetched_at = article["fetched_at"]
126+
article_id = upsert_article(cur,article)
127+
inserted = load_user_news(cur, user_id, search_request_id, article_id, keyword, fetched_at)
128+
loaded_count += inserted
129+
load_request_stats(cur, search_request_id, stats)
130+
conn.commit()
131+
return loaded_count
132+

0 commit comments

Comments
 (0)