Inserito analisi del link per l'estrazione dei link agli indici e ai racconti
- Testata estrazione die link alle pagine di indice - Testata estrazione dei link ai racconti - iniziato ad inserire un service per la gestione parallela. ToDo: - Aggiungere gestione parallela - Aggiungere analisi di quanto downloadato per estrarre altri link e proseguire con lo skraping - Aumentare i log in modo da tenere traccia di quanto succede - Animare la UI in modo da far capire cosa succede
This commit is contained in:
1 parent
5567b141f8
commit
3033880fd9
6 files changed
+325
-36
No files matched your search
@@ -62,6 +62,7 @@
|
||||
<Compile Include="Data\DBTools.cs" />
|
||||
<Compile Include="Net\eLinkState.cs" />
|
||||
<Compile Include="Net\cLink_A69.cs" />
|
||||
<Compile Include="Service\Service_Crawler.cs" />
|
||||
<Compile Include="Site\cSite_A69.cs" />
|
||||
<Compile Include="UI\frmDownloader.cs">
|
||||
<SubType>Form</SubType>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.Remoting.Messaging;
|
||||
@@ -42,6 +43,35 @@ namespace A69WD.Net {
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static List<iLink> GetStartLink() {
|
||||
List<iLink> links = new List<iLink>();
|
||||
for (int i = 0; i < 10; i++) {
|
||||
foreach (string cat in categorie) {
|
||||
string url = LinkIdxBase.Replace("{Categoria}", cat).Replace("{ID}", i.ToString());
|
||||
string name = string.Format("_A69_{0}_{1}.html", cat, i.ToString());
|
||||
links.Add(new cLink_A69(url, name));
|
||||
}
|
||||
}
|
||||
return links;
|
||||
}
|
||||
|
||||
public static bool InsertStartLink(BlockingCollection<iLink> _urlQueue) {
|
||||
int i = 1;
|
||||
try {
|
||||
foreach (string cat in categorie) {
|
||||
string url = LinkIdxBase.Replace("{Categoria}", cat).Replace("{ID}", i.ToString());
|
||||
string name = string.Format("_A69_{0}_{1}.html", cat, i.ToString("0000"));
|
||||
_urlQueue.Add(new cLink_A69(url, name));
|
||||
}
|
||||
return true;
|
||||
} catch (Exception ex) {
|
||||
Logger.Error("Errore inserendo A69 Start Link - " + ex.Message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}//class cLink_A69
|
||||
|
||||
}//namespace A69WD.Net
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
|
||||
|
||||
namespace A69WD.Service {
|
||||
public class Service_Crawler {
|
||||
|
||||
// Thread worker che consuma la coda
|
||||
private Thread _workerThread;
|
||||
|
||||
// Coda thread-safe di URL da scaricare
|
||||
private readonly BlockingCollection<string> _urlQueue = new BlockingCollection<string>(new ConcurrentQueue<string>());
|
||||
|
||||
// Semaforo per limitare il numero massimo di download simultanei
|
||||
private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1);
|
||||
|
||||
// Contatori
|
||||
private int _inCorso = 0;
|
||||
private int _completati = 0;
|
||||
private int _errori = 0;
|
||||
|
||||
// HttpClient autenticato (fornito da AuthService)
|
||||
private HttpClient _client;
|
||||
|
||||
|
||||
public Service_Crawler(Label lblInCorso) {
|
||||
_lblInCorso = lblInCorso;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Riferimenti ai controlli UI per aggiornare i contatori e la progress bar
|
||||
private readonly Label _lblInCorso;
|
||||
private readonly Label _lblCompletati;
|
||||
private readonly Label _lblDaFare;
|
||||
private readonly Label _lblErrori;
|
||||
private readonly ProgressBar _progressBar;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Avvia il thread worker che consuma la coda di URL.
|
||||
/// </summary>
|
||||
public void StartWorker(HttpClient client) {
|
||||
_client = client;
|
||||
_workerThread = new Thread(ProcessQueue) { IsBackground = true };
|
||||
_workerThread.Start();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ferma il worker completando la coda.
|
||||
/// </summary>
|
||||
public void StopWorker() {
|
||||
_urlQueue.CompleteAdding();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Aggiunge un URL alla coda FIFO.
|
||||
/// </summary>
|
||||
public void EnqueueUrl(string url) {
|
||||
_urlQueue.Add(url);
|
||||
UpdateCounters();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Thread worker: consuma la coda ed avvia task di download.
|
||||
/// </summary>
|
||||
private void ProcessQueue() {
|
||||
foreach (var url in _urlQueue.GetConsumingEnumerable()) {
|
||||
Task.Run(async () => {
|
||||
Interlocked.Increment(ref _inCorso);
|
||||
UpdateCounters();
|
||||
|
||||
await _semaphore.WaitAsync();
|
||||
try {
|
||||
// Scarica contenuto della pagina
|
||||
var html = await _client.GetStringAsync(url);
|
||||
|
||||
Interlocked.Increment(ref _completati);
|
||||
|
||||
// Salvo il file downloadato
|
||||
System.IO.StreamWriter sw = new System.IO.StreamWriter("A69_Idx_altro_" + _completati.ToString("000") + ".html", false, Encoding.UTF8);
|
||||
sw.Write(html);
|
||||
|
||||
Logger.Information($"Scaricato {url} ({html.Length} bytes)");
|
||||
} catch (Exception ex) {
|
||||
Interlocked.Increment(ref _errori);
|
||||
Logger.Error($"Errore su {url}: {ex.Message}");
|
||||
} finally {
|
||||
Interlocked.Decrement(ref _inCorso);
|
||||
_semaphore.Release();
|
||||
UpdateCounters();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Aggiorna i contatori e la progress bar sulla UI.
|
||||
/// </summary>
|
||||
private void UpdateCounters() {
|
||||
if (_lblInCorso.InvokeRequired) {
|
||||
_lblInCorso.Invoke(new Action(UpdateCounters));
|
||||
return;
|
||||
}
|
||||
|
||||
int daFare = _urlQueue.Count;
|
||||
|
||||
_lblInCorso.Text = $"In corso: {_inCorso} - Completati: {_completati} - Errori: {_errori} - Da fare: {daFare}";
|
||||
|
||||
//int totale = _inCorso + _completati + _errori + daFare;
|
||||
//int fatti = _completati + _errori;
|
||||
//
|
||||
//_progressBar.Maximum = totale > 0 ? totale : 1;
|
||||
//_progressBar.Value = fatti;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+103
-23
@@ -87,8 +87,18 @@ namespace A69WD.Site {
|
||||
return logged;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<string>> CrawlPageAsync(iLink lk) {
|
||||
var links = new List<string>();
|
||||
/// <summary>
|
||||
/// Codice da eseguire per ciascun A69 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
|
||||
/// </summary>
|
||||
/// <param name="lk"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<List<iLink>> CrawlPageAsync(iLink lk) {
|
||||
var newlinks = new List<iLink>();
|
||||
try {
|
||||
Console.WriteLine($"A69 - Scarico: {lk.URL}");
|
||||
HtmlDocument tdoc = null;
|
||||
@@ -125,7 +135,7 @@ namespace A69WD.Site {
|
||||
Console.WriteLine($"A69 - Errore HTTP {(int)resp.StatusCode} {resp.ReasonPhrase} per {lk.URL}");
|
||||
lk.Status = eLinkState.Error;
|
||||
//App.DB.LinkLog(lk);
|
||||
return links;
|
||||
return newlinks;
|
||||
}
|
||||
// Scarico la pagina
|
||||
var thtml = await client.GetStringAsync(lk.URL);
|
||||
@@ -141,24 +151,94 @@ namespace A69WD.Site {
|
||||
#endregion
|
||||
|
||||
#region ToAnalize
|
||||
// if (lk.Status == eLinkState.ToAnalize) {
|
||||
// // Estraggo i link alle altre pagine:
|
||||
// var tnodes = tdoc.DocumentNode.SelectNodes("//div[@id='pagination']//li//a[@href]");
|
||||
// if (tnodes != null) {
|
||||
// foreach (var link in tnodes) {
|
||||
// var href = link.GetAttributeValue("href", "");
|
||||
// if (!string.IsNullOrEmpty(href) && href.StartsWith("/racconti-erotici/racconti_lista.php?genere="))
|
||||
// links.Add(cLink_A69.PageBase + href);
|
||||
// }
|
||||
// }
|
||||
// // Rimuove duplicati e ordina alfabeticamente
|
||||
// links = links
|
||||
// .Distinct() // elimina duplicati
|
||||
// .OrderBy(s => s) // ordina alfabeticamente
|
||||
// .ToList();
|
||||
// }
|
||||
// lk.Status = eLinkState.End;
|
||||
// App.DB.LinkLog(lk);
|
||||
{
|
||||
if (lk.Status == eLinkState.ToAnalize) {
|
||||
List<string> tmpLk = new List<string>();
|
||||
#region Estraggo gli url ad indici:
|
||||
{
|
||||
/*
|
||||
* Gli url delle pagine di indice sono del tipo:
|
||||
*
|
||||
* <div id="pagination">
|
||||
* <ul>
|
||||
* <li class="prev"><a href="/racconti-erotici/racconti_lista.php?genere=altro&pagina=2">‹</a></li>
|
||||
* <li class="page"><a href="/racconti-erotici/racconti_lista.php?genere=altro&pagina=1">1</a></li>
|
||||
* <li class="page"><a href="/racconti-erotici/racconti_lista.php?genere=altro&pagina=2">2</a></li>
|
||||
* <li class="currentpage">3</li>
|
||||
* <li class="page"><a href="/racconti-erotici/racconti_lista.php?genere=altro&pagina=4">4</a></li>
|
||||
* <li class="page"><a href="/racconti-erotici/racconti_lista.php?genere=altro&pagina=5">5</a></li>
|
||||
* <li class="next"><a href="/racconti-erotici/racconti_lista.php?genere=altro&pagina=4">›</a></li>
|
||||
* </ul>
|
||||
* </div>
|
||||
*
|
||||
*/
|
||||
// Estraggo i link alle altre pagine:
|
||||
var tnodes = tdoc.DocumentNode.SelectNodes("//div[@id='pagination']//ul//li//a[@href]");
|
||||
if (tnodes != null) {
|
||||
foreach (var link in tnodes) {
|
||||
var href = link.GetAttributeValue("href", "");
|
||||
if (!string.IsNullOrEmpty(href) && href.StartsWith("/racconti-erotici/racconti_lista.php?genere="))
|
||||
tmpLk.Add(href); //tmpLk.Add(cLink_A69.PageBase + href);
|
||||
}
|
||||
}
|
||||
// Rimuove duplicati e ordina alfabeticamente
|
||||
tmpLk = tmpLk
|
||||
.OrderBy(s => s) // ordina alfabeticamente
|
||||
.Distinct() // elimina duplicati
|
||||
.ToList();
|
||||
// Inserisco i link trovati
|
||||
try {
|
||||
foreach (string ilk in tmpLk) {
|
||||
string[] separator = new string[] { "&pagina=" };
|
||||
string[] txt = ilk.Split(separator, StringSplitOptions.RemoveEmptyEntries);
|
||||
string url = cLink_A69.PageBase + ilk;
|
||||
string name = txt[0].Replace("/racconti-erotici/racconti_lista.php?genere=", "_A69_") + "_" + int.Parse(txt[1]).ToString("0000") + ".html";
|
||||
newlinks.Add(new cLink_A69(url, name));
|
||||
}
|
||||
} catch (Exception ex) { Logger.Error("Errore analisi Idx link dal " + lk.FileName + " - " + ex.Message); }
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Estraggo gli url a racconti:
|
||||
{
|
||||
/*
|
||||
*
|
||||
* I link ai racconti sono dei pulsanti così formati:
|
||||
* <div class="continua">
|
||||
* <a href="/racconti-erotici/altro/Tutto-e-iniziato-per-gioco-pazza-famiglia_166770.html">Continua a leggere » </a>
|
||||
* </div>
|
||||
*/
|
||||
// Estraggo i link ai racconti:
|
||||
tmpLk = new List<string>();
|
||||
// Estraggo i link alle altre pagine:
|
||||
var tnodes = tdoc.DocumentNode.SelectNodes("//div[@class='continua']//a[@href]");
|
||||
if (tnodes != null) {
|
||||
foreach (var link in tnodes) {
|
||||
var href = link.GetAttributeValue("href", "");
|
||||
if (!string.IsNullOrEmpty(href) && href.StartsWith("/racconti-erotici/") && (href.EndsWith(".html") || href.EndsWith(".htm")))
|
||||
tmpLk.Add(href); //tmpLk.Add(cLink_A69.PageBase + href);
|
||||
}
|
||||
}
|
||||
// Rimuove duplicati e ordina alfabeticamente
|
||||
tmpLk = tmpLk
|
||||
.OrderBy(s => s) // ordina alfabeticamente
|
||||
.Distinct() // elimina duplicati
|
||||
.ToList();
|
||||
// Inserisco i link trovati
|
||||
try {
|
||||
foreach (string ilk in tmpLk) {
|
||||
string url = cLink_A69.PageBase + ilk;
|
||||
string name = ilk.Replace("/racconti-erotici/", "A69_").Replace(@"/","_");
|
||||
newlinks.Add(new cLink_A69(url, name));
|
||||
}
|
||||
} catch (Exception ex) { Logger.Error("Errore analisi Idx link dal " + lk.FileName + " - " + ex.Message); }
|
||||
}
|
||||
#endregion
|
||||
|
||||
lk.Status = eLinkState.End;
|
||||
App.DB.LinkLog(lk);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region End
|
||||
@@ -181,14 +261,14 @@ namespace A69WD.Site {
|
||||
}
|
||||
#endregion
|
||||
|
||||
Console.WriteLine("Link.Count=" + links.Count.ToString("00"));
|
||||
Console.WriteLine("Link.Count=" + newlinks.Count.ToString("00"));
|
||||
|
||||
} catch (Exception ex) {
|
||||
Console.WriteLine($"Errore con {lk.URL}: {ex.Message}");
|
||||
lk.Status = eLinkState.Error;
|
||||
//App.DB.LinkLog(lk);
|
||||
}
|
||||
return links;
|
||||
return newlinks;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ namespace A69WD.Site {
|
||||
/// </summary>
|
||||
/// <param name="lk"></param>
|
||||
/// <returns></returns>
|
||||
Task<IEnumerable<string>> CrawlPageAsync(iLink lk);
|
||||
Task<List<iLink>> CrawlPageAsync(iLink lk);
|
||||
|
||||
}//interface iSiteType
|
||||
|
||||
|
||||
@@ -14,11 +14,21 @@ using static System.Windows.Forms.LinkLabel;
|
||||
using static System.Windows.Forms.VisualStyles.VisualStyleElement;
|
||||
using A69WD.Site;
|
||||
using A69WD.Net;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Xml.Linq;
|
||||
using A69WD.Service;
|
||||
|
||||
namespace A69WD {
|
||||
|
||||
public partial class frmDownloader : Form {
|
||||
|
||||
// Coda thread-safe di URL da scaricare
|
||||
private readonly BlockingCollection<iLink> _urlQueue = new BlockingCollection<iLink>(new ConcurrentQueue<iLink>());
|
||||
|
||||
// Semaforo per limitare il numero massimo di download simultanei
|
||||
private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1);
|
||||
|
||||
|
||||
|
||||
public frmDownloader() {
|
||||
InitializeComponent();
|
||||
@@ -52,20 +62,45 @@ namespace A69WD {
|
||||
A69WD.Site.iSiteType siteA69 = new cSite_A69();
|
||||
// - Eseguo l'autenticazione
|
||||
bool res = await siteA69.Authenticate();
|
||||
lblST.Text = DateTime.Now.ToString() + " - sito loggato: " + res.ToString();
|
||||
// - Verifico directory pe ri download
|
||||
if (!System.IO.Directory.Exists(Cfg.Settings.PathDownloadWorking)) { System.IO.Directory.CreateDirectory(Cfg.Settings.PathDownloadWorking); }
|
||||
// - Test di download di un link di indice
|
||||
iLink lk = new cLink_A69("https://www.annunci69.it/racconti-erotici/altro.html", "Idx_altro_01.html");
|
||||
await siteA69.CrawlPageAsync(lk);
|
||||
// - Test di download di un link di racconto
|
||||
lk = new cLink_A69("https://www.annunci69.it/racconti-erotici/altro/Oltre-il-desiderio_166769.html", "Rac_0001.html");
|
||||
await siteA69.CrawlPageAsync(lk);
|
||||
// - Test di download di un link protetto
|
||||
lk = new cLink_A69("https://www.annunci69.it/racconti-erotici/racconti_lista.php?genere=altro&pagina=11", "Idx_altro_11.html");
|
||||
await siteA69.CrawlPageAsync(lk);
|
||||
if (res) {
|
||||
lblST.Text = DateTime.Now.ToString() + " - sito loggato: " + res.ToString();
|
||||
Logger.Information("Sito correttamente loggato.");
|
||||
} else {
|
||||
Logger.Information("Errore di autenticazione al sito.");
|
||||
return;
|
||||
}
|
||||
// - Verifico path per il download
|
||||
if (!System.IO.Directory.Exists(Cfg.Settings.PathDownloadWorking)) System.IO.Directory.CreateDirectory(Cfg.Settings.PathDownloadWorking);
|
||||
// // Test downloadando tutti i 10 primi link per categoria
|
||||
// List<iLink> links = cLink_A69.GetStartLink();
|
||||
// int i = 1;
|
||||
// foreach (iLink link in links) {
|
||||
// lblST.Text = "Start url " + link.FileName;
|
||||
// Logger.Information("Start url " + link.FileName);
|
||||
// await siteA69.CrawlPageAsync(link);
|
||||
// Logger.Information(" end url " + link.FileName);
|
||||
// i++;
|
||||
// }
|
||||
|
||||
// Inserisco i link iniziali sulla coda dei download:
|
||||
if (!cLink_A69.InsertStartLink(_urlQueue)) {
|
||||
lblST.Text = "Inserimento A69 start link fault.";
|
||||
return;
|
||||
}
|
||||
lblST.Text = "In coda vi sono: " + _urlQueue.Count.ToString() + " url.";
|
||||
|
||||
// Test estrazione link dal primo indice:
|
||||
iLink link = new cLink_A69("https://www.annunci69.it/racconti-erotici/racconti_lista.php?genere=altro&pagina=1", "Idx_altro_1.html");
|
||||
Logger.Information("Start url " + link.FileName);
|
||||
List<iLink> urls = await siteA69.CrawlPageAsync(link);
|
||||
Logger.Information(" end url " + link.FileName + " - URL trovati: " + urls.Count.ToString("000"));
|
||||
foreach (iLink url in urls) { _urlQueue.Add(url); }
|
||||
lblST.Text = "In coda vi sono: " + _urlQueue.Count.ToString() + " url.";
|
||||
|
||||
|
||||
}
|
||||
private Service_Crawler service = null;
|
||||
|
||||
|
||||
private void btnShowLog_Click(object sender, EventArgs e) {
|
||||
cTools.ShowOnNotepad(Cfg.Settings.PathFileLogs);
|
||||
|
||||
Reference in new issue
Block a user