mirror of
https://github.com/xboxeer/NScrapy.git
synced 2026-10-18 21:57:48 +08:00
44a6df9804
## Major Changes - Upgrade all 9 projects from netcoreapp2.0 to net10.0 - Update NuGet packages to latest compatible versions: - HtmlAgilityPack → 1.11.61 - log4net → 2.0.17 - Microsoft.Extensions.Configuration* → 8.0.0 - Newtonsoft.Json → 13.0.3 - StackExchange.Redis → 2.7.33 - MongoDB.Driver → 2.25.0 - Microsoft.NET.Test.Sdk → 17.9.0, MSTest → 3.2.0 - Remove ZooKeeperNetEx (no .NET 8/10 compatible version) - Remove HtmlAgilityPack.CssSelectors.NetCore → replaced with Fizzler.Systems.HtmlAgilityPack - Exclude ZooKeeper-dependent files: ZookeeperConfigProvider, ConfigProviderFactory, DefaultConfigProvider - Add .gitignore - Fix source code API changes from package upgrades (QuerySelectorAll, etc.) ## New Demo Project - NScrapy.Demo: LianjiaHouseSpider - crawls Beijing rental listings - Runs in InMemory mode (no ZooKeeper/Redis required) - Outputs results to CSV - Demonstrates NScrapy framework usage
98 lines
4.2 KiB
C#
98 lines
4.2 KiB
C#
using NScrapy.Downloader;
|
|
using NScrapy.Downloader;
|
|
using NScrapy.Infra;
|
|
using System;
|
|
using System.Threading.Tasks;
|
|
using Newtonsoft.Json;
|
|
using Newtonsoft.Json.Serialization;
|
|
using System.Runtime.Serialization.Json;
|
|
using System.IO;
|
|
using System.Text;
|
|
using System.Runtime.Serialization.Formatters.Binary;
|
|
using NScrapy.Scheduler.RedisExt;
|
|
|
|
namespace NScrapy.DownloaderShell
|
|
{
|
|
public class Program
|
|
{
|
|
public static Guid ID;
|
|
public static void Main(string[] args)
|
|
{
|
|
ID = Guid.NewGuid();
|
|
var context = Downloader.DownloaderContext.CurrentContext;
|
|
context.RunningMode = Downloader.DownloaderRunningMode.Distributed;
|
|
context.Log.Info("Downloader Started");
|
|
var receiveQueueName = DownloaderContext.CurrentContext.CurrentConfig["AppSettings:Scheduler.RedisExt:ReceiverQueue"];
|
|
var responseQueueName = DownloaderContext.CurrentContext.CurrentConfig["AppSettings:Scheduler.RedisExt:ResponseQueue"];
|
|
while (true)
|
|
{
|
|
var lockToken = Guid.NewGuid().ToString();
|
|
//Get Lock before we count the lengh of queue
|
|
//In case multiple Downloader runs into this part and found there are 1 item in queue
|
|
//Then one of the Downloader gets that item, results to other Downloader get nothing
|
|
RedisManager.GetLock($"{receiveQueueName}.Lock", lockToken);
|
|
if (RedisManager.Connection.GetDatabase().ListLength(receiveQueueName) > 0 &&
|
|
Downloader.Downloader.RunningDownloader < Downloader.Downloader.DownloaderPoolCapbility)
|
|
{
|
|
|
|
var requestMessage = string.Empty;
|
|
try
|
|
{
|
|
requestMessage = RedisManager.Connection.GetDatabase().ListRightPop(receiveQueueName);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
DownloaderContext.CurrentContext.Log.Error($"Aquire lock failed!", ex);
|
|
}
|
|
finally
|
|
{
|
|
RedisManager.ReleaseLock($"{receiveQueueName}.Lock", lockToken);
|
|
}
|
|
ProcessRequestAndSendBack(responseQueueName, requestMessage);
|
|
}
|
|
}
|
|
}
|
|
|
|
private static void ProcessRequestAndSendBack(string responseQueueName, string requestMessage)
|
|
{
|
|
var requestObj = JsonConvert.DeserializeObject<RedisRequestMessage>(requestMessage);
|
|
var request = new HttpRequest()
|
|
{
|
|
URL = requestObj.URL
|
|
};
|
|
var result = Downloader.Downloader.SendRequestAsync(request);
|
|
|
|
result.ContinueWith(async u =>
|
|
{
|
|
|
|
var resultPayload = string.Empty;
|
|
try
|
|
{
|
|
resultPayload = JsonConvert.SerializeObject(u.Result);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
DownloaderContext.CurrentContext.Log.Error($"Serialize response for {request.URL} failed!", ex);
|
|
}
|
|
|
|
resultPayload = await NScrapyHelper.CompressString(resultPayload);
|
|
var responseMessage = new RedisResponseMessage()
|
|
{
|
|
URL = requestObj.URL,
|
|
CallbacksFingerprint = requestObj.CallbacksFingerprint,
|
|
Payload = resultPayload
|
|
};
|
|
|
|
//var publishResult = RedisManager.Connection.GetSubscriber().Publish(responseQueueName, $"{JsonConvert.SerializeObject(responseMessage)}");
|
|
var publishResult = RedisManager.Connection.GetDatabase().ListLeftPush(responseQueueName, $"{JsonConvert.SerializeObject(responseMessage)}");
|
|
DownloaderContext.CurrentContext.Log.Info($"Sending request to {request.URL} success!");
|
|
|
|
},
|
|
TaskContinuationOptions.OnlyOnRanToCompletion);
|
|
result.ContinueWith(u =>
|
|
DownloaderContext.CurrentContext.Log.Info($"Sending request to {request.URL} failed", result.Exception.InnerException),
|
|
TaskContinuationOptions.OnlyOnFaulted);
|
|
}
|
|
}
|
|
}
|