I'm building web scraper application which takes name, code and price from few sites. I thought factory pattern would fit in my application. I would like to someone review my code and tell if I something missed out.
I have class Item which holds scraped data.
public class Item
{
public string Code { get; set; }
public string Name { get; set; }
public string Price { get; set; }
}
Interface which have method RunScrapingAsync
with one parameter list of item codes which I need scape.
public interface IWebScraper
{
Task<List<Item>> RunScrapingAsync(List<string> itemCodes);
}
There I have implementations for three scrapers (Amazon, EBay, AliExpress):
public class AmazonWebScraper : IWebScraper
{
private static HttpClient client;
public List<string> ItemCodes { get; set; }
public AmazonWebScraper()
{
client = new HttpClient(new HttpClientHandler() { Proxy = null });
client.BaseAddress = new Uri("https://amazon.com");
}
public async Task<List<Item>> RunScrapingAsync(List<string> itemCodes)
{
ItemCodes = itemCodes;
ConcurrentBag<Item> itemsConcurrentBag = new ConcurrentBag<Item>();
//for simplicity this logic is not important no need to go in details
return itemsConcurrentBag.ToList();
}
}
public class EBayWebScraper : IWebScraper
{
private static HttpClient client;
public List<string> ItemCodes { get; set; }
public EBayWebScraper()
{
client = new HttpClient(new HttpClientHandler() { Proxy = null });
client.BaseAddress = new Uri("https://ebay.com");
}
public async Task<List<Item>> RunScrapingAsync(List<string> itemCodes)
{
ItemCodes = itemCodes;
ConcurrentBag<Item> itemsConcurrentBag = new ConcurrentBag<Item>();
//for simplicity this logic is not important no need to go in details
return itemsConcurrentBag.ToList();
}
}
public class AliExpressWebScraper : IWebScraper
{
private static HttpClient client;
public List<string> ItemCodes { get; set; }
public AliExpressWebScraper()
{
client = new HttpClient(new HttpClientHandler() { Proxy = null });
client.BaseAddress = new Uri("https://aliexpress.com");
}
public async Task<List<Item>> RunScrapingAsync(List<string> itemCodes)
{
ItemCodes = itemCodes;
ConcurrentBag<Item> itemsConcurrentBag = new ConcurrentBag<Item>();
//for simplicity this logic is not important no need to go in details
return itemsConcurrentBag.ToList();
}
}
Here is my factory class WebScraperFactory
:
public enum WebSite
{
Amazon,
EBay,
AliExpress
}
public class WebScraperFactory
{
private readonly Dictionary<WebSite, IWebScraper> _scrapers;
public WebScraperFactory()
{
_scrapers = new Dictionary<WebSite, IWebScraper>();
foreach (WebSite webSite in Enum.GetValues(typeof(WebSite)))
{
_scrapers.Add(webSite, (IWebScraper)Activator.CreateInstance(Type.GetType($"{webSite}WebScraper")));
}
}
public async Task<List<Item>> Execute(WebSite website, List<string> itemCodes) => await _scrapers[website].RunScrapingAsync(itemCodes);
}
This is WinForm app so user have option to run one or more scraping (they are not all mandatory to run). So if user choose to run Amazon and AliExpress it will choose two files with codes add it in Dictionary
and on every chosen website call webscraper factory.
Example:
var websitesItemCodes = new Dictionary<WebSite, List<string>>
{
{WebSite.Amazon, amazonCodes},
{WebSite.AliExpress, aliExpressCodes}
}
var websitesItems = new Dictionary<WebSite, List<Item>>
{
{WebSite.Amazon, null},
{WebSite.AliExpress, null}
}
var factory = new WebScraperFactory();
foreach(var webSite in websitesItemCodes.Keys)
{
websitesItems[webSite] = await factory.Execute(webSite, websitesItemCodes[webSite]);
}