Загрузка...

Python Парсер отзывов STEAM , написанный полностью нейросетью

Тема в разделе Ваши работы создана пользователем KanRak 26 июн 2025. 154 просмотра

Опрос

Оценка

Результаты будут видны только после голосования.
  1. Кал дырявый

  2. Имбулька

  1. KanRak
    KanRak Автор темы 26 июн 2025 1 9 фев 2025
    Добрый день!
    Мне было нечем заняться и решил создать через CHATGPT парсер отзывов стим :fap:

    Для полный работы бота введите эту команду в cmd

    ⁡pip install aiohttp pandas openpyxl


    Весь парсинг конвертируется в .xlsx ( Потому что так удобно сортировать список через Excel)
    В самом боте имеется проверка на кол-во отзывов на игру
    Какие данные входят:

    1. Гиперссылка на отзыв
    2. Текст отзыва
    3. Положительный/Отрицательный отзыв
    4. Кол-во helpful
    5. Кол-во funny
    6. Кол-во игр автора отзыва
    7. Кол-во отзывов автора
    8. Общее кол-во часов в игре
    Где найти appid от игры?

    Заходите на любую страницу игры стима и в url будет номерок, он нам и нужен
    [IMG]


    Скидываю это сюда, может кому-то понадобится такой парсер)
    Написан он через CHATGPT

    Сам код:
    Python
    import asyncio
    import aiohttp
    import pandas as pd
    import tkinter as tk
    from tkinter import ttk, messagebox
    import threading

    class SteamReviewsApp:
    def __init__(self, root):
    self.root = root
    root.title("Steam Reviews Downloader")
    root.geometry("450x360")
    root.resizable(False, False)
    root.configure(bg="#1e1e2f")

    # Стили
    style = ttk.Style(root)
    style.theme_use('clam')

    style.configure("TLabel",
    background="#1e1e2f",
    foreground="#e0e0e0",
    font=("Segoe UI", 11))
    style.configure("TButton",
    background="#4a4e69",
    foreground="#e0e0e0",
    font=("Segoe UI", 11, "bold"),
    padding=8)
    style.map("TButton",
    background=[('active', '#22223b')])
    style.configure("TEntry",
    fieldbackground="#2a2a40",
    foreground="#f0f0f0",
    font=("Segoe UI", 11),
    padding=5)

    # Отступы вокруг элементов
    pad_opts = {'padx': 15, 'pady': 10}

    # Заголовок
    title_lbl = ttk.Label(root, text="Загрузчик отзывов Steam", font=("Segoe UI", 18, "bold"), foreground="#f2e9e4", background="#1e1e2f")
    title_lbl.pack(pady=(15,5))

    # Frame для ввода appid и кнопки проверки
    input_frame = ttk.Frame(root)
    input_frame.pack(pady=(10, 0), fill="x", padx=15)

    ttk.Label(input_frame, text="AppID игры:").grid(row=0, column=0, sticky="w", **pad_opts)
    self.appid_entry = ttk.Entry(input_frame, width=20)
    self.appid_entry.grid(row=0, column=1, sticky="w")

    self.check_button = ttk.Button(input_frame, text="Проверить", command=self.check_reviews_count)
    self.check_button.grid(row=0, column=2, padx=10)

    self.available_label = ttk.Label(root, text="Всего отзывов: не проверено", font=("Segoe UI", 10), foreground="#a7a9be", background="#1e1e2f")
    self.available_label.pack(anchor="w", padx=25, pady=(3, 10))

    # Кол-во отзывов
    count_frame = ttk.Frame(root)
    count_frame.pack(fill="x", padx=15)

    ttk.Label(count_frame, text="Количество отзывов:").grid(row=0, column=0, sticky="w", **pad_opts)
    self.num_entry = ttk.Entry(count_frame, width=20)
    self.num_entry.grid(row=0, column=1, sticky="w")

    # Progress bar
    self.progress_var = tk.IntVar()
    self.progressbar = ttk.Progressbar(root, maximum=100, variable=self.progress_var, length=400)
    self.progressbar.pack(pady=(20, 10))

    # Статус
    self.status_label = ttk.Label(root, text="Готов к запуску", font=("Segoe UI", 10), foreground="#a7a9be", background="#1e1e2f")
    self.status_label.pack()

    # Кнопка запуска
    self.start_button = ttk.Button(root, text="Начать загрузку", command=self.start_download)
    self.start_button.pack(pady=20, ipadx=10, ipady=5)

    self.loop = None
    self.reviews_downloaded = 0
    self.total_reviews = 0
    self.available_reviews = None

    def check_reviews_count(self):
    appid = self.appid_entry.get().strip()
    if not appid.isdigit():
    messagebox.showerror("Ошибка", "Введите корректный numeric AppID")
    return
    self.available_label.config(text="Проверка...", foreground="#f2cc8f")
    self.check_button.config(state="disabled")
    threading.Thread(target=self.async_check_reviews_count, args=(appid,), daemon=True).start()

    def async_check_reviews_count(self, appid):
    try:
    count = asyncio.run(self.fetch_total_reviews(appid))
    self.available_reviews = count
    self.available_label.config(text=f"Всего доступно отзывов: {count}", foreground="#90be6d")
    except Exception as e:
    self.available_label.config(text=f"Ошибка проверки: {e}", foreground="#f05454")
    finally:
    self.check_button.config(state="normal")

    async def fetch_total_reviews(self, appid):
    url = f"https://store.steampowered.com/appreviews/{appid}"
    params = {
    'json': 1,
    'filter': 'all',
    'language': 'all',
    'day_range': 9223372036854775807,
    'review_type': 'all',
    'purchase_type': 'all',
    'num_per_page': 1,
    'cursor': '*',
    }
    headers = {"User-Agent": "Mozilla/5.0"}
    async with aiohttp.ClientSession() as session:
    async with session.get(url, params=params, headers=headers) as resp:
    resp.raise_for_status()
    data = await resp.json()
    return data.get('query_summary', {}).get('total_reviews', 0)

    def start_download(self):
    appid = self.appid_entry.get().strip()
    num_str = self.num_entry.get().strip()
    if not appid.isdigit():
    messagebox.showerror("Ошибка", "Введите корректный numeric AppID")
    return
    if not num_str.isdigit() or int(num_str) <= 0:
    messagebox.showerror("Ошибка", "Введите положительное число отзывов")
    return
    if self.available_reviews is not None and int(num_str) > self.available_reviews:
    if not messagebox.askyesno("Подтверждение", f"Запрошено {num_str} отзывов, а доступно только {self.available_reviews}. Продолжить?"):
    return

    self.total_reviews = int(num_str)
    self.reviews_downloaded = 0
    self.progress_var.set(0)
    self.status_label.config(text="Запуск загрузки...", foreground="#f2cc8f")

    self.start_button.config(state="disabled")
    self.check_button.config(state="disabled")

    threading.Thread(target=self.run_async_download, args=(appid, self.total_reviews), daemon=True).start()

    def run_async_download(self, appid, total_reviews):
    asyncio.run(self.async_download(appid, total_reviews))

    async def async_download(self, appid, total_reviews):
    try:
    reviews = await self.fetch_reviews(appid, total_reviews)
    self.save_to_excel(reviews, appid)
    self.status_label.config(text=f"Загрузка завершена. Отзывы сохранены в {appid}_reviews.xlsx", foreground="#90be6d")
    except Exception as e:
    self.status_label.config(text=f"Ошибка: {e}", foreground="#f05454")
    finally:
    self.start_button.config(state="normal")
    self.check_button.config(state="normal")

    async def fetch_reviews(self, appid, max_reviews):
    reviews = []
    seen_ids = set()
    cursor = '*'
    headers = {"User-Agent": "Mozilla/5.0"}

    async with aiohttp.ClientSession() as session:
    while len(reviews) < max_reviews:
    url = f"https://store.steampowered.com/appreviews/{appid}"
    params = {
    'json': 1,
    'filter': 'all',
    'language': 'all',
    'day_range': 9223372036854775807,
    'review_type': 'all',
    'purchase_type': 'all',
    'num_per_page': 100,
    'cursor': cursor,
    }
    async with session.get(url, params=params, headers=headers) as resp:
    resp.raise_for_status()
    data = await resp.json()

    batch_reviews = data.get('reviews', [])
    if not batch_reviews:
    break

    for r in batch_reviews:
    rid = r.get('recommendationid')
    if rid not in seen_ids:
    seen_ids.add(rid)
    steamid = r['author']['steamid']
    recommendationid = rid
    review_url = f"https://steamcommunity.com/profiles/{steamid}/recommended/{appid}/#review_{recommendationid}"
    review_text = r.get('review', '')
    recommended = "Положительный" if r.get('voted_up', False) else "Отрицательный"
    helpful = r.get('votes_up', 0)
    funny = r.get('votes_funny', 0)
    games_owned = r['author'].get('num_games_owned', 0)
    reviews_posted = r['author'].get('num_reviews', 0)
    hours_played = r['author'].get('playtime_forever', 0) / 60
    reviews.append({
    'Автор': steamid,
    'Ссылка на отзыв': review_url,
    'Отзыв': review_text,
    'Тип отзыва': recommended,
    'Helpful': helpful,
    'Funny': funny,
    'Кол-во игр': games_owned,
    'Кол-во отзывов': reviews_posted,
    'Часов наиграно': round(hours_played, 2),
    })
    self.reviews_downloaded += 1
    self.root.after(0, self.update_progress)
    if len(reviews) >= max_reviews:
    break
    cursor = data.get('cursor')
    if not cursor:
    break
    return reviews

    def update_progress(self):
    percent = int(self.reviews_downloaded / self.total_reviews * 100)
    self.progress_var.set(percent)
    self.status_label.config(text=f"Загружено отзывов: {self.reviews_downloaded} из {self.total_reviews}", foreground="#e0e0e0")

    def save_to_excel(self, reviews, appid):
    df = pd.DataFrame(reviews)
    def make_hyperlink(row):
    return f'=HYPERLINK("{row["Ссылка на отзыв"]}", "{row["Автор"]}")'
    df['Ссылка на отзыв'] = df.apply(make_hyperlink, axis=1)
    df.drop(columns=['Автор'], inplace=True)
    filename = f"{appid}_reviews.xlsx"
    df.to_excel(filename, index=False)

    if __name__ == "__main__":
    root = tk.Tk()
    app = SteamReviewsApp(root)
    root.mainloop()
     
    26 июн 2025 Изменено
Загрузка...
Top