Dink0 commited on
Commit
83e9c20
·
verified ·
1 Parent(s): c43bf22

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +148 -0
app.py ADDED
@@ -0,0 +1,148 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import requests
3
+ import re
4
+ import os
5
+
6
+ # Читаем токен из переменных окружения (либо просто вставьте строку, если нужно)
7
+ VK_ACCESS_TOKEN = os.environ.get("VK_ACCESS_TOKEN", "")
8
+ if not VK_ACCESS_TOKEN:
9
+ # Если не используете секреты, можно просто указать токен напрямую:
10
+ # VK_ACCESS_TOKEN = "vk1.a.XXX..."
11
+ # Или вывести ошибку, если токена нет
12
+ st.warning("Не найден VK_ACCESS_TOKEN. Вставьте свой токен.")
13
+ VK_API_VERSION = "5.131"
14
+
15
+ def human_format_views(num: int) -> str:
16
+ """
17
+ Форматирует число просмотров:
18
+ - 877 -> "0.9K"
19
+ - 2800 -> "2.8K"
20
+ - 15000 -> "15K"
21
+ - 1,234,567 -> "1.2M"
22
+ """
23
+ if num < 1000:
24
+ return f"{num / 1000:.1f}K"
25
+ elif num < 10_000:
26
+ return f"{num / 1000:.1f}K"
27
+ elif num < 1_000_000:
28
+ return f"{int(num / 1000)}K"
29
+ else:
30
+ return f"{num / 1_000_000:.1f}M"
31
+
32
+ def process_vk_link(link: str) -> tuple[str, int]:
33
+ """
34
+ Обрабатывает ссылку вида https://vk.com/wall-237426_1643652.
35
+ Возвращает (Markdown-строка, число просмотров).
36
+ Вместо "VK пост" в названии выводит реальное название сообщества или имя пользователя.
37
+ """
38
+ link = link.strip()
39
+ if not link:
40
+ return "", 0
41
+
42
+ # Парсим owner_id и post_id из ссылки
43
+ match = re.search(r'vk\.com/wall(-?\d+)_(\d+)', link)
44
+ if not match:
45
+ return f"**Ошибка**: не распознал ссылку — {link}", 0
46
+
47
+ owner_id = int(match.group(1))
48
+ post_id = match.group(2)
49
+ posts_param = f"{owner_id}_{post_id}"
50
+
51
+ # Запрашиваем wall.getById с extended=1, чтобы получить массив profiles/groups
52
+ api_url = "https://api.vk.com/method/wall.getById"
53
+ params = {
54
+ "posts": posts_param,
55
+ "access_token": VK_ACCESS_TOKEN,
56
+ "v": VK_API_VERSION,
57
+ "extended": 1 # Важно!
58
+ }
59
+
60
+ try:
61
+ response = requests.get(api_url, params=params)
62
+ if response.status_code != 200:
63
+ return f"**Ошибка**: HTTP {response.status_code} — {link}", 0
64
+
65
+ data = response.json()
66
+ if "error" in data:
67
+ error_msg = data["error"].get("error_msg", "Неизвестная ошибка")
68
+ return f"**Ошибка**: {error_msg} — {link}", 0
69
+
70
+ # В ответе при extended=1 структура: data["response"]["items"] - список постов,
71
+ # data["response"]["profiles"] - пользователи, data["response"]["groups"] - сообщества.
72
+ resp = data.get("response", {})
73
+ items = resp.get("items", [])
74
+ if not items:
75
+ return f"**Ошибка**: пост не найден — {link}", 0
76
+
77
+ post = items[0]
78
+ views = post.get("views", {}).get("count", 0)
79
+ post_owner_id = post.get("owner_id", owner_id)
80
+
81
+ # Определяем название: пользователь или группа
82
+ title = None
83
+ if post_owner_id < 0:
84
+ # Это группа/сообщество
85
+ group_id = -post_owner_id
86
+ for g in resp.get("groups", []):
87
+ if g["id"] == group_id:
88
+ title = g["name"]
89
+ break
90
+ else:
91
+ # Это пользователь
92
+ user_id = post_owner_id
93
+ for p in resp.get("profiles", []):
94
+ if p["id"] == user_id:
95
+ first_name = p.get("first_name", "")
96
+ last_name = p.get("last_name", "")
97
+ title = (first_name + " " + last_name).strip()
98
+ break
99
+
100
+ if not title:
101
+ # Если почему-то не нашли, пусть будет "VK пост"
102
+ title = "VK пост"
103
+
104
+ result = f"- [{title}]({link}) — {human_format_views(views)}"
105
+ return result, views
106
+
107
+ except Exception as e:
108
+ return f"**Ошибка** при обработке [{link}]({link}): {e}", 0
109
+
110
+ # ---------- Интерфейс Streamlit ----------
111
+ st.title("Парсер просмотров ВКонтакте-постов (с названием сообщества/пользователя)")
112
+ st.write("Введите ссылки (каждая на новой строке) в формате: `https://vk.com/wall-237426_1643652`")
113
+
114
+ links_input = st.text_area("Ссылки:", height=150)
115
+
116
+ if st.button("Обработать"):
117
+ lines = links_input.strip().split('\n')
118
+ results = []
119
+ total_views = 0
120
+
121
+ for line in lines:
122
+ result_line, views = process_vk_link(line)
123
+ if result_line:
124
+ results.append((result_line, views))
125
+ total_views += views
126
+
127
+ # Сортируем по просмотрам от большего к меньшему
128
+ results.sort(key=lambda x: x[1], reverse=True)
129
+
130
+ st.markdown("### Результат:")
131
+ md_lines = []
132
+ for result_line, _ in results:
133
+ st.markdown(result_line, unsafe_allow_html=True)
134
+ md_lines.append(result_line)
135
+
136
+ summary = f"**Суммарно публикации собрали {human_format_views(total_views)} просмотров**"
137
+ st.markdown(summary)
138
+ md_lines.append("")
139
+ md_lines.append(summary)
140
+
141
+ # Итоговый Markdown-код
142
+ markdown_result = "\n".join(md_lines)
143
+ st.download_button(
144
+ label="Скачать результат в Markdown",
145
+ data=markdown_result,
146
+ file_name="vk_result.md",
147
+ mime="text/markdown"
148
+ )