From 89ca167bcc3273936c6951210cbaf9f309e457b5 Mon Sep 17 00:00:00 2001 From: CSiCoAlm Date: Fri, 2 Jan 2026 17:48:06 +0100 Subject: [PATCH 1/2] Inserito anche lo skraping di eRac --- Src/A69WD/.vs/A69WD.csproj.dtbcache.json | 2 +- Src/A69WD/A69WD.csproj | 1 + Src/A69WD/Net/cLink_A69.cs | 14 +- Src/A69WD/Net/cLink_eRac.cs | 654 +++++++++++++++++++++++ Src/A69WD/Service/Service_Crawler.cs | 13 +- Src/A69WD/UI/frmReader.cs | 36 +- 6 files changed, 705 insertions(+), 15 deletions(-) create mode 100644 Src/A69WD/Net/cLink_eRac.cs diff --git a/Src/A69WD/.vs/A69WD.csproj.dtbcache.json b/Src/A69WD/.vs/A69WD.csproj.dtbcache.json index 754ebdc..8f64603 100644 --- a/Src/A69WD/.vs/A69WD.csproj.dtbcache.json +++ b/Src/A69WD/.vs/A69WD.csproj.dtbcache.json @@ -1 +1 @@ -{"RootPath":"C:\\Commesse\\_zPrivate\\A69WD\\Src\\A69WD","ProjectFileName":"A69WD.csproj","Configuration":"Debug|AnyCPU","FrameworkPath":"","Sources":[{"SourceFile":"App.cs"},{"SourceFile":"Data\\cNota.cs"},{"SourceFile":"Data\\cRac.cs"},{"SourceFile":"Data\\DBTools.cs"},{"SourceFile":"Data\\Helper.cs"},{"SourceFile":"General\\Navigator.cs"},{"SourceFile":"Net\\eLinkState.cs"},{"SourceFile":"Net\\cLink_A69.cs"},{"SourceFile":"Service\\Service_Crawler.cs"},{"SourceFile":"Service\\Service_Importer.cs"},{"SourceFile":"Site\\cSite_A69.cs"},{"SourceFile":"UI\\frmDownloader.cs"},{"SourceFile":"UI\\frmDownloader.Designer.cs"},{"SourceFile":"General\\Cfg.cs"},{"SourceFile":"General\\cTools.cs"},{"SourceFile":"General\\Logger.cs"},{"SourceFile":"Net\\iLink.cs"},{"SourceFile":"Properties\\AssemblyInfo.cs"},{"SourceFile":"Site\\iSiteType.cs"},{"SourceFile":"UI\\frmReader.cs"},{"SourceFile":"UI\\frmReader.Designer.cs"},{"SourceFile":"Properties\\Resources.Designer.cs"},{"SourceFile":"Properties\\Settings.Designer.cs"},{"SourceFile":"obj\\Debug\\.NETFramework,Version=v4.8.AssemblyAttributes.cs"}],"References":[{"Reference":"C:\\Commesse\\_zPrivate\\A69WD\\Src\\_Lib\\HtmlAgilityPack.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\Microsoft.CSharp.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\mscorlib.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\System.Core.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\System.Data.DataSetExtensions.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\System.Data.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Commesse\\_zPrivate\\A69WD\\Src\\_Lib\\System.Data.SQLite.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\System.Deployment.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\System.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\System.Drawing.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\System.Net.Http.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\System.Windows.Forms.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\System.Xml.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\System.Xml.Linq.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""}],"Analyzers":[],"Outputs":[{"OutputItemFullPath":"C:\\Commesse\\_zPrivate\\A69WD\\Src\\A69WD\\bin\\Debug\\A69WD.exe","OutputItemRelativePath":"A69WD.exe"},{"OutputItemFullPath":"","OutputItemRelativePath":""}],"CopyToOutputEntries":[]} \ No newline at end of file +{"RootPath":"C:\\Commesse\\_zPrivate\\A69WD\\Src\\A69WD","ProjectFileName":"A69WD.csproj","Configuration":"Debug|AnyCPU","FrameworkPath":"","Sources":[{"SourceFile":"App.cs"},{"SourceFile":"Data\\cNota.cs"},{"SourceFile":"Data\\cRac.cs"},{"SourceFile":"Data\\DBTools.cs"},{"SourceFile":"Data\\Helper.cs"},{"SourceFile":"General\\Navigator.cs"},{"SourceFile":"Net\\eLinkState.cs"},{"SourceFile":"Net\\cLink_A69.cs"},{"SourceFile":"Service\\Service_Crawler.cs"},{"SourceFile":"Service\\Service_Importer.cs"},{"SourceFile":"General\\Cfg.cs"},{"SourceFile":"General\\cTools.cs"},{"SourceFile":"General\\Logger.cs"},{"SourceFile":"Net\\iLink.cs"},{"SourceFile":"Properties\\AssemblyInfo.cs"},{"SourceFile":"UI\\frmReader.cs"},{"SourceFile":"UI\\frmReader.Designer.cs"},{"SourceFile":"Properties\\Resources.Designer.cs"},{"SourceFile":"Properties\\Settings.Designer.cs"},{"SourceFile":"obj\\Debug\\.NETFramework,Version=v4.8.AssemblyAttributes.cs"}],"References":[{"Reference":"C:\\Commesse\\_zPrivate\\A69WD\\Src\\_Lib\\HtmlAgilityPack.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\Microsoft.CSharp.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\mscorlib.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\System.Core.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\System.Data.DataSetExtensions.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\System.Data.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Commesse\\_zPrivate\\A69WD\\Src\\_Lib\\System.Data.SQLite.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\System.Deployment.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\System.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\System.Drawing.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\System.Net.Http.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\System.Windows.Forms.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\System.Xml.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""},{"Reference":"C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.8\\System.Xml.Linq.dll","ResolvedFrom":"","OriginalItemSpec":"","Name":"","EmbedInteropTypes":false,"CopyLocal":false,"IsProjectReference":false,"ProjectPath":""}],"Analyzers":[],"Outputs":[{"OutputItemFullPath":"C:\\Commesse\\_zPrivate\\A69WD\\Src\\A69WD\\bin\\Debug\\A69WD.exe","OutputItemRelativePath":"A69WD.exe"},{"OutputItemFullPath":"","OutputItemRelativePath":""}],"CopyToOutputEntries":[]} \ No newline at end of file diff --git a/Src/A69WD/A69WD.csproj b/Src/A69WD/A69WD.csproj index 3e8851e..a012960 100644 --- a/Src/A69WD/A69WD.csproj +++ b/Src/A69WD/A69WD.csproj @@ -64,6 +64,7 @@ + diff --git a/Src/A69WD/Net/cLink_A69.cs b/Src/A69WD/Net/cLink_A69.cs index b7337ea..45afd91 100644 --- a/Src/A69WD/Net/cLink_A69.cs +++ b/Src/A69WD/Net/cLink_A69.cs @@ -45,7 +45,7 @@ namespace A69WD.Net { return !App.DB.IsPresent(URL); } } - } + } public eLinkState Status { get => status; set { status = value; } } @@ -87,7 +87,7 @@ namespace A69WD.Net { return false; } } - + public static bool InsertStartLink(Service_Crawler service) { //string url = LinkIdxBase.Replace("{Categoria}", "altro").Replace("{ID}", "1"); //LinkIdxBase.Replace("{Categoria}", "trio").Replace("{ID}", "1"); @@ -176,7 +176,7 @@ namespace A69WD.Net { rac.Title = cTools.FormattaTesto(nodes[0].InnerText.Trim(), false); if (string.IsNullOrEmpty(rac.Title)) { Logger.Error($"A69 - Import - No Title - {filePathName}"); - return null; + return null; } } catch (Exception ex) { Logger.Error(string.Format("Fallita estrazione titolo dal file {0}\r\n{1}", FileName, ex.Message)); return null; } #endregion @@ -224,7 +224,7 @@ namespace A69WD.Net { if (parts.Length == 3) { CultureInfo culture = CultureInfo.CreateSpecificCulture("it-IT"); DateTimeStyles styles = DateTimeStyles.None; - DateTime tmpDT = DateTime.Now; + DateTime tmpDT = DateTime.Now; if (!DateTime.TryParse(parts[0].Trim(), culture, styles, out tmpDT)) { Logger.Error($"A69 - Import - No data - {filePathName}"); } @@ -764,7 +764,7 @@ namespace A69WD.Net { try { #region 1) Prepare HTML Client - + HttpClientHandler _handler = new HttpClientHandler { CookieContainer = new CookieContainer(), UseCookies = true, @@ -776,7 +776,7 @@ namespace A69WD.Net { client.Timeout = TimeSpan.FromSeconds(60); client.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"); client.DefaultRequestHeaders.Referrer = new Uri(cLink_A69.LoginPageUrl); - + #endregion #region 2) GET pagina di login @@ -784,7 +784,7 @@ namespace A69WD.Net { Console.WriteLine("A69 - Richiedo la pagina di login..."); Logger.Information("A69 - Richiedo la pagina di login..."); string loginPageHtml = await client.GetStringAsync(cLink_A69.LoginPageUrl); - + #endregion #region 3) Parsing HTML per estrarre ts e token diff --git a/Src/A69WD/Net/cLink_eRac.cs b/Src/A69WD/Net/cLink_eRac.cs new file mode 100644 index 0000000..d6c2341 --- /dev/null +++ b/Src/A69WD/Net/cLink_eRac.cs @@ -0,0 +1,654 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Net; +using System.Text; +using System.Threading.Tasks; +using A69WD.Data; +using A69WD.Service; +using HtmlAgilityPack; +using System.Globalization; +using System.Xml.Serialization; + + + +namespace A69WD.Net { + + public class cLink_eRac : iLink { + + private readonly string filename; + private readonly string filepath; + private eLinkState status = eLinkState.ToConfirm; + private string fields = ""; + + public static string PageBase { get { return "https://www.eroticiracconti.it"; } } + + public static string LinkIdxBase { get { return "https://www.eroticiracconti.it/archivio/Tutto/{ID}"; } } + public static string LinkRacBase { get { return "https://www.eroticiracconti.it/racconto/{RacID}"; } } + + public string ID => "eRac"; + + public string URL { get; } + + public string FileName => filename; + + public string FilePath { get => filepath; } + + public bool Validate { + get { + if (URL.StartsWith("https://www.eroticiracconti.it/archivio/Tutto/")) { + // URL di tipo Idx, devo lavorare i link nuovo o rilavorare i link più obsoleti di 6 ore. + return !App.DB.IsPresent(URL, -6); + } else { + // URL di tipo Rac, devo lavorare solo i link nuovi + return !App.DB.IsPresent(URL); + } + } + } + + public eLinkState Status { get => status; set { status = value; } } + + public string Fields { get => fields; set => fields = value; } + + public cLink_eRac(string Url, string Filename, string fields = "none", string Filepath = "") { + this.URL = Url; + this.filename = Filename; + this.fields = fields; + this.filepath = string.IsNullOrEmpty(Filepath) ? Cfg.Settings.PathDownloadWorking : Filepath; + this.status = eLinkState.ToConfirm; + } + + + public static bool InsertStartLink(Service_Crawler service) { + try { + int i = 0; + string url = LinkIdxBase.Replace("{ID}", i.ToString()); + string name = $"_eRac_Idx_{i.ToString("0000")}.html"; + service.EnqueueUrl(new cLink_eRac(url, name)); + return true; + } catch (Exception ex) { + Logger.Error("Errore inserendo eRac Start Link - " + ex.Message); + return false; + } + } + + + public cRac EstraiRac(HtmlDocument doc) { + /* + * Analisi html dei racconti aggiornata al 2025/12/27: + * + * + * Per ciascun file html, si ha un unico racconto che ha un formato interno pari a: + * + * + * + * ... + * Quante voglie. | Erotici Racconti + * + * + *
+ *
+ *
+ *

{Title}

+ *

+ * + * + * + * di
+ * + *
+ * + * + * genere
+ * {Genere} + *
+ *
+ *

+ *
+ * {Trama} + *
+ *
+ *
+ * + * di
+ * + *
+ *
+ * + * scritto il
+ * {Data} + *
+ *
+ * + * 5.1K + *
+ * visite + *
+ *
+ *
+ *
+ * + * + * 3 + *
+ * voti + *
+ *
+ * + * valutazione
+ * 2
+ *
+ *
+ *
+ * + *
+ *
+ * + * il tuo voto
+ *
+ * 12345678910
+ *
+ *
+ *
+ * ... + *
+ * ... + *
+ * ... + *
+ * + * + * + * quindi i dati del racconto che si possono estrapolare sono: + * Titolo: --> Testo del nodo

{Title}

+ * SubTitle: --> Sempre Vuoto + * Autore: --> Testo del nodo

+ * Creato: --> Estrarre la parte dal
{Data}
+ * Tags: --> Testo del nodo

{Genere}

+ * Trama: --> Testo del nodo
{Trama}
+ * Notes: --> SrcFile - Nome del file che si analizza + * Origini: --> Sempre l'ID della sorgente web + * Voto: --> Sempre "Non Letto" + * Updated: --> Data attuale + * + */ + cRac rac = new cRac(); + HtmlNodeCollection nodes; + try { + Console.WriteLine($"eRac - Importo: {FileName}"); + + // Ricavo il nodo radice del racconto:
+ //HtmlNode root = doc.DocumentNode; + HtmlNode root = doc.DocumentNode.SelectSingleNode("//div[@class='story']"); + + if (root == null) { + // racconto non presente + return null; + } + + #region Origini: --> Sempre l'ID della sorgente web + rac.Origini = new List { ID }; + #endregion + + #region Titolo: --> Testo del nodo

{Title}

+ try { + nodes = root.SelectNodes("//h1[@class='tit']"); + rac.Title = cTools.FormattaTesto(nodes[0].InnerText.Trim(), false); + if (string.IsNullOrEmpty(rac.Title)) { + Logger.Error($"eRac - Import - No Title - {FileName}"); + return null; + } + } catch (Exception ex) { Logger.Error(string.Format("Fallita estrazione titolo dal file {0}\r\n{1}", FileName, ex.Message)); return null; } + #endregion + + #region SubTitle: --> Sempre Vuoto + rac.SubTitle = ""; + #endregion + + #region Autore: --> Testo del nodo

+ try { + //nodes = root.SelectNodes("//h2//span[@class='infos']//span[]//a"); + nodes = root.SelectNodes("//a[@rel='author']"); + List items = new List(); + foreach (HtmlNode nd in nodes) { + string aut = nd.ParentNode.InnerText.Replace(" ", "").Trim(); + if (aut.StartsWith("di")) { + items.Add(aut.Replace("di", "").Trim()); + } + } + items.Sort(); + string tmp = ""; + rac.Autori = new List(); + // Rimuovo eventuali duplicati + foreach (string aut in items) { + if (tmp != aut) { + rac.Autori.Add(aut); + tmp = aut; + } + } + if (rac.Autori == null || string.IsNullOrEmpty(rac.Autori[0])) { + Logger.Error($"eRac - Import - No Autors - {FileName}"); + return null; + } + } catch (Exception ex) { Logger.Error(string.Format("Fallita estrazione autore dal file {0}\r\n{1}", FileName, ex.Message)); return null; } + #endregion + + #region Creato: --> Estrarre la parte dal
+ rac.Creato = DateTime.Now; + try { + // Creato --> Estrarre la prima parte dal
{Data}
+ nodes = root.SelectNodes("//div[@class='infos']//div"); + foreach (HtmlNode nd in nodes) { + string txt = nd.InnerText.Trim().Replace(" ", ""); + if (txt.StartsWith("scritto il")) { + CultureInfo culture = CultureInfo.CreateSpecificCulture("it-IT"); + DateTimeStyles styles = DateTimeStyles.None; + DateTime tmpDT = DateTime.Now; + if (!DateTime.TryParse(txt.Replace("scritto il", "").Trim(), culture, styles, out tmpDT)) { + Logger.Error($"eRac - Import - No data - {FileName}"); + } + rac.Creato = tmpDT; + break; + } + } + } catch (Exception ex) { Logger.Warning(string.Format("Data non riconosciuta nel file {0}\r\n{1}", FileName, ex.Message)); return null; } + #endregion + + #region Updated: --> Data attuale + rac.Updated = DateTime.Now; + #endregion + + #region Tags: --> Testo del nodo

{Genere}

+ try { + //nodes = root.SelectNodes("//h2//span[@class='infos']//span//a"); + nodes = root.SelectNodes("//h2//span[@class='infos']//span"); + List items = new List(); + foreach (HtmlNode nd in nodes) { + string txt = nd.InnerText.Trim(); + if (txt.StartsWith("genere")) { + items.Add(cTools.FormattaTesto(txt.Replace("genere", "").Trim(), false)); + } + } + //items.Sort(); + items = items + .OrderBy(s => s) // ordina alfabeticamente + .Distinct() // elimina duplicati + .ToList(); + Format_Insert_Tags(rac, items); // rac.Tags = items; + } catch (Exception ex) { Logger.Warning(string.Format("Fallita estrazione Tags dal file {0}\r\n{1}", FileName, ex.Message)); return null; } + #endregion + + #region Trama: --> Testo del nodo
a cui si levano i DIV interni. + try { + nodes = root.SelectNodes("//div[@class='tes']"); + foreach (HtmlNode nd in nodes) { + foreach (HtmlNode n in nd.ChildNodes) { + if (n.Name.ToUpper() == "#TEXT") { rac.Trama += cTools.FormattaTesto(n.InnerText.Trim(), false); } + if (n.Name.ToUpper() == "BR") { rac.Trama += "\r"; } + if (n.Name.ToUpper() == "DIV") {; } + } + } + } catch (Exception ex) { Logger.Error(string.Format("Fallita estrazione Trama dal file {0}\r\n{1}", FileName, ex.Message)); return null; } + #endregion + + #region Voto: --> Sempre "Non Letto" + rac.Voto = "Non Letto"; + #endregion + + #region Notes: --> SrcFile - Nome del file che si analizza + rac.Notes = new List(); + rac.Notes.Add(new Data.cNota("SrcFile", System.IO.Path.GetFileName(FileName))); + #endregion + + // Formalizzo esito estrazione: + if (!rac.Validate()) { + rac = null; + } + + } catch (Exception ex) { + Logger.Error($"eRac - Import Error - {FileName}: {ex.Message}"); + Console.WriteLine($"eRac - Import Error - {FileName}: {ex.Message}"); + return null; + } + return rac; + } + + + + + protected virtual void Format_Insert_Tags(Data.cRac rac, List items) { + // Per ora riporto tutti i tag rilevati, mentre in futuro dovrò: + // - parsare la lista e formattare correttamente i tag + // - ordinare la lista dei tag formattati ed eliminare i duplicati + // - se non sono rimasti tag, inserisco il tag generale per indicare che non vi sono tag + // - altrimenti inserisco tutti i tag rimasti. + rac.Tags = new List(); + try { + items.Sort(); + string tmp = ""; + foreach (string item in items) { + string it = item.Trim().ToLower(); + if (tmp != it) { + #region switch per formattare il testo + switch (it) { + //case "Gay & Bisex": + // rac.Tags.Add("Bisex"); + // rac.Tags.Add("Gay"); + // break; + //case "tradimenti": + // rac.Tags.Add("Tradimenti"); + // break; + //case "Lui & Lei": + // rac.Tags.Add("Lui & Lei"); + // break; + //case "trans": + // rac.Tags.Add("Trans"); + // break; + //case "Prime Esperienze": + // rac.Tags.Add("Prime Esperienze"); + // break; + //case "trio": + // rac.Tags.Add("Trio"); + // break; + //case "incesto": + // rac.Tags.Add("Incesto"); + // break; + //case "orge": + // rac.Tags.Add("Orge"); + // break; + //case "bdsm": + // rac.Tags.Add("BDSM"); + // break; + //case "lesbo": + // rac.Tags.Add("Lesbo"); + // break; + //case "Scambio di Coppia": + // rac.Tags.Add("Scambio di Coppia"); + // break; + default: + rac.Tags.Add(item); + break; + } + #endregion + tmp = it; + + }//if + + }//foreach + + } catch (Exception ex) { + Logger.Error(string.Format("Error Code: {0} - Errore in {1}.{2}: {3}", "ER00040", System.Reflection.MethodInfo.GetCurrentMethod().DeclaringType.FullName, System.Reflection.MethodInfo.GetCurrentMethod().Name, ex.Message)); + } finally { + if (rac.Tags.Count == 0) rac.Tags.Add("_None_"); + } + }//function + + + #region Gestione Sito eRac + + private static HttpClient client = null; + private static bool autenticated = false; + + /// + /// Indica se siamo autenticati al sito + /// + public static bool Autenticated => autenticated; + + + /// + /// Esegue l'autenticazione al sito: + /// - Scarica la pagina di autenticazione + /// - analizza quanto scaricato per determinare i campi dinamici 'ts' e 'token' + /// - prepara la risposta al form di identificazione + /// - invia il POST di autenticazione + /// - analizza la risposta per verificare il corretto login + /// + public static async Task Authenticate() { + if (autenticated) { + // Autenticazione già fatta, posso proseguire senza altro fare + Logger.Warning("eRac - Autenticazione già effettuata."); + } + try { + + #region 1) Prepare HTML Client + + HttpClientHandler _handler = new HttpClientHandler { + CookieContainer = new CookieContainer(), + UseCookies = true, + AllowAutoRedirect = true, + AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate + }; + + client = new HttpClient(_handler); + client.Timeout = TimeSpan.FromSeconds(60); + client.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"); + client.DefaultRequestHeaders.Referrer = new Uri(cLink_eRac.PageBase); + + #endregion + + autenticated = true; + + } catch (Exception ex) { + Console.WriteLine($"Errore generale: {ex.Message}"); + Logger.Information($"Errore generale: {ex.Message}"); + } + return autenticated; + } + + + /// + /// Codice da eseguire per ciascun eRac link: + /// - scarico l'url indicato + /// - se richiesto lo salvo come file di testo + /// - analizzo il documento html ed estraggo tutti gli url ad altre pagine di link + /// - analizzo il documento html ed estraggo tutti gli url a racconti + /// - analizzo il documento html ed estraggo il testo del racconto + /// + /// + /// + public async Task> CrawlPageAsync() { + var newlinks = new List(); + + try { + Console.WriteLine($"eRac - Scarico: {URL}"); + HtmlDocument tdoc = null; + string thtml = ""; + + #region ToConfirm + if (Status == eLinkState.ToConfirm) { + // Eseguo la verifica se link da downloadare + Status = eLinkState.ToDownload; + } + #endregion + + #region ToDownload + if (Status == eLinkState.ToDownload) { + Status = eLinkState.OnDownload; + } + #endregion + + #region OnDownload + if (Status == eLinkState.OnDownload) { + // Scarico il file + var resp = await client.GetAsync(URL); + if (!resp.IsSuccessStatusCode) { + Console.WriteLine($"eRac - Errore HTTP {(int)resp.StatusCode} {resp.ReasonPhrase} per {URL}"); + Status = eLinkState.Error; + //App.DB.LinkLog(lk); + return newlinks; + } + // Scarico la pagina + thtml = await client.GetStringAsync(URL); + tdoc = new HtmlDocument(); + tdoc.LoadHtml(thtml); + // Salvo il file downloadato + //SaveToFile(thtml, lk.FilePath, lk.FileName); + + Status = eLinkState.ToAnalize; + } + #endregion + + #region ToAnalize + { + if (Status == eLinkState.ToAnalize) { + List tmpLk = new List(); + // + // #region Estraggo gli url ad indici: + // { + // /* + // * Gli url delle pagine di indice sono del tipo: + // * + // * + // * + // */ + // try { + // // Estraggo i link alle altre pagine: + // var tnodes = tdoc.DocumentNode.SelectNodes("//div[@class='pagination']//a[@href]"); + // if (tnodes != null) { + // foreach (var link in tnodes) { + // var href = link.GetAttributeValue("href", ""); + // if (!string.IsNullOrEmpty(href) && href.StartsWith("/archivio/Tutto/")) + // tmpLk.Add(href); //tmpLk.Add(cLink_eRac.PageBase + href); + // } + // } + // // Rimuove duplicati e ordina alfabeticamente + // tmpLk = tmpLk + // .OrderBy(s => s) // ordina alfabeticamente + // .Distinct() // elimina duplicati + // .ToList(); + // // Inserisco i link trovati + // foreach (string ilk in tmpLk) { + // string url = cLink_eRac.PageBase + ilk; + // int offset = int.Parse(ilk.Replace("/archivio/Tutto/", "")); + // string name = $"_eRac_Idx_{offset.ToString("0000")}.html"; + // newlinks.Add(new cLink_eRac(url, name)); + // } + // } catch (Exception ex) { + // Logger.Error("Errore analisi Idx link dal " + FileName + " - " + ex.Message); + // cTools.SaveToFile(thtml, Cfg.Settings.PathSrcErrOnExtract, FileName); + // } + // } + // #endregion + // + // #region Estraggo gli url a racconti: + // { + // /* + // * + // * I link ai racconti sono dei pulsanti così formati: + // * + // * + // */ + // try { + // // Estraggo i link ai racconti: + // tmpLk = new List(); + // // Estraggo i link alle altre pagine: + // var tnodes = tdoc.DocumentNode.SelectNodes("//a[@class='rac']"); + // if (tnodes != null) { + // foreach (var link in tnodes) { + // var href = link.GetAttributeValue("href", ""); + // if (!string.IsNullOrEmpty(href) && href.StartsWith("/racconto/")) + // tmpLk.Add(href); //tmpLk.Add(cLink_eRac.PageBase + href); + // } + // } + // // Rimuove duplicati e ordina alfabeticamente + // tmpLk = tmpLk + // .OrderBy(s => s) // ordina alfabeticamente + // .Distinct() // elimina duplicati + // .ToList(); + // // Inserisco i link trovati + // foreach (string ilk in tmpLk) { + // string url = cLink_eRac.PageBase + ilk; + // string name = ilk.Replace("/racconto/", "eRac_").Replace(@"/", "_") + ".html"; + // newlinks.Add(new cLink_eRac(url, name)); + // } + // } catch (Exception ex) { + // Logger.Error("Errore analisi Idx link dal " + FileName + " - " + ex.Message); + // cTools.SaveToFile(thtml, Cfg.Settings.PathSrcErrOnExtract, FileName); + // } + // } + // #endregion + // + #region Estraggo il racconto dal file e lo inserisco nel DB + if (FileName.StartsWith("eRac_")) { + // Link ad un racconto + cRac rac = EstraiRac(tdoc); + if (rac != null) { + // Racconto estratto correttamente, lo salvo sul DB + int res = App.DB.ImportRac(rac); + if (res > 0) { + // Racconto salvato correttamente sul DB + cTools.SaveToFile(thtml, Cfg.Settings.PathSrcDone, FileName); + } else { + // Errore nel salvataggio sul DB + cTools.SaveToFile(thtml, Cfg.Settings.PathSrcErrOnSave, FileName); + } + } else { + // Estrazione del racconto fallita + cTools.SaveToFile(thtml, Cfg.Settings.PathSrcErrOnExtract, FileName); + } + } else { + // Link ad un indice + cTools.SaveToFile(thtml, Cfg.Settings.PathIdxDone, FileName); + } + #endregion + + Status = eLinkState.End; + App.DB.LinkLog(this); + } + } + #endregion + + #region End + if (Status == eLinkState.End) { + } + #endregion + + #region Error + if (Status == eLinkState.Error) { + } + #endregion + + #region Abort + if (Status == eLinkState.Abort) { + } + #endregion + + #region Cancel + if (Status == eLinkState.Cancel) { + } + #endregion + + Console.WriteLine("Link.Count=" + newlinks.Count.ToString("00")); + + } catch (Exception ex) { + Console.WriteLine($"Errore con {URL}: {ex.Message}"); + Status = eLinkState.Error; + App.DB.LinkLog(this); + } + return newlinks; + } + + #endregion + + + }//class cLink_eRac + +}//namespace A69WD.Net diff --git a/Src/A69WD/Service/Service_Crawler.cs b/Src/A69WD/Service/Service_Crawler.cs index daaaf42..c1ca6b1 100644 --- a/Src/A69WD/Service/Service_Crawler.cs +++ b/Src/A69WD/Service/Service_Crawler.cs @@ -76,6 +76,7 @@ namespace A69WD.Service { // Autenticazione ai siti: if (!cLink_A69.Autenticated) { await cLink_A69.Authenticate(); } + if (!cLink_eRac.Autenticated) { await cLink_eRac.Authenticate(); } // Ciclo per ciascun elemento della FIFO: foreach (iLink link in _urlQueue.GetConsumingEnumerable()) { @@ -87,8 +88,16 @@ namespace A69WD.Service { await _semaphore.WaitAsync(); try { - cLink_A69 clk = link as cLink_A69; - List urls = await clk.CrawlPageAsync(); + List urls = null; + if (link is cLink_A69) { + cLink_A69 clk = link as cLink_A69; + urls = await clk.CrawlPageAsync(); + } else { + if (link is cLink_eRac) { + cLink_eRac clk = link as cLink_eRac; + urls = await clk.CrawlPageAsync(); + } + } Logger.Information("ProcessQueue: end url " + link.FileName + " - URL trovati: " + urls.Count.ToString("000")); foreach (iLink url in urls) { if (url.Validate) { diff --git a/Src/A69WD/UI/frmReader.cs b/Src/A69WD/UI/frmReader.cs index 9014c2e..131354d 100644 --- a/Src/A69WD/UI/frmReader.cs +++ b/Src/A69WD/UI/frmReader.cs @@ -61,9 +61,9 @@ namespace A69WD.UI { mImpStart.Enabled = true; mImpStop.Enabled = false; - // Update UI - pnlTop.Enabled = false; - pnlTop.Visible = false; + // // Update UI + // pnlTop.Enabled = false; + // pnlTop.Visible = false; } @@ -684,7 +684,13 @@ namespace A69WD.UI { // Preparo il servizio serviceCrawler = new Service_Crawler(sb); // Inserisco i link iniziali nella coda + if (!cLink_eRac.InsertStartLink(serviceCrawler)) { + Logger.Warning("eRac - Insert start link Fault"); + sbStatusLabel.Text = "eRac fault."; + return; + } if (!cLink_A69.InsertStartLink(serviceCrawler)) { + Logger.Warning("A69 - Insert start link Fault"); sbStatusLabel.Text = "A69 fault."; return; } @@ -735,8 +741,28 @@ namespace A69WD.UI { } private void btnTest1_Click(object sender, EventArgs e) { - // Test download multipli con sempre lo stesso client per condividere la sessione - ; + // Test skraping eRac + + + // - Verifico path per il download + if (!System.IO.Directory.Exists(Cfg.Settings.PathDownloadWorking)) System.IO.Directory.CreateDirectory(Cfg.Settings.PathDownloadWorking); + + // Preparo il servizio + serviceCrawler = new Service_Crawler(sb); + // // Inserisco i link iniziali nella coda + // if (!cLink_eRac.InsertStartLink(serviceCrawler)) { + // Logger.Warning("eRac - Insert start link Fault"); + // sbStatusLabel.Text = "eRac fault."; + // return; + // } + + // Inserisco link di un racconto: + string url = "https://www.eroticiracconti.it/racconto/105286-nicole-gis-il-culto-della-terza-notte"; // "https://www.eroticiracconti.it/racconto/112763-elara-capitolo-2-il-cambiamento"; + string name = "eRac_112763-elara-capitolo-2-il-cambiamento.html"; + serviceCrawler.EnqueueUrl(new cLink_eRac(url, name)); + + // avvio il servizio + serviceCrawler.StartWorker(); } -- 2.54.0 From f8685ad65da877deef04bfeabbef74614019646d Mon Sep 17 00:00:00 2001 From: CSiCoAlm Date: Fri, 2 Jan 2026 17:53:38 +0100 Subject: [PATCH 2/2] Testato nuovo skraping --- Src/A69WD/Net/cLink_eRac.cs | 186 +++++++++++++-------------- Src/A69WD/Properties/AssemblyInfo.cs | 20 ++- Src/A69WD/UI/frmReader.cs | 26 ++-- 3 files changed, 124 insertions(+), 108 deletions(-) diff --git a/Src/A69WD/Net/cLink_eRac.cs b/Src/A69WD/Net/cLink_eRac.cs index d6c2341..91a8298 100644 --- a/Src/A69WD/Net/cLink_eRac.cs +++ b/Src/A69WD/Net/cLink_eRac.cs @@ -493,99 +493,99 @@ namespace A69WD.Net { { if (Status == eLinkState.ToAnalize) { List tmpLk = new List(); - // - // #region Estraggo gli url ad indici: - // { - // /* - // * Gli url delle pagine di indice sono del tipo: - // * - // * - // * - // */ - // try { - // // Estraggo i link alle altre pagine: - // var tnodes = tdoc.DocumentNode.SelectNodes("//div[@class='pagination']//a[@href]"); - // if (tnodes != null) { - // foreach (var link in tnodes) { - // var href = link.GetAttributeValue("href", ""); - // if (!string.IsNullOrEmpty(href) && href.StartsWith("/archivio/Tutto/")) - // tmpLk.Add(href); //tmpLk.Add(cLink_eRac.PageBase + href); - // } - // } - // // Rimuove duplicati e ordina alfabeticamente - // tmpLk = tmpLk - // .OrderBy(s => s) // ordina alfabeticamente - // .Distinct() // elimina duplicati - // .ToList(); - // // Inserisco i link trovati - // foreach (string ilk in tmpLk) { - // string url = cLink_eRac.PageBase + ilk; - // int offset = int.Parse(ilk.Replace("/archivio/Tutto/", "")); - // string name = $"_eRac_Idx_{offset.ToString("0000")}.html"; - // newlinks.Add(new cLink_eRac(url, name)); - // } - // } catch (Exception ex) { - // Logger.Error("Errore analisi Idx link dal " + FileName + " - " + ex.Message); - // cTools.SaveToFile(thtml, Cfg.Settings.PathSrcErrOnExtract, FileName); - // } - // } - // #endregion - // - // #region Estraggo gli url a racconti: - // { - // /* - // * - // * I link ai racconti sono dei pulsanti così formati: - // * - // * - // */ - // try { - // // Estraggo i link ai racconti: - // tmpLk = new List(); - // // Estraggo i link alle altre pagine: - // var tnodes = tdoc.DocumentNode.SelectNodes("//a[@class='rac']"); - // if (tnodes != null) { - // foreach (var link in tnodes) { - // var href = link.GetAttributeValue("href", ""); - // if (!string.IsNullOrEmpty(href) && href.StartsWith("/racconto/")) - // tmpLk.Add(href); //tmpLk.Add(cLink_eRac.PageBase + href); - // } - // } - // // Rimuove duplicati e ordina alfabeticamente - // tmpLk = tmpLk - // .OrderBy(s => s) // ordina alfabeticamente - // .Distinct() // elimina duplicati - // .ToList(); - // // Inserisco i link trovati - // foreach (string ilk in tmpLk) { - // string url = cLink_eRac.PageBase + ilk; - // string name = ilk.Replace("/racconto/", "eRac_").Replace(@"/", "_") + ".html"; - // newlinks.Add(new cLink_eRac(url, name)); - // } - // } catch (Exception ex) { - // Logger.Error("Errore analisi Idx link dal " + FileName + " - " + ex.Message); - // cTools.SaveToFile(thtml, Cfg.Settings.PathSrcErrOnExtract, FileName); - // } - // } - // #endregion - // + + #region Estraggo gli url ad indici: + { + /* + * Gli url delle pagine di indice sono del tipo: + * + * + * + */ + try { + // Estraggo i link alle altre pagine: + var tnodes = tdoc.DocumentNode.SelectNodes("//div[@class='pagination']//a[@href]"); + if (tnodes != null) { + foreach (var link in tnodes) { + var href = link.GetAttributeValue("href", ""); + if (!string.IsNullOrEmpty(href) && href.StartsWith("/archivio/Tutto/")) + tmpLk.Add(href); //tmpLk.Add(cLink_eRac.PageBase + href); + } + } + // Rimuove duplicati e ordina alfabeticamente + tmpLk = tmpLk + .OrderBy(s => s) // ordina alfabeticamente + .Distinct() // elimina duplicati + .ToList(); + // Inserisco i link trovati + foreach (string ilk in tmpLk) { + string url = cLink_eRac.PageBase + ilk; + int offset = int.Parse(ilk.Replace("/archivio/Tutto/", "")); + string name = $"_eRac_Idx_{offset.ToString("0000")}.html"; + newlinks.Add(new cLink_eRac(url, name)); + } + } catch (Exception ex) { + Logger.Error("Errore analisi Idx link dal " + FileName + " - " + ex.Message); + cTools.SaveToFile(thtml, Cfg.Settings.PathSrcErrOnExtract, FileName); + } + } + #endregion + + #region Estraggo gli url a racconti: + { + /* + * + * I link ai racconti sono dei pulsanti così formati: + * + * + */ + try { + // Estraggo i link ai racconti: + tmpLk = new List(); + // Estraggo i link alle altre pagine: + var tnodes = tdoc.DocumentNode.SelectNodes("//a[@class='rac']"); + if (tnodes != null) { + foreach (var link in tnodes) { + var href = link.GetAttributeValue("href", ""); + if (!string.IsNullOrEmpty(href) && href.StartsWith("/racconto/")) + tmpLk.Add(href); //tmpLk.Add(cLink_eRac.PageBase + href); + } + } + // Rimuove duplicati e ordina alfabeticamente + tmpLk = tmpLk + .OrderBy(s => s) // ordina alfabeticamente + .Distinct() // elimina duplicati + .ToList(); + // Inserisco i link trovati + foreach (string ilk in tmpLk) { + string url = cLink_eRac.PageBase + ilk; + string name = ilk.Replace("/racconto/", "eRac_").Replace(@"/", "_") + ".html"; + newlinks.Add(new cLink_eRac(url, name)); + } + } catch (Exception ex) { + Logger.Error("Errore analisi Idx link dal " + FileName + " - " + ex.Message); + cTools.SaveToFile(thtml, Cfg.Settings.PathSrcErrOnExtract, FileName); + } + } + #endregion + #region Estraggo il racconto dal file e lo inserisco nel DB if (FileName.StartsWith("eRac_")) { // Link ad un racconto diff --git a/Src/A69WD/Properties/AssemblyInfo.cs b/Src/A69WD/Properties/AssemblyInfo.cs index 25d85c1..3a476fb 100644 --- a/Src/A69WD/Properties/AssemblyInfo.cs +++ b/Src/A69WD/Properties/AssemblyInfo.cs @@ -32,8 +32,24 @@ using System.Runtime.InteropServices; // È possibile specificare tutti i valori oppure impostare valori predefiniti per i numeri relativi alla revisione e alla build // usando l'asterisco '*' come illustrato di seguito: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.5.2.0")] -[assembly: AssemblyFileVersion("0.5.2.0")] +[assembly: AssemblyVersion("0.5.3.0")] +[assembly: AssemblyFileVersion("0.5.3.0")] + + +/* + * + * Vrs 0.5.3.0 + * + * Compilata da CSiCoAlm il 2026/01/02 + * Inserito nello skraping anche la sorgente eRac + * + * + * ToDo: + * - Aggiungere gestione parallela della FIFO secondo vecchi modello per aumentare il feedback alla UI + * - Inserire anche l'estrazione dei racconti + * - Inserire funzionalità avanzate sul lettore + * + */ /* diff --git a/Src/A69WD/UI/frmReader.cs b/Src/A69WD/UI/frmReader.cs index 131354d..6a31982 100644 --- a/Src/A69WD/UI/frmReader.cs +++ b/Src/A69WD/UI/frmReader.cs @@ -61,9 +61,9 @@ namespace A69WD.UI { mImpStart.Enabled = true; mImpStop.Enabled = false; - // // Update UI - // pnlTop.Enabled = false; - // pnlTop.Visible = false; + // Update UI + pnlTop.Enabled = false; + pnlTop.Visible = false; } @@ -749,17 +749,17 @@ namespace A69WD.UI { // Preparo il servizio serviceCrawler = new Service_Crawler(sb); - // // Inserisco i link iniziali nella coda - // if (!cLink_eRac.InsertStartLink(serviceCrawler)) { - // Logger.Warning("eRac - Insert start link Fault"); - // sbStatusLabel.Text = "eRac fault."; - // return; - // } + // Inserisco i link iniziali nella coda + if (!cLink_eRac.InsertStartLink(serviceCrawler)) { + Logger.Warning("eRac - Insert start link Fault"); + sbStatusLabel.Text = "eRac fault."; + return; + } - // Inserisco link di un racconto: - string url = "https://www.eroticiracconti.it/racconto/105286-nicole-gis-il-culto-della-terza-notte"; // "https://www.eroticiracconti.it/racconto/112763-elara-capitolo-2-il-cambiamento"; - string name = "eRac_112763-elara-capitolo-2-il-cambiamento.html"; - serviceCrawler.EnqueueUrl(new cLink_eRac(url, name)); + //// Inserisco link di un racconto: + //string url = "https://www.eroticiracconti.it/racconto/105286-nicole-gis-il-culto-della-terza-notte"; // "https://www.eroticiracconti.it/racconto/112763-elara-capitolo-2-il-cambiamento"; + //string name = "eRac_112763-elara-capitolo-2-il-cambiamento.html"; + //serviceCrawler.EnqueueUrl(new cLink_eRac(url, name)); // avvio il servizio serviceCrawler.StartWorker(); -- 2.54.0