import time import pandas as pd import undetected_chromedriver as uc from bs4 import BeautifulSoup from selenium.webdriver.common.keys import Keys import os import json def scrape_alternativeto(i): url = f'https://alternativeto.net/category/business-and-commerce/cms/?p={i}' # Konfiguracja Selenium (undetected-chromedriver) options = uc.ChromeOptions() options.add_argument("--disable-blink-features=AutomationControlled") driver = uc.Chrome(options=options) driver.get(url) # Poczekaj na załadowanie strony time.sleep(2) # Akceptacja cookies jeśli pojawi się banner try: consent_button = driver.find_element("xpath", "//button[contains(., 'Consent') or contains(., 'Zgadzam się')]") consent_button.click() time.sleep(1) except Exception: pass # Jeśli nie ma bannera, przechodzimy dalej # Przewiń stronę, aby załadować więcej CMS-ów body = driver.find_element("tag name", "body") for _ in range(10): # Możesz zwiększyć, jeśli nie pobiera wszystkich wyników body.send_keys(Keys.PAGE_DOWN) time.sleep(1) # Pobierz HTML strony html = driver.page_source driver.quit() # Parsowanie HTML za pomocą BeautifulSoup soup = BeautifulSoup(html, "html.parser") # **🔍 ZMIENNE: Ustaw poprawne selektory CSS dla CMS-ów** cms_items = soup.select("div[id^='app-item-']") # Pobiera wszystkie CMS-y if not cms_items: print("⚠️ Nie znaleziono CMS-ów! Sprawdź poprawny selektor w przeglądarce.") return # Lista na wyniki extracted_data = [] for item in cms_items: # Nazwa narzędzia name_tag = item.select_one("div.flex.flex-col.w-full.gap-3 > div > div.min-w-\\[180px\\].md\\:min-w-0 > a > h2") name = name_tag.text.strip() if name_tag else "N/A" # Link link_tag = item.select_one("div.flex.flex-col.w-full.gap-3 > div > div.min-w-\\[180px\\].md\\:min-w-0 > a") link = f"https://alternativeto.net{link_tag['href']}" if link_tag and link_tag.has_attr('href') else "N/A" # Obrazek image_tag = item.select_one("div.flex.flex-col.w-full.gap-3 > div > div.flex.items-center.lg\\:hidden > a > div > img") image = image_tag['src'] if image_tag and image_tag.has_attr('src') else "N/A" extracted_data.append({ "name": name, "link": link, "image": image }) if not extracted_data: print("⚠️ Nie udało się wydobyć żadnych danych.") return # Dopisywanie do istniejących danych JSON (jeśli plik istnieje) json_path = "cms_alternatives.json" if os.path.exists(json_path): with open(json_path, "r", encoding="utf-8") as f: try: existing_data = json.load(f) except Exception: existing_data = [] else: existing_data = [] # Dodaj nowe dane, unikając duplikatów po nazwie i linku existing_keys = {(d["name"], d["link"]) for d in existing_data if "name" in d and "link" in d} for row in extracted_data: if (row["name"], row["link"]) not in existing_keys: existing_data.append(row) # Zapisz zaktualizowane dane with open(json_path, "w", encoding="utf-8") as f: json.dump(existing_data, f, indent=4, ensure_ascii=False) print("✅ Dane dopisane do cms_alternatives.json") # Analogicznie dla CSV import pandas as pd df_new = pd.DataFrame(extracted_data) csv_path = "cms_alternatives.csv" if os.path.exists(csv_path): df_existing = pd.read_csv(csv_path, encoding="utf-8") df_all = pd.concat([df_existing, df_new], ignore_index=True) df_all = df_all.drop_duplicates(subset=["name", "link"]) else: df_all = df_new df_all.to_csv(csv_path, index=False, encoding="utf-8") print("✅ Dane dopisane do cms_alternatives.csv") # Uruchamiamy skrypt if __name__ == "__main__": for i in range(15): print(f"🔄 Strona {i + 12}...") j = i + 12 scrape_alternativeto(j) time.sleep(2) ## scrape_alternativeto()