diff --git a/EseguiScript.bat b/EseguiScript.bat new file mode 100644 index 000000000..d56bf5cc7 --- /dev/null +++ b/EseguiScript.bat @@ -0,0 +1,3 @@ +@echo off +streamlit run ddqbscript\main.py +pause \ No newline at end of file diff --git a/README.md b/README.md index 9a5d87683..32ec588cc 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,102 @@ -# AI-Web-Scraper -An AI web scraper using ollama, brightdata, selenium and other libraries. +# AI Web Scraper con Ollama +Questo progetto ti permette di fare il scraping dei siti web e analizzare il loro contenuto utilizzando il modello Llama3 di Ollama. Il programma estrae e processa i dati dai siti web, permettendoti di fare domande sul contenuto DOM estratto e di scaricare i risultati. -# 💻 Launch Your Software Development Career Today! +Se preferisci la versione in inglese di questo progetto, puoi trovarla [qui](https://github.com/dddevid/AI-Web-Scraper-Ollama). -🎓 **No degree? No problem!** My program equips you with everything you need to break into tech and land an entry-level software development role. +## Requisiti -🚀 **Why Join?** -- 💼 **$70k+ starting salary potential** -- 🕐 **Self-paced:** Complete on your own time -- 🤑 **Affordable:** Low risk compared to expensive bootcamps or degrees -- 🎯 **45,000+ job openings** in the market +Prima di cominciare, assicurati di avere installato: -👉 **[Start your journey today!](https://techwithtim.net/dev)** -No experience needed—just your determination. Future-proof your career and unlock six-figure potential like many of our students have! +- Python 3.8 o superiore +- `pip` (gestore di pacchetti Python) + +### Passaggio 1: Installa Ollama e Llama3 + +1. **Scarica Ollama**: + - Ollama è una piattaforma che esegue modelli di intelligenza artificiale come Llama3. Puoi scaricare Ollama per il tuo sistema dal sito ufficiale: + [Download Ollama](https://ollama.com/download) + +2. **Installa il modello Llama3**: + - Dopo aver scaricato Ollama, devi installare il modello Llama3. Apri un terminale o prompt dei comandi e esegui il seguente comando per installare il modello Llama3: + ``` + ollama install llama3 + ``` + +### Passaggio 2: Clona il Repository + +1. **Clona il repository**: + - Per prima cosa, clona il repository GitHub sulla tua macchina locale eseguendo il seguente comando, specificando il branch italiano: + ``` + git clone --branch Italian https://github.com/dddevid/AI-Web-Scraper-Ollama.git + ``` + +2. **Naviga nella cartella del progetto**: + - Cambia nella cartella del progetto eseguendo: + ``` + cd AI-Web-Scraper-Ollama + ``` + +### Passaggio 3: Configura l'Ambiente Python + +1. **Crea un ambiente virtuale (opzionale ma consigliato)**: + - Crea un ambiente virtuale per gestire le dipendenze del progetto: + ``` + python -m venv venv + ``` + +2. **Attiva l'ambiente virtuale**: + - Su Windows: + ``` + venv\Scripts\activate + ``` + - Su macOS/Linux: + ``` + source venv/bin/activate + ``` + +3. **Installa le dipendenze richieste**: + - Il file `requirements.txt` si trova nella cartella `ddbqscript`. Installa le librerie Python necessarie eseguendo: + ``` + pip install -r ddbqscript/requirements.txt + ``` + +### Passaggio 4: Esegui l'Applicazione + +#### Su Windows: + +- **Esegui lo script utilizzando il file batch**: + - Usa il file `Executethescript.bat` per avviare l'applicazione: + ``` + Executethescript.bat + ``` + +#### Su macOS/Linux: + +- **Esegui lo script utilizzando Streamlit**: + - Avvia l'app Streamlit eseguendo il seguente comando: + ``` + streamlit run ddbqscript/main.py + ``` + +2. **Accedi all'app**: + - L'interfaccia Streamlit si aprirà nel tuo browser. Ora puoi inserire un URL di un sito web, fare scraping del suo contenuto e analizzarlo usando Llama3. + +### Passaggio 5: Utilizzo + +- **Fare scraping di un sito web**: Inserisci un URL e clicca su "Scrape the website" per fare scraping del contenuto del sito. +- **Analizzare il contenuto**: Dopo aver fatto lo scraping, puoi inserire una descrizione di cosa vuoi analizzare, e l'IA processerà il contenuto. +- **Scaricare i risultati**: Una volta completata l'analisi, puoi scaricare i risultati nei formati JSON e TXT. + +### Risoluzione dei Problemi + +- **Ollama non trovato**: Se ricevi un errore relativo a Ollama, assicurati che sia correttamente installato e che sia aggiunto al PATH del sistema. +- **Dipendenze mancanti**: Assicurati di aver installato tutte le librerie Python necessarie eseguendo `pip install -r ddbqscript/requirements.txt`. + +--- + +### Se ti è piaciuto questo progetto, puoi offirmi un caffè! ☕ + +[![Buy me a coffee](https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png)](https://buymeacoffee.com/devidd) + +Cliccando sul link, puoi scegliere di donarmi quanto vuoi o iscriverti per 30€ al mese per supportare lo sviluppo continuo di questo progetto. diff --git a/chromedriver b/chromedriver deleted file mode 100644 index 6251131df..000000000 Binary files a/chromedriver and /dev/null differ diff --git a/ddqbscript/main.py b/ddqbscript/main.py new file mode 100644 index 000000000..c77180b95 --- /dev/null +++ b/ddqbscript/main.py @@ -0,0 +1,76 @@ +import streamlit as st +import json +import os +import zipfile +import io + +from scrape import ( + scrape_website, + extract_body_content, + clean_body_content, + split_dom_content, +) +from parse import parse_with_ollama + +# Interfaccia utente Streamlit +st.title("Scraper Web con IA") +url = st.text_input("Inserisci URL del sito web") + +# Passaggio 1: Scraping del sito web +if st.button("Scrapa sito web"): + if url: + st.write("Scraping del sito web in corso...") + + # Scraping del sito web + dom_content = scrape_website(url) + body_content = extract_body_content(dom_content) + cleaned_content = clean_body_content(body_content) + + # Salvataggio del contenuto DOM nello stato della sessione di Streamlit + st.session_state.dom_content = cleaned_content + + # Visualizzazione del contenuto DOM in una casella espandibile + with st.expander("Visualizza contenuto DOM"): + st.text_area("Contenuto DOM", cleaned_content, height=300) + +# Passaggio 2: Fare domande sul contenuto DOM +if "dom_content" in st.session_state: + parse_description = st.text_area("Descrivi cosa vuoi analizzare") + + if st.button("Analizza contenuto"): + if parse_description: + st.write("Analisi del contenuto in corso...") + + # Analisi del contenuto con Ollama + dom_chunks = split_dom_content(st.session_state.dom_content) + parsed_result = parse_with_ollama(dom_chunks, parse_description) + st.session_state.parsed_result = parsed_result + st.write(parsed_result) + +# Tasto per scaricare i risultati +if "parsed_result" in st.session_state: + if st.button("Scarica risultati"): + # Crea un file JSON + json_data = { + "url": url, + "parse_description": parse_description, + "parsed_result": st.session_state.parsed_result + } + + # Crea un file ZIP in memoria + zip_buffer = io.BytesIO() + with zipfile.ZipFile(zip_buffer, 'w', zipfile.ZIP_DEFLATED) as zip_file: + # Aggiunge risultato.json + zip_file.writestr('risultato.json', json.dumps(json_data, indent=2, ensure_ascii=False)) + + # Aggiunge risultato.txt + zip_file.writestr('risultato.txt', st.session_state.parsed_result) + + # Prepara il download + zip_buffer.seek(0) + st.download_button( + label="Scarica risultati (JSON + TXT)", + data=zip_buffer, + file_name="risultati_scraping.zip", + mime="application/zip" + ) \ No newline at end of file diff --git a/ddqbscript/parse.py b/ddqbscript/parse.py new file mode 100644 index 000000000..2adea1dc5 --- /dev/null +++ b/ddqbscript/parse.py @@ -0,0 +1,31 @@ +#parse.py + +from langchain_ollama import OllamaLLM +from langchain_core.prompts import ChatPromptTemplate + +template = ( + "Sei incaricato di estrarre informazioni specifiche dal seguente contenuto testuale: {dom_content}. " + "Segui attentamente queste istruzioni: \n\n" + "1. **Estrazione Informazioni:** Estrai solo le informazioni che corrispondono direttamente alla descrizione fornita: {parse_description}. " + "2. **Nessun Contenuto Aggiuntivo:** Non includere testo, commenti o spiegazioni aggiuntive nella tua risposta. " + "3. **Risposta Vuota:** Se nessuna informazione corrisponde alla descrizione, restituisci una stringa vuota ('')." + "4. **Solo Dati Diretti:** L'output deve contenere solo i dati esplicitamente richiesti, senza altro testo." +) + +model = OllamaLLM(model="llama3") + + +def parse_with_ollama(dom_chunks, parse_description): + prompt = ChatPromptTemplate.from_template(template) + chain = prompt | model + + parsed_results = [] + + for i, chunk in enumerate(dom_chunks, start=1): + response = chain.invoke( + {"dom_content": chunk, "parse_description": parse_description} + ) + print(f"Batch analizzato: {i} di {len(dom_chunks)}") + parsed_results.append(response) + + return "\n".join(parsed_results) \ No newline at end of file diff --git a/requirements.txt b/ddqbscript/requirements.txt similarity index 65% rename from requirements.txt rename to ddqbscript/requirements.txt index b840a3e14..06b16d07c 100644 --- a/requirements.txt +++ b/ddqbscript/requirements.txt @@ -1,8 +1,9 @@ -streamlit -langchain -langchain_ollama -selenium -beautifulsoup4 -lxml -html5lib -python-dotenv \ No newline at end of file +streamlit +langchain +langchain_ollama +selenium +beautifulsoup4 +lxml +html5lib +python-dotenv +webdriver-manager diff --git a/scrape.py b/ddqbscript/scrape.py similarity index 50% rename from scrape.py rename to ddqbscript/scrape.py index 3875a7cde..e25aeb6b0 100644 --- a/scrape.py +++ b/ddqbscript/scrape.py @@ -1,57 +1,46 @@ -from selenium.webdriver import Remote, ChromeOptions -from selenium.webdriver.chromium.remote_connection import ChromiumRemoteConnection -from bs4 import BeautifulSoup -from dotenv import load_dotenv -import os - -load_dotenv() - -SBR_WEBDRIVER = os.getenv("SBR_WEBDRIVER") - - -def scrape_website(website): - print("Connecting to Scraping Browser...") - sbr_connection = ChromiumRemoteConnection(SBR_WEBDRIVER, "goog", "chrome") - with Remote(sbr_connection, options=ChromeOptions()) as driver: - driver.get(website) - print("Waiting captcha to solve...") - solve_res = driver.execute( - "executeCdpCommand", - { - "cmd": "Captcha.waitForSolve", - "params": {"detectTimeout": 10000}, - }, - ) - print("Captcha solve status:", solve_res["value"]["status"]) - print("Navigated! Scraping page content...") - html = driver.page_source - return html - - -def extract_body_content(html_content): - soup = BeautifulSoup(html_content, "html.parser") - body_content = soup.body - if body_content: - return str(body_content) - return "" - - -def clean_body_content(body_content): - soup = BeautifulSoup(body_content, "html.parser") - - for script_or_style in soup(["script", "style"]): - script_or_style.extract() - - # Get text or further process the content - cleaned_content = soup.get_text(separator="\n") - cleaned_content = "\n".join( - line.strip() for line in cleaned_content.splitlines() if line.strip() - ) - - return cleaned_content - - -def split_dom_content(dom_content, max_length=6000): - return [ - dom_content[i : i + max_length] for i in range(0, len(dom_content), max_length) - ] +from selenium import webdriver +from selenium.webdriver.chrome.service import Service +from webdriver_manager.chrome import ChromeDriverManager +from bs4 import BeautifulSoup + +def scrape_website(website): + service = Service(ChromeDriverManager().install()) + options = webdriver.ChromeOptions() + + options.add_argument("--no-sandbox") + options.add_argument("--disable-dev-shm-usage") + + driver = webdriver.Chrome(service=service, options=options) + + try: + driver.get(website) + print("Navigazione completata! Scraping del contenuto della pagina...") + html = driver.page_source + return html + finally: + driver.quit() + +def extract_body_content(html_content): + soup = BeautifulSoup(html_content, "html.parser") + body_content = soup.body + if body_content: + return str(body_content) + return "" + +def clean_body_content(body_content): + soup = BeautifulSoup(body_content, "html.parser") + + for script_or_style in soup(["script", "style"]): + script_or_style.extract() + + cleaned_content = soup.get_text(separator="\n") + cleaned_content = "\n".join( + line.strip() for line in cleaned_content.splitlines() if line.strip() + ) + + return cleaned_content + +def split_dom_content(dom_content, max_length=6000): + return [ + dom_content[i : i + max_length] for i in range(0, len(dom_content), max_length) + ] \ No newline at end of file diff --git a/main.py b/main.py deleted file mode 100644 index 17a5695dc..000000000 --- a/main.py +++ /dev/null @@ -1,43 +0,0 @@ -import streamlit as st -from scrape import ( - scrape_website, - extract_body_content, - clean_body_content, - split_dom_content, -) -from parse import parse_with_ollama - -# Streamlit UI -st.title("AI Web Scraper") -url = st.text_input("Enter Website URL") - -# Step 1: Scrape the Website -if st.button("Scrape Website"): - if url: - st.write("Scraping the website...") - - # Scrape the website - dom_content = scrape_website(url) - body_content = extract_body_content(dom_content) - cleaned_content = clean_body_content(body_content) - - # Store the DOM content in Streamlit session state - st.session_state.dom_content = cleaned_content - - # Display the DOM content in an expandable text box - with st.expander("View DOM Content"): - st.text_area("DOM Content", cleaned_content, height=300) - - -# Step 2: Ask Questions About the DOM Content -if "dom_content" in st.session_state: - parse_description = st.text_area("Describe what you want to parse") - - if st.button("Parse Content"): - if parse_description: - st.write("Parsing the content...") - - # Parse the content with Ollama - dom_chunks = split_dom_content(st.session_state.dom_content) - parsed_result = parse_with_ollama(dom_chunks, parse_description) - st.write(parsed_result) diff --git a/parse.py b/parse.py deleted file mode 100644 index 142ccb689..000000000 --- a/parse.py +++ /dev/null @@ -1,29 +0,0 @@ -from langchain_ollama import OllamaLLM -from langchain_core.prompts import ChatPromptTemplate - -template = ( - "You are tasked with extracting specific information from the following text content: {dom_content}. " - "Please follow these instructions carefully: \n\n" - "1. **Extract Information:** Only extract the information that directly matches the provided description: {parse_description}. " - "2. **No Extra Content:** Do not include any additional text, comments, or explanations in your response. " - "3. **Empty Response:** If no information matches the description, return an empty string ('')." - "4. **Direct Data Only:** Your output should contain only the data that is explicitly requested, with no other text." -) - -model = OllamaLLM(model="llama3") - - -def parse_with_ollama(dom_chunks, parse_description): - prompt = ChatPromptTemplate.from_template(template) - chain = prompt | model - - parsed_results = [] - - for i, chunk in enumerate(dom_chunks, start=1): - response = chain.invoke( - {"dom_content": chunk, "parse_description": parse_description} - ) - print(f"Parsed batch: {i} of {len(dom_chunks)}") - parsed_results.append(response) - - return "\n".join(parsed_results) diff --git a/sample.env b/sample.env deleted file mode 100644 index 99d0b93b9..000000000 --- a/sample.env +++ /dev/null @@ -1 +0,0 @@ -SBR_WEBDRIVER="" \ No newline at end of file