آموزش وب اسکرپینگ با سی شارپ – مقدماتی و به بیان ساده

۷۶۰ بازدید
آخرین به‌روزرسانی: ۲۴ اردیبهشت ۱۴۰۲
زمان مطالعه: ۲۲ دقیقه
آموزش وب اسکرپینگ با سی شارپ – مقدماتی و به بیان ساده

وب اِسکرِپینگ، تکنیکی است که در آن، از ربات‌ها به منظور استخراج محتوا و داده‌های وب‌سایتی دلخواه، استفاده می‌شود. این کار به صورت دستی نیز قابل انجام است، اما خودکار کردن این فرایند، علاوه بر سرعت بیشتر و بهینگی، خطای کمتری را به دنبال دارد. عملکرد وب اِسکرِپینگ به گونه‌ای است که کدهای HTML نهفته در صفحات وب را بیرون می‌کِشد و داده‌های موجود در این صفحات، که ممکن است ساختاری ضعیف و غیرجدولی داشته باشند را به‌صورت قالبی ساختاریافته در می‌آورد که برای کاربردهای گوناگون، مناسب‌تر خواهد بود. وب اسکرپینگ با سی شارپ فرایندی فراتر از جمع‌آوری داده‌ها است و می‌تواند در بایگانی داده‌ها و ردیابی آنلاین تغییرات آن‌ها نیز به ما کمک کند. در این مطلب، به بیانی ساده و به‌صورت گام به گام، آموزش وب اسکرپینگ با سی شارپ را با استفاده از کتابخانه‌هایی، نظیر «سلنیوم» (Selenium) و Html Agility Pack، خواهیم داشت و با ایجاد یک خزنده‌وب، داده‌های مورد نظر را از یک وب سایت نمونه استخراج می‌کنیم. همچنین مفاهیم پیشرفته‌تری مانند اسکرپینگ موازی، اسکرپینگ وب‌سایت‌های پویا و راهکارهایی به منظور پرهیز از بلاک شدن را نیز بررسی خواهیم کرد.

فهرست مطالب این نوشته

آشنایی با وب اسکرپینگ

وب اسکرپینگ، فرایند استخراج داده از وب‌سایت‌ها با استفاده از ابزارها و نرم‌افزارهای خودکار است. در دنیای پُرشتاب و داده‌محور امروز، وب اِسکرِپینگ به ابزاری ضروری برای کسب و کارها، محققان و تحلیلگران تبدیل شده است تا دیدگاه‌های ارزشمندی را از داده‌های حجیم موجود در اینترنت، بیرون بِکشند.

تحلیل‌های صورت گرفته با استفاده از داده‌های Scrape شده، در مقاصد مختلفی مانند شناسایی مشتریان بالقوه، اطلاع از روند قیمت‌گذاری در بازار، تحلیل احساسات مشتری و ده‌ها مورد دیگر قابل استفاده هستند. Web Scraping به طور روز افزون توسط محققان، به منظور ایجاد «مجموعه داده‌ها» (Data Sets)، برای پروژه‌هایی مانند «متن‌کاوی» (Text Mining) و غیره استفاده می‌شود. این داده‌ها، ممکن است مجموعه‌ای از مقالات ژورنالی یا متون دیجیتالی باشند.

سی شارپ (و به طور کلی دات نت)، تمامی‌ابزارها و کتابخانه‌های لازم برای پیاده‌سازی وب اِسکرِپینگ را فراهم و به شما کمک می‌کند تا به سرعت پروژه Scraper خود را پیاده‌سازی و داده‌های مورد نظر را جمع‌آوری کنید.

یکی از موضوعاتی که در این نوشتار به آن پرداخته شده است، تکنیک‌های مختلف برای پیشگیری از «انسداد» (Block شدن) و همین‌طور محدود شدن توسط سرور است. این قضیه، به عنوان یکی از موانع اصلی در مبحث وب اِسکرِپینگ، به‌شمار می‌رود.

امروزه، شرکت‌های زیادی هستند که از مزایای داده‌های جمع‌آوری شده از وب، بهره می‌گیرند. سی شارپ، یکی از مناسب‌ترین زبان‌های برنامه‌نویسی برای پیاده سازی Web Scraping است.

آموزش Web Scraping با سی شارپ

کتابخانه Html Agility Pack، محبوب‌ترین کتابخانه Scraper برای سی شارپ است. با استفاده از این کتابخانه، می‌توانید صفحات وب مورد نظر را دانلود و محتوای HTML آن‌ها را تجزیه کنید، به طوری‌که، پس از انتخاب عناصر HTML، بتوان داده‌های مورد نیاز را از آن‌ها استخراج کرد.

Selenium WebDriver، کتابخانه‌ی دیگری است که از چندین زبان برنامه‌نویسی پشتیبانی می‌کند و به شما امکان می‌دهد تست‌های خودکار برای وب اپلیکیشن بنویسید. همچنین می‌توانید از آن برای اهداف وب اسکرپینگ نیز استفاده کنید.

پیش نیاز‌های Web Scraping با C#‎

در این بخش به معرفی و شرح پیش‌نیازهایی پرداخته شده است که برای وب اسکریپینگ با سی شارپ مورد نیاز هستند. این موارد در زیربخش‌هایی جداگانه شامل دانلود و راه‌اندازی محیط و ابزارهای اولیه و همچنین ایجاد پروژه در سی شارپ، ارائه شده‌ است.

تنظیم و راه‌اندازی محیط برنامه نویسی وب اسکرپینگ با سی شارپ

به منظور پیاده‌سازی وب اِسکرِپینگ با سی شارپ، لازم است تا پیش نیازهای زیر را فراهم کنیم:

  • دانت نت نسخه ۷ (یا بالاتر): توصیه می‌شود که از جدیدترین نسخه دانت نت استفاده شود.
  • محیط IDE برای کد نویسی C#‎: ویژوال استدیو کامیونیتی ۲۰۲۲، می‌تواند گزینه مناسبی برای Web Scraping با سی شارپ باشد. همچنین اگر گزینه کم‌حجم‌تری را ترجیح می‌دهید، می‌توانید محیط ویژوال استدیو کد، به همراه افزونه C#‎ را انتخاب کنید.

برای صرفه جویی در زمان، بهتر است بسته دات نت Coding Pack را دانلود و نصب کنید. با نصب این بسته، «ویژوال استودیو کد» (VSCode) به همراه افزونه‌های ضروری دات نت SDK را خواهید داشت. در غیر این صورت، می‌توانید ابزار‌های مورد نیاز را به صورت جداگانه، دانلود و نصب کنید.

اکنون، همه چیز برای Web Scraping با سی شارپ آماده است ولی برای اطمینان از اینکه دات نت را به درستی نصب کرده‌ایم، می‌بایست پنجره‌ی پاورشل را باز کرده و دستورات زیر را در آن اجرا کنیم.

1dotnet --list-sdks

در صورتی که مشکلی وجود نداشته باشد، شماره نسخه دات نت SDK که روی سیستم نصب شده است، در خروجی چاپ می‌شود (ما در اینجا ‎نسخه ۷٫۰٫۱۰۱ از دات نت ‎SDK‎ را برای وب اسکرپینگ با سی شارپ نصب کردیم).

 

در صورتی که بجای دستور بالا، پیغامی‌با محتوای زیر نمایش داده شد،

1'dotnet' is not recognized as an internal or external command error

نیاز است که سیستم را ریستارت و مراحل فوق را دوباره امتحان کنیم. در صورت مشاهده مجدد این خطا، بهتر است که دات نت از روی سیستم حذف و دوباره نصب شود.

راه اندازی پروژه سی شارپ

یک «اپلیکیشن کنسول» (Console Application) را در ویژوال استدیو ایجاد می‌کنیم. به این صورت که ابتدا، یک پوشه خالی به نام SimpleWebScraper ، برای پروژه‌ی Web Scraping با سی شارپ می‌سازیم.

1mkdir SimpleWebScraper

حالا، VSCode را باز می‌کنیم و پس از کلیک روی منوی File ،  گزینه Open Folder را انتخاب می‌کنیم (معادل کلید ترکیبی Ctrl+K Ctrl O).

ساخت پوشه برای راه اندازی پروژه web scraping با سی شارپ

در پنجره باز شده، پوشه SimpleWebScraper را انتخاب و صبر می‌کنیم تا ویژوال استدیو آن را باز کند. سپس با انتخاب گزینه Terminal  از منوی View   که در نوار منوی اصلی وجود دارد، پنجره Terminal را نیز به ویژوال استدیو اضافه می‌کنیم.

ورود به پنجره ترمینال در پروژه وب اسکریپینگ با سی شارپ

در پنجره Terminal ، دستور زیر را اجرا می‌کنیم:

1dotnet new console --framework net7.0

دستور بالا، یک پروژه کنسول ‎.NET 7.0 را راه‌اندازی می‌کند. به بیان دقیق‌تر، یک فایل پروژه‎ با فرمت ‎ .csproj و یک فایل C#‎ به نام Program.cs ایجاد می‌شود. حالا، کد زیر را با محتویات موجود در Program.cs ، جایگزین می‌کنیم.

1namespace SimpleWebScraper 
2{ 
3	class Program 
4	{ 
5		static void Main(string[] args) 
6		{ 
7			Console.WriteLine("Hello, World!"); 
8 
9			// scraping logic... 
10		} 
11	} 
12}

این کد، نمونه‌ای از یک اسکریپت ساده کنسول در سی شارپ است. توجه داشته باشیم که تابع Main() ، شامل منطق وب اِسکرِپینگ با سی شارپ خواهد بود. با دستور زیر ، می‌توانیم اسکریپت را اجرا کنیم:

1dotnet run

که باید خروجی زیر را چاپ کند:

"Hello, World!"

 

بسیار عالی، اسکریپت اولیه C#‎، همانطوری که انتظار می‌رفت بدون مشکل کار می‌کند و ما با خیال راحت می‌توانیم مقدمات یادگیری Web Scraping با سی شارپ را ادامه دهیم.

چگونه اطلاعات یک وب‌سایت را جمع آوری کنیم؟

در این قسمت، وب اسکرپینگ با سی شارپ را در قالب ساخت برنامه‌ای برای استخراج داده‌ها از وب‌سایت ScrapeMe یاد می‌گیریم. وب‌سایت ScrapeMe، فهرستی از عناصر الهام گرفته از شخصت کارتونی Pokemon را در قالب چندین صفحه به نمایش می‌گذارد. اسکریپت C#‎، به طور خودکار، داده مربوط به هر محصول را بازدید و استخراج می‌کند.

در تصویر زیر، نمایی از وب‌سایت ScrapeMe، نشان داده شده است.

نمایی از صفحه هدف در مثال وب اسکریپینگ در سی شارپ

 

حالا وقت آن رسیده که برخی از وابستگی‌ها را نصب و استخراج داده از وب را شروع کنیم.

گام اول: نصب کتابخانه Html Agility Pack و افزونه CSS Selector مربوط به آن

Html Agility Pack (که به اختصار HAP هم نامیده می‌شود)، یکی از کتابخانه‌های قدرتمند و منبع باز ‎.NET برای تجزیه اسناد HTML است. این کتابخانه که API منعطفی برای وب اِسکرِپینگ محسوب می‌شود، به ما اجازه می‌دهد تا صفحه HTML مورد نظر را دانلود و تجزیه کنیم. همچنین می‌توانیم عناصر HTML را انتخاب کرده و داده‌ها را از آن‌ها بیرون بکشیم. کتابخانه Html Agility Pack را از طریق برنامه مدیر بسته NuGet، با استفاده از دستور زیر نصب می‌کنیم.

1dotnet add package HtmlAgilityPack

با اینکه Html Agility Pack به طور ذاتی از XPath و XSLT پشتیبانی می‌کند، اما این‌ها روش‌های محبوبی برای انتخاب عناصر HTML از DOM محسوب نمی‌شوند. خوشبختانه، افزونه‌ای به نام CSS Selector وجود دارد که محبوبیت بیشتری دارد. این افزونه از طریق کتابخانه HtmlAgilityPack.CssSelectors   از NuGet قابل نصب است.

1dotnet add package HtmlAgilityPack.CssSelectors

با نصب این افزونه، HAP قادر خواهد بود تا سلکتورهای CSS را با روش‌های توسعه‌یافته‌ای درک کند. سلکتورهای CSS، اولین بخش از یک دستور CSS هستند و به مرورگر می‌گویند که کدام عناصر از HTML باید انتخاب شوند تا مقادیر ویژگی CSS که در داخل دستور تعیین کردیم، روی آن‌ها اعمال شوند.

خزنده وب در وب اسکرپینگ

حالا می‌بایست، کتابخانه Html Agility Pack را با افزودن خط زیر در ابتدای فایل Program.cs پروژه، به خزنده وب C#‎، وارد کنیم.

1using HtmlAgilityPack;

اگر تا اینجای کار، ویژوال استدیو خطایی را گزارش نکرد، یعنی کار به درستی پیش رفته است.

گام دوم: بارگیری صفحه وب هدف

منظور از «صفحه‌وب هدف» (Target Web Page)، صفحه‌ای است که قصد اِسکرِپینگ آن را داریم. با ایجاد شی‌ای از Html Agility Pack شروع می‌کنیم.

1var web = new HtmlWeb();

HtmlWeb  به ما امکان دسترسی به قابلیت‌های وب اِسکرِپینگ ارائه شده توسط HAP را می‌دهد. سپس از متد Load()  مربوط به HtmlWeb  ، برای دریافت HTML از URL استفاده می‌کنیم.

1// loading the target web page 
2var document = web.Load("https://scrapeme.live/shop/");

در پشت صحنه، HAP یک درخواست HTTP از نوع GET را به منظور دانلود صفحه وب و تجزیه محتوای HTML آن ارسال می‌کند. در صورت بروز خطا، یک HtmlAgilityPack.HtmlWebException و در صورتی که همه چیز همانطور که انتظار می‌رود کار کند، یک شی HtmlDocument HAP را ارائه می‌دهد. حالا آماده هستیم تا از HtmlDocument برای استخراج داده از عناصر HTML استفاده کنیم. اما پیش از آن، اجازه بدهید که کد صفحه هدف را به منظور تعریف یک راهبرد موثر برای انتخاب عناصر HTML بررسی کنیم.

گام سوم: بررسی صفحه هدف

صفحه مورد نظر را برررسی می‌کنیم تا ببینیم ساختار آن چگونه است. این کار را با تگ‌های HTML هدف (گره‌های مورد نظر) که عناصر محصول را تشکیل می‌دهند، شروع می‌کنیم. روی یکی از این تگ‌ها راست کلیک و با انتخاب گزینه Inspect به DevTools مرورگر، دسترسی پیدا می‌کنیم.

لازم به ذکر است که DevTools، بخشی از مرورگر است که ابزارها و امکاناتی را برای برنامه نویسان فراهم می‌کند.

بررسی کدهای صفحه هدف از طریق inspect

در اینجا، یک تگ li.product HTML را می‌بینید که متشکل از چهار مولفه زیر است:

  • URL محصول در تگ a
  • تصویر محصول در تگ img
  • نام محصول در تگ h2
  • قیمت محصول در تگ span با کلاس .price

در صورت بررسی سایر محصولات، خواهید دید که آن‌ها نیز از ساختار یکسانی پیروی می‌کنند. در حقیقت چیزی که تغییر می‌کند، مقادیر ذخیره شده در پشت عناصر HTML هستند و این یعنی می‌توانیم همه آن‌ها را با برنامه‌نویسی، Scrape کنیم. در ادامه آموزشِ Web Scraping با سی شارپ، چگونگی اِسکرِپ داده‌ها از این عناصر HTML محصول را با استفاده از ابزار HAP در C#‎، یاد می‌گیریم.

گام چهارم: استخراج داده از عناصر HTML

ما باید یک کلاس سفارشی C#‎ را برای ذخیره داده‌های Scrape شده تعریف کنیم. برای این منظور، یک کلاس PokemonProduct را به شرح زیر، در داخل Program برنامه خود می‌نویسیم:

1public class PokemonProduct 
2{ 
3	public string? Url { get; set; } 
4	public string? Image { get; set; } 
5	public string? Name { get; set; } 
6	public string? Price { get; set; } 
7}

کلاس فوق شامل فیلدهای Url ، Image ، Name و Price است. این‌ فیلدها، مواردی هستند که قصد Scrape کردن آن‌ها را از هر محصول داریم. حالا، فهرستی از PokemonProduct را در تابع Main() برنامه، مانند خط زیر مقداردهی می‌کنیم.

1var pokemonProducts = new List<PokemonProduct>();

عبارت فوق شامل، داده Scrape و ذخیره شده در «وهله‌های» (Instances) PokemonProduct است. حالا وقت آن فرا رسیده است تا با استفاده از HAP، فهرستی از همه عناصر HTML li.product را از DOM بیرون بِکشیم، شبیه به کد زیر:

1// selecting all HTML product elements from the current page 
2var productHTMLElements = document.DocumentNode.QuerySelectorAll("li.product");

متد QuerySelectorAll() ، این امکان را برایمان فراهم می‌کند تا گره‌های HTML را از DOM با استفاده از سلکتور CSS، بازیابی کنیم. در متد فوق، استراتژی سلکتور CSS li.product ، برای به دست آوردن تمام عناصر محصول اعمال شده است. به طور خاص، QuerySelectorAll() فهرستی از اشیای HtmlNode HAP را بر می‌گرداند.

این نکته حائز اهمیت است که متد QuerySelectorAll() به افزونه CSS Selector مربوط به HAP تعلق دارد. بنابراین نمی‌توانیم آن را روی رابط اصلی Html Agility Pack پیدا کنیم. از یک حلقه  foreach ، برای پیمایش روی لیست HTML و داده Scrape شده‌ هر محصول، استفاده می‌کنیم.

1// iterating over the list of product elements 
2foreach (var productHTMLElement in productHTMLElements) 
3{ 
4	// scraping the interesting data from the current HTML element 
5	var url = HtmlEntity.DeEntitize(productHTMLElement.QuerySelector("a").Attributes["href"].Value); 
6	var image = HtmlEntity.DeEntitize(productHTMLElement.QuerySelector("img").Attributes["src"].Value); 
7	var name = HtmlEntity.DeEntitize(productHTMLElement.QuerySelector("h2").InnerText); 
8	var price = HtmlEntity.DeEntitize(productHTMLElement.QuerySelector(".price").InnerText); 
9	// instancing a new PokemonProduct object 
10	var pokemonProduct = new PokemonProduct() { Url = url, Image = image, Name = name, Price = price }; 
11	// adding the object containing the scraped data to the list 
12	pokemonProducts.Add(pokemonProduct); 
13}

تا اینجای کار توانستیم منطق وب اسکرپینگ با سی شارپ را پیاده‌سازی کنیم. متد QuerySelector() ، سلکتور CSS را در گره‌های فرزند HtmlNode ، به‌منظور دریافت یکی از آن‌ها، اعمال می‌کند.

پس از آن، ما ویژگی HTML را از Attributes انتخاب می‌کنیم و داده آن را با استفاده از  Value بیرون می‌کشیم. هر مقدار را نیز با استفاده از HtmlEntity.DeEntitize() برای جایگزینی با موجودیت‌های شناخته شده HTML، پوشش می‌دهیم. بهتر است دوباره یادآوری شود که QuerySelector() ، متعلق به افزونه CSS Selector است و در حالت عادی نمی‌توانیم آن را در HAP بیابیم. اکنون زمان آن رسیده است که یاد بگیریم که چگونه داده‌های اِسکرِپ شده را در قالبی خوانا، مانند CSV ذخیره کنیم.

گام پنجم: صدور داده‌های اِسکرِپ شده در قالب CSV

ما می‌توانیم داده‌های اِسکرِپ شده را به وسیله توابع داخلی C#‎ به قالب CSV تبدیل کنیم اما کتابخانه‌ CsvHelper، انتخاب مناسب‌تری برای این کار است.

خوب است که بدانیم، قالب CSV، به ما اجازه می‌دهد تا داده‌ها را در قالبی جدول مانند، ذخیره کنیم. CsvHelper کتابخانه‌ای سریع، منعطف و قابل اطمینان از دات نت است که برای خواندن و نوشتن فایل‌های CSV مورد استفاده قرار می‌گیرد. برای نصب این کتابخانه، کافی است بسته ناگت CsvHelper را با دستور زیر به وابستگی‌های پروژه خود اضافه کنیم:

1dotnet add package CsvHelper

با افزودن خط زیر به ابتدای فایل Program.cs ، این کتابخانه را به پروژه خود اضافه می‌کنیم:

1using CsvHelper;

همانطور که در زیر مشاهده می‌شود، داده‌های به دست آمده را به کمک CSVHelper، به یک فایل خروجی CSV تبدیل می‌کنیم:

1// initializing the CSV output file 
2using (var writer = new StreamWriter("pokemon-products.csv")) 
3// initializing the CSV writer 
4using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture)) 
5{ 
6	// populating the CSV file 
7	csv.WriteRecords(pokemonProducts); 
8}

در ابتدا، فایل pokemon-products.csv ایجاد می‌شود. پس از آن، متد WriteRecords() ، تمام رکوردهای محصول را در فایل CSV می‌نویسد. به لطف ویژگی using در سی شارپ، این اسکریپت به طور خوکار منابع مربوط به اشیا نوشتن را، آزاد می‌کند. توجه داشته باشید که «سازنده» (Constructor) به یک پارامتر CultureInfo نیاز دارد. این پارامتر، مشخصات قالب بندی، کاراکترهای جداکننده و پایانِ خط را تعیین می‌کند. InvariantCulture تضمین می‌کند که همه نرم‌افزارها می‌توانند CSV تولید شده را بدون در نظر گرفتن تنظیمات محلی کاربر، تجزیه کنند.

برای استفاده از مقادیر CultureInfo ، نیاز است که دستور زیر را نیز اضافه کنیم.

1using System.Globalization;

بسیار عالی. تنها چیزی که باقی می‌ماند، اجرای وب اِسکرِپری است که با سی شارپ نوشتیم.

گام ششم: راه‌اندازی اِسکرِپر

محتوای فایل Program.cs ، در وب اِسکرِپری که تا کنون نوشتیم به صورت زیر است:

1using HtmlAgilityPack; 
2using CsvHelper; 
3using System.Globalization; 
4 
5namespace SimpleWebScraper 
6{ 
7	public class Program 
8	{ 
9		// defining a custom class to store the scraped data 
10		public class PokemonProduct 
11		{ 
12			public string? Url { get; set; } 
13			public string? Image { get; set; } 
14			public string? Name { get; set; } 
15			public string? Price { get; set; } 
16		} 
17 
18		public static void Main() 
19		{ 
20			// creating the list that will keep the scraped data 
21			var pokemonProducts = new List<PokemonProduct>(); 
22 
23			// creating the HAP object 
24			var web = new HtmlWeb(); 
25 
26			// visiting the target web page 
27			var document = web.Load("https://scrapeme.live/shop/"); 
28 
29			// getting the list of HTML product nodes 
30			var productHTMLElements = document.DocumentNode.QuerySelectorAll("li.product"); 
31			// iterating over the list of product HTML elements 
32			foreach (var productHTMLElement in productHTMLElements) 
33			{ 
34				// scraping logic 
35				var url = HtmlEntity.DeEntitize(productHTMLElement.QuerySelector("a").Attributes["href"].Value); 
36				var image = HtmlEntity.DeEntitize(productHTMLElement.QuerySelector("img").Attributes["src"].Value); 
37				var name = HtmlEntity.DeEntitize(productHTMLElement.QuerySelector("h2").InnerText); 
38				var price = HtmlEntity.DeEntitize(productHTMLElement.QuerySelector(".price").InnerText); 
39 
40				var pokemonProduct = new PokemonProduct() { Url = url, Image = image, Name = name, Price = price }; 
41				pokemonProducts.Add(pokemonProduct); 
42			} 
43 
44			// crating the CSV output file 
45			using (var writer = new StreamWriter("pokemon-products.csv")) 
46			using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture)) 
47			{ 
48				// populating the CSV file 
49				csv.WriteRecords(pokemonProducts); 
50			} 
51		} 
52	} 
53}

با دستور زیر، اسکریپت را اجرا می‌کنیم:

1dotnet run

بسته به زمان پاسخگویی سرور صفحه مورد نظر، ممکن است کمی‌طول بکشد. پس از پایان این فرایند، می‌توانیم فایل pokemon-products.csv   را در پوشه اصلی پروژه C#‎ خود، پیدا کنیم. برای بررسی داده‌ها، آن را باز کنید.

فایل csv موارد Scrape شده در مثال وب اسکریپینگ با سی شارپ

همانطور که دیدیم، با نوشتن حدود 50 خط کُد توانستیم پروژه وب اسکرپینگ با سی شارپ را به طور کاملا کاربردی ایجاد کنیم.

وب اسکرپینگ پیشرفته در سی شارپ

Web Scraping با سی شارپ، فراتر از اصولی است که تاکنون دیدیم. در ادامه، تکنیک‌های پیشرفته‌تری را یاد خواهیم گرفت تا به ما برای تبدیل شدن به یک متخصص وب اسکرپینگ با سی شارپ، کمک کند.

Web Crawling با دات نت

فراموش نکنیم که وب‌سایت ScrapeMe، لیستی «صفحه‌بندی شده» (Pagination) از محصولات را نشان می‌دهد، به این معنی که وب‌سایت هدف، از چندین صفحه وب تشکیل شده است. برای اِسکرِپینگ همه محصولات، باید کل وب‌سایت بازدید شود، این همان چیزی است که «خزیدن در وب» (Web Crawling) به آن اشاره دارد.

برای انجام Web Crawling در سی شارپ، باید تمام لینک‌های صفحه‌بندی را دنبال کنیم. عنصر HTML مربوط به صفحه‌بندی را بررسی می‌کنیم با این هدف که بفهمیم چگونه URL صفحات باید استخراج شوند. با راست کلیک روی شماره صفحه، گزینه Inspect را انتخاب می‌کنیم.

Web Crawling با دات نت

صفحه‌ای مشابه تصویر زیر در DevTools مرورگر، مشاهده می‌شود.

ابزار DevTools در مرورگر برای برنامه نویسان

در اینجا، باید توجه داشت که تمام عناصر HTML مربوط به صفحه‌بندی، کلاسِ CSS page-numbers (شماره صفحه) را به اشتراک می‌گذارند. به طور دقیق تر، فقط گره‌های HTML شامل URL هستند، در حالی که عناصر span ، «نگه‌دارنده مکان» (Palceholder) محسوب می‌شوند. بنابراین، می‌توانیم تمام عناصر صفحه بندی را با a.page-numbers سلکتور CSS، انتخاب کنیم.

 

برای جلوگیری از اِسکرِپینگ مجدد یک صفحه، به چند ساختار داده اضافی نیاز داریم:

  • pagesDiscovered : لیستی که URLهای پیدا شده به وسیله Crawler را نگه می‌دارد.
  • pagesToScrape : صفی، شامل لیستی از صفحات، که برنامه Crawler به زودی قرار است آن‌ها اِسکرِپ کند.

همچنین به یک متغیر limit ، که مانع از خزیدن همیشگی برنامه Crawler در صفحات می‌شود، نیاز داریم.

1// the URL of the first pagination web page 
2var firstPageToScrape = "https://scrapeme.live/shop/page/1/"; 
3 
4// the list of pages discovered during the crawling task 
5var pagesDiscovered = new List<string> { firstPageToScrape }; 
6 
7// the list of pages that remains to be scraped 
8var pagesToScrape = new Queue<string>(); 
9 
10// initializing the list with firstPageToScrape 
11pagesToScrape.Enqueue(firstPageToScrape); 
12 
13// current crawling iteration 
14int i = 1; 
15 
16// the maximum number of pages to scrape before stopping 
17int limit = 5; 
18 
19// until there are no pages to scrape or limit is hit 
20while (pagesToScrape.Count != 0 && i < limit) 
21{ 
22	// extracting the current page to scrape from the queue 
23	var currentPage = pagesToScrape.Dequeue(); 
24 
25	// loading the page 
26	var currentDocument = web.Load(currentPage); 
27 
28	// selecting the list of pagination HTML elements 
29	var paginationHTMLElements = currentDocument.DocumentNode.QuerySelectorAll("a.page-numbers"); 
30 
31	// to avoid visiting a page twice 
32	foreach (var paginationHTMLElement in paginationHTMLElements) 
33	{ 
34		// extracting the current pagination URL 
35		var newPaginationLink = paginationHTMLElement.Attributes["href"].Value; 
36 
37		// if the page discovered is new 
38		if (!pagesDiscovered.Contains(newPaginationLink)) 
39		{ 
40			// if the page discovered needs to be scraped 
41			if (!pagesToScrape.Contains(newPaginationLink)) 
42			{ 
43				pagesToScrape.Enqueue(newPaginationLink); 
44			} 
45			pagesDiscovered.Add(newPaginationLink); 
46		} 
47	} 
48 
49	// scraping logic... 
50	 
51	// incrementing the crawling counter 
52	i++; 
53}

کارهایی که «خزنده» (Crawler) فوق، انجام می‌دهد، به شرح زیر است:

  1. از اولین صفحه در لیست صفحه‌بندی شروع می‌کند.
  2. در صفحه جاری، به دنبال URL‌-های صفحه‌بندی جدید می‌گردد.
  3. URLهای کشف شده را به صف اِسکرِپینگ اضافه می‌کند.
  4. داده‌ها را از صفحه جاری اِسکرِپ می‌کند.
  5. چهار مرحله قبلی را برای هر صفحه موجود در صف، تکرار می‌کند. این تکرار تا زمانی ادامه می‌یابد که، یا عناصر وجود در صف تمام شوند (صف خالی شود) یا اینکه به اندازه محدودیت تعیین شده در limit ، از صفحات بازدید کرده باشد.

از آنجایی که وب‌سایت ScrapeMe از ۴۸ صفحه تشکیل شده است، برای اِسکرِپینگ داده‌ها از همه محصولات، limit را روی ۴۸ تنظیم می‌کنیم. در این صورت، pokemon-product.csv ، به ازای هر یک از ۷۵۵ محصول موجود در وب‌سایت، رکوردی جداگانه خواهد داشت. تا اینجای کار یک برنامه وب اسکرپینگ با سی شارپ ساخته‌ایم که می‌تواند یک وب‌سایت را بطور کامل Scrape کند.

پرهیز از بلاک شدن

ممکن است برنامه‌ای که برای Web Scraping با سی شارپ نوشتیم، از کار بیفتد. این اتفاق به دلیل وجود چندین مکانیسم ضد اِسکرِپینگی است که ممکن است وب‌سایت‌ها اتخاذ کنند. تکنیک‌های ضد Scraping زیادی وجود دارند که اسکریپت ما برای مقابله با آن‌ها باید آماده باشد.

ابتدایی‌ترین تکنیک، این است که درخواست‌های HTTP را بر اساس مقدار «سرآمد» (Headers) آن‌ها مسدود کنیم. این معمولاً زمانی اتفاق می‌افتد که درخواست‌ها از مقدار User-Agent نامعتبر استفاده می‌کنند.

سرآمد User-Agent ، حاوی اطلاعاتی است که منشأ درخواست را مشخص می‌کنند. به طور معمول، موارد قابل قبول و معتبر، به مرورگرها و سیستم عامل‌های رایج اشاره می‌کنند. کتابخانه‌های اِسکرِپینگ تمایل دارند تا از placeholder-هایی از User-Agent استفاده کنند که می‌توانند به راحتی برنامه Scraper ما را آشکار کنند. می‌توانیم یک User-Agent معتبر را در Html Agility Pack با خط زیر به صورت سراسری ایجاد کنیم.

1// setting a global User-Agent header in HAP 
2web.UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36";

حالا، اینطور به نظر می‌رسد که تمام درخواست‌های HTTP، که به وسیله HAP انجام شده است، از کروم ۱۰۹ می‌آیند.

وب اسکرپینگ موازی با سی شارپ

کارایی Web Scraping با سی شارپ، به سرعت وب سرورِ مورد نظر (وب سرور صفحات هدفی که قصد اسکرپ آن را داریم) بستگی دارد. با ایجاد درخواست‌های موازی و اِسکرِپینگ صفحات به طور همزمان، با این مشکل مقابله می‌کنیم. همچنین ضمن پرهیز از اتلاف وقت، سرعت Scraper خود را به سطح بالاتری بهبود می‌دهیم. این همان مفهومی‌ است که موازی‌سازی وب اسکرپینگ با سی شارپ، بیان می‌کند. برای این کار، لیست تمام صفحاتی که Crawler سی شارپی ما باید از آن بازدید کند را در یک ConcurrentBag: ذخیره می‌کنیم:

1var pagesToScrape = new ConcurrentBag<string> { 
2	"https://scrapeme.live/shop/page/1/", 
3	"https://scrapeme.live/shop/page/2/", 
4	"https://scrapeme.live/shop/page/3/", 
5	// ... 
6	"https://scrapeme.live/shop/page/47/", 
7	"https://scrapeme.live/shop/page/48/" 
8};

List در سی شارپ، Thread-Safe نیست و زمانی که صحبت از کارهای موازی می‌شود، نباید از آن استفاده کنیم. در این مواقع، List را با ConcurrentBag ، که جایگزینی Thread-Safe و «نامرتب» (non-Order) برای آن است، تعویض می‌کنیم. Thread-Safe بودن قطعه کد، به این معنی است که نتایج حاصل، به دلیل تعامل همزمان چندین «رشته» (Thread) با کدها، اثرات نامطلوب (داده‌های ناسازگار، استثنا و غیره) ایجاد نمی‌کنند. به همین دلیل، pokemonProducts   را به ConcurrentBag   تبدیل می‌کنیم:

1var pokemonProducts = new ConcurrentBag<PokemonProduct>();

بیایید Web Scraping موازی را پیاده‌سازی کنیم. از Parallel.forEach() برای اجرای یک حلقه foreach به صورت موازی در سی شارپ و همینطور Scraping چندین صفحه به طور همزمان، استفاده می‌کنیم:

1// the import statement required to use Parallel.forEach() 
2using System.Collections.Concurrent; 
3 
4// ... 
5 
6Parallel.ForEach( 
7	pagesToScrape, 
8	// limiting the parallelization level to 4 pages at a time 
9	new ParallelOptions { MaxDegreeOfParallelism = 4 }, 
10	currentPage => { 
11		// visiting the current page of the loop 
12		var currentDocument = web.Load(currentPage); 
13	 
14		// complete scrapping logic 
15		var productHTMLElements = currentDocument.DocumentNode.QuerySelectorAll("li.product"); 
16		foreach (var productHTMLElement in productHTMLElements) 
17		{ 
18			var url = HtmlEntity.DeEntitize(productHTMLElement.QuerySelector("a").Attributes["href"].Value); 
19			var image = HtmlEntity.DeEntitize(productHTMLElement.QuerySelector("img").Attributes["src"].Value); 
20			var name = HtmlEntity.DeEntitize(productHTMLElement.QuerySelector("h2").InnerText); 
21			var price = HtmlEntity.DeEntitize(productHTMLElement.QuerySelector(".price").InnerText); 
22	 
23			var pokemonProduct = new PokemonProduct() { Url = url, Image = image, Name = name, Price = price }; 
24	 
25			// storing the scraped product data in parallel 
26			pokemonProducts.Add(pokemonProduct); 
27		} 
28	} 
29);

اکنون، برنامه‌ای که برای وب اِسکرِپینگ با سی شارپ نوشتیم، بسیار سریع‌تر شده است. اما فراموش نکنیم که سطح موازی‌سازی را برای پرهیز از فشار زیاد به سرور، محدود کنیم. زیرا هدف ما استخراج داده‌ها از وب‌سایت و نه انجام یک حمله DoS است. کدهای بالا به عنوان مثالی برای درک چگونگی دستیابی به «Crawling موازی» در سی شارپ بودند. تمام کدهای برنامه Scraping موازی که با سی شارپ نوشتیم را در زیر مشاهده می‌کنید.

1using HtmlAgilityPack; 
2using CsvHelper; 
3using System.Globalization; 
4using System.Collections.Concurrent; 
5 
6namespace SimpleWebScraper 
7{ 
8	public class Program 
9	{ 
10		public class PokemonProduct 
11		{ 
12			public string? Url { get; set; } 
13			public string? Image { get; set; } 
14			public string? Name { get; set; } 
15			public string? Price { get; set; } 
16		} 
17 
18		public static void Main() 
19		{ 
20			// initializing HAP 
21			var web = new HtmlWeb(); 
22		 
23			// this can't be a List because it's not thread-safe 
24			var pokemonProducts = new ConcurrentBag<PokemonProduct>(); 
25		 
26			// the complete list of pages to scrape 
27			var pagesToScrape = new ConcurrentBag<string> { 
28				"https://scrapeme.live/shop/page/1/", 
29				"https://scrapeme.live/shop/page/2/", 
30				// ... 
31				"https://scrapeme.live/shop/page/48/" 
32			}; 
33 
34			// performing parallel web scraping 
35			Parallel.ForEach( 
36				pagesToScrape, 
37				new ParallelOptions { MaxDegreeOfParallelism = 4 }, 
38				currentPage => 
39				{ 
40					var currentDocument = web.Load(currentPage); 
41 
42					var productHTMLElements = currentDocument.DocumentNode.QuerySelectorAll("li.product"); 
43					foreach (var productHTMLElement in productHTMLElements) 
44					{ 
45						var url = HtmlEntity.DeEntitize(productHTMLElement.QuerySelector("a").Attributes["href"].Value); 
46						var image = HtmlEntity.DeEntitize(productHTMLElement.QuerySelector("img").Attributes["src"].Value); 
47						var name = HtmlEntity.DeEntitize(productHTMLElement.QuerySelector("h2").InnerText); 
48						var price = HtmlEntity.DeEntitize(productHTMLElement.QuerySelector(".price").InnerText); 
49 
50						var pokemonProduct = new PokemonProduct() { Url = url, Image = image, Name = name, Price = price }; 
51 
52						pokemonProducts.Add(pokemonProduct); 
53					} 
54				} 
55			); 
56 
57			// exporting to CSV 
58			using (var writer = new StreamWriter("pokemon-products.csv")) 
59			using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture)) 
60			{ 
61				csv.WriteRecords(pokemonProducts); 
62			} 
63		} 
64	} 
65}

Scraping وبسایت داینامیک با استفاده از مرورگر هِدلِس در سی شارپ

سایت‌هایی که محتوای استاتیک دارند، تمام محتوای خود را در صفحاتی از HTML جای داده‌اند که توسط سرور بازگردانده شده‌است. این موضوع باعث می‌شود که سایت‌های مذکور، به یک هدفِ آسان برای اِسکرِیپینگ، به‌وسیله هر کتابخانه تجزیه HTML، تبدیل شوند.

وب‌سایت‌های پویا، از زبان جاوا اسکریپت برای رِندر یا بازیابی داده‌ها استفاده می‌کنند. دلیل آن این است که این نوع وب‌سایت‌ها برای بازیابی داینامیکِ تمام یا بخشی از محتوا به جاوا اسکریپت متکی هستند. اِسکرِپینگ چنین وب‌سایت‌هایی نیازمند ابزاری است که بتواند جاوا اسکریپت را مانند یک «مرورگر هِدلِس یا بی‌سر» (Headless Browser) اجرا کند.

اگر با این اصطلاح آشنا نیستید، باید بگوییم که مرورگر هِدلِس، مرورگری قابل برنامه‌نویسی و بدون «رابط کاربری گرافیکی» (GUI) است. پُر استفاده‌ترین کتابخانه برای مرورگر هِدلِس در سی شارپ، با بیش از 65 میلیون دانلود، «سلنیوم» (Selenium) نام دارد. برای استفاده از آن، بسته ناگت Selenium.WebDriver را طبق دستور زیر نصب می‌کنیم:

1dotnet add package Selenium.WebDriver

از سلنیوم در حالت هِدلِس برای اِسکرِپینگ داده‌ها از وب‌سایت ScrapeMe، با منطق زیر استفاده می‌کنیم:

1using CsvHelper; 
2using System.Globalization; 
3using OpenQA.Selenium; 
4using OpenQA.Selenium.Chrome; 
5 
6namespace SimpleWebScraper 
7{ 
8	public class Program 
9	{ 
10		public class PokemonProduct 
11		{ 
12			public string? Url { get; set; } 
13			public string? Image { get; set; } 
14			public string? Name { get; set; } 
15			public string? Price { get; set; } 
16		} 
17 
18		public static void Main() 
19		{ 
20			var pokemonProducts = new List<PokemonProduct>(); 
21 
22			// to open Chrome in headless mode 
23			var chromeOptions = new ChromeOptions(); 
24			chromeOptions.AddArguments("headless"); 
25 
26			// starting a Selenium instance 
27			using (var driver = new ChromeDriver(chromeOptions)) 
28			{ 
29				// navigating to the target page in the browser 
30				driver.Navigate().GoToUrl("https://scrapeme.live/shop/"); 
31 
32				// getting the HTML product elements 
33				var productHTMLElements = driver.FindElements(By.CssSelector("li.product")); 
34				// iterating over them to scrape the data of interest 
35				foreach (var productHTMLElement in productHTMLElements) 
36				{ 
37					// scraping logic 
38					var url = productHTMLElement.FindElement(By.CssSelector("a")).GetAttribute("href"); 
39					var image = productHTMLElement.FindElement(By.CssSelector("img")).GetAttribute("src"); 
40					var name = productHTMLElement.FindElement(By.CssSelector("h2")).Text; 
41					var price = productHTMLElement.FindElement(By.CssSelector(".price")).Text; 
42 
43					var pokemonProduct = new PokemonProduct() { Url = url, Image = image, Name = name, Price = price }; 
44 
45					pokemonProducts.Add(pokemonProduct); 
46				} 
47			} 
48 
49			// export logic 
50			using (var writer = new StreamWriter("pokemon-products.csv")) 
51			using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture)) 
52			{ 
53				csv.WriteRecords(pokemonProducts); 
54			} 
55		} 
56	} 
57}

تابع FindElements() سلنیوم، به مرورگر، این امکان را می‌دهد تا گره‌های HTML را جستجو کند. به لطف وجود این تابع، می‌توانیم عناصر HTML محصول را از طریق پرس و جوی سلکتورِ CSS، انتخاب و پس از آن، عملیات پیمایش را روی آن‌ها با یک حلقه foreach انجام دهیم. سپس متد GetAttribute() را اِعمال و از Text برای استخراج داده‌های مورد نظر استفاده می‌کنیم.

Web Scraping با سی شارپ، چه از طریق HAP انجام و چه با سلنیوم پیاده‌سازی شود، کدنویسی تقریباً یکسانی دارد و تفاوت آن، در نحوه اجرای منطق اِسکرِپینگ است. HAP، صفحات HTML را به منظور استخراج داده‌ها از آن تجزیه می‌کند و سلنیوم دستورات اِسکرِپینگ را در یک مرورگر هِدلِس اجرا می‌کند.

کتابخانه های مورد استفاده در وب اسکرپینگ

به لطف وجود سلنیوم، می‌توانیم وب‌سایت‌هایی با محتوای پویا را Crawl کنیم و مانند یک کاربر واقعی در مرورگر، با صفحات وب، تعامل داشته باشیم. همچنین کُد ما احتمالاً به عنوان یک ربات شناسایی می‌شود. در نتیجه، با استفاده از سلنیوم، Scraping صفحه وب با پرهیز از انسداد، آسان‌تر می‌شود.

بسته Html Agility Pack، تمامی‌قابلیت‌های مرورگر را به همراه ندارد، بنابراین، از HAP فقط می‌توانیم به منظور اِسکرِیپینگِ وب‌سایت‌های ایستا استفاده کنیم. همچنین مانند سلنیوم، سربار اضافی منابع، برای اجرای یک مرورگر معمولی را به همراه ندارد.

کد نهایی Web Scraping با سی شارپ

در این بخش، کد کامل Web Scraping با سی شارپ، به همراه Crawling و منطق ضدبلاک اولیه، که با استفاده از بسته Html Agility Pack ساختیم، ارائه شده است.

1using HtmlAgilityPack; 
2using System.Globalization; 
3using CsvHelper; 
4using System.Collections.Concurrent; 
5namespace SimpleWebScraper 
6{ 
7	public class Program 
8	{ 
9		// defining a custom class to store 
10		// the scraped data 
11		public class PokemonProduct 
12		{ 
13			public string? Url { get; set; } 
14			public string? Image { get; set; } 
15			public string? Name { get; set; } 
16			public string? Price { get; set; } 
17		} 
18		public static void Main() 
19		{ 
20			// initializing HAP 
21			var web = new HtmlWeb(); 
22			// setting a global User-Agent header 
23			web.UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36"; 
24			// creating the list that will keep the scraped data 
25 
26			var pokemonProducts = new List<PokemonProduct>(); 
27			// the URL of the first pagination web page 
28			var firstPageToScrape = "https://scrapeme.live/shop/page/1/"; 
29			// the list of pages discovered during the crawling task 
30			var pagesDiscovered = new List<string> { firstPageToScrape }; 
31			// the list of pages that remains to be scraped 
32			var pagesToScrape = new Queue<string>(); 
33			// initializing the list with firstPageToScrape 
34			pagesToScrape.Enqueue(firstPageToScrape); 
35			// current crawling iteration 
36			int i = 1; 
37			// the maximum number of pages to scrape before stopping 
38			int limit = 5; 
39			// until there is a page to scrape or limit is hit 
40			while (pagesToScrape.Count != 0 && i < limit) 
41			{ 
42				// getting the current page to scrape from the queue 
43				var currentPage = pagesToScrape.Dequeue(); 
44				// loading the page 
45				var currentDocument = web.Load(currentPage); 
46				// selecting the list of pagination HTML elements 
47				var paginationHTMLElements = currentDocument.DocumentNode.QuerySelectorAll("a.page-numbers"); 
48				// to avoid visiting a page twice 
49				foreach (var paginationHTMLElement in paginationHTMLElements) 
50				{ 
51					// extracting the current pagination URL 
52					var newPaginationLink = paginationHTMLElement.Attributes["href"].Value; 
53					// if the page discovered is new 
54					if (!pagesDiscovered.Contains(newPaginationLink)) 
55					{ 
56						// if the page discovered needs to be scraped 
57						if (!pagesToScrape.Contains(newPaginationLink)) 
58						{ 
59							pagesToScrape.Enqueue(newPaginationLink); 
60						} 
61						pagesDiscovered.Add(newPaginationLink); 
62					} 
63				} 
64				// getting the list of HTML product nodes 
65				var productHTMLElements = currentDocument.DocumentNode.QuerySelectorAll("li.product"); 
66				// iterating over the list of product HTML elements 
67				foreach (var productHTMLElement in productHTMLElements) 
68				{ 
69					// scraping logic 
70					var url = HtmlEntity.DeEntitize(productHTMLElement.QuerySelector("a").Attributes["href"].Value); 
71					var image = HtmlEntity.DeEntitize(productHTMLElement.QuerySelector("img").Attributes["src"].Value); 
72					var name = HtmlEntity.DeEntitize(productHTMLElement.QuerySelector("h2").InnerText); 
73					var price = HtmlEntity.DeEntitize(productHTMLElement.QuerySelector(".price").InnerText); 
74					var pokemonProduct = new PokemonProduct() { Url = url, Image = image, Name = name, Price = price }; 
75					pokemonProducts.Add(pokemonProduct); 
76				} 
77				// incrementing the crawling counter 
78				i++; 
79			} 
80			// opening the CSV stream reader 
81			using (var writer = new StreamWriter("pokemon-products.csv")) 
82			using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture)) 
83			{ 
84				// populating the CSV file 
85				csv.WriteRecords(pokemonProducts); 
86			} 
87		} 
88	} 
89}

در نتیجه، با نوشتن کمتر از 100 خط کد توانستیم، برنامه Web Scraping با سی شارپ را پیاده‌سازی کنیم

سایر کتابخانه های وب اسکرپینگ با سی شارپ کدامند؟

در این بخش، ابزارهای دیگری که در Web Scraping با سی شارپ می‌توانند مورد استفاده قرار بگیرند، به شرح زیر معرفی شده است:

  • ZenRows: یک API با امکانات فراوان و قابلیت استفاده آسان برای تسهیل فرایند استخراج داده‌ها از صفحات وب است. ZenRows میانبُری خودکار برای هر سیستم ضد ربات یا ضد اِسکرِپینگ فراهم می‌کند. علاوه بر این، به همراه پراکسی‌، مرورگر هِدلِس کاربردی و تضمین آپ‌تایم ۹۹ درصدی ارائه می‌شود.
  • Puppeteer Sharp: کتابخانه الهام گرفته شده دات نت از Puppeteer در Node.js است. با استفاده از آن، می‌توانیم یک مرورگر کرومیوم هِدلِس را به منظور تست و اِسکرِپینگ هدایت کنیم.
  • AngleSharp: کتابخانه اپن سورسی از دات نت، با هدف تجزیه و دستکاری اسناد XML و HTML است. این کتابخانه به ما امکان می‌دهد تا داده‌ها را از یک وب‌سایت استخراج و عناصر HTML را از طریق سلکتورهای CSS، انتخاب کنیم.
  • HttpClient: محبوب‌ترین کلاینت HTTP سی شارپ است و در زمینه وب اسکرپینگ نیز کاربرد دارد. زیرا به شما امکان می‌دهد درخواست‌های HTTP را به راحتی و به صورت «ناهمزمان» (Asynchronously) انجام دهید.
معرفی کتابخانه های وب اسکریپینگ با سی شارپ

جمع‌بندی

در این نوشتار، اطلاعات مربوط به یادگیری وب اسکرپینگ با سی شارپ تا حد زیادی پوشش و آموزش داده شد. ابتدا اصول و مفاهیم اولیه Web Scraping را یاد گرفتیم، سپس کار را با پیاده‌سازی مفاهیم پیشرفته Web Scraping با سی شارپ ادامه دادیم.

به طور خلاصه، اکنون می‌دانیم:

  • چگونه با استفاده از بسته Html Agility Pack، اِسکرِپینگ مقدماتی وب را در سی شارپ انجام دهیم.
  • چگونه کل یک وب‌سایت را از طریق خزیدن در وب Scrape کنیم.
  • در مواقع مورد نیاز، از راه‌حلی که مرورگر هِدلِس سی شارپ ارائه می‌دهد استفاده کنیم.
  • چگونه داده‌های وب‌سایت‌ پویا را با استفاده از سلنیوم استخراج کنیم.

Web Scraping با سی شارپ، چالشی نسبتاً بزرگ به حساب می‌آید. زیرا در حال حاضر، وب‌سایت‌ها از فناوری‌های ضد Scraping زیادی استفاده می‌کنند. دور زدن همه آن‌ها کار آسانی نیست و ما همیشه باید به دنبال راه حلی برای این چالش باشیم. در این مسیر می‌توانیم از APIهای موجود نیز، استفاده کنیم.

سوالات متداول Web Scraping با سی شارپ

در این بخش به تعدادی از پرسش‌های رایج پیرامون وب اسکریپینگ در سی شارپ پاسخ داده شده است.

آیا زبان سی شارپ برای وب اسکرپینگ گزینه مناسبی است؟

بله، سی شارپ یک زبان برنامه‌نویسی همه منظوره است که شما را قادر می‌سازد تا فرایند وب اسکرپینگ را در حد خیلی خوبی انجام دهید. سی شارپ دارای یک کامیونیتی بزرگ و فعال است که کتابخانه‌های زیادی را برای کمک به شما، در دستیابی به هدفی که از وب اسکرپینگ دارید، توسعه داده است.

وب اسکرپینگ با سی شارپ چگونه انجام می‌ شود؟

وب اسکرپینگ در سی شارپ، مانند سایر زبان‌های برنامه نویسی انجام می‌شود. با استفاده از یک کتابخانه سی شارپ مربوط به وب اسکرپینگ، می‌توانید به وب‌سایت مورد نظر متصل شوید، عناصر HTML را از DOM آن انتخاب و داده‌های آن را بازیابی کنید.

بهترین روش برای وب اسکرپینگ با سی شارپ چیست؟

استفاده از کتابخانه‌های موجود در NuGet برای Scraping در سی شارپ، همه چیز را آسان‌تر می‌کند. Selenium ،ScrapySharp و Html Agility Pack، برخی از محبوب‌ترین کتابخانه‌های سی شارپ برای استفاده در پروژه‌های اسکرپینگ داده‌ها محسوب می‌شوند.

با داده‌های Scrape شده چه باید کرد؟

پس از جمع‌آوری داده‌ها، با توجه به هدفی که در ذهن داریم، لازم است آن‌ها را در جایی نگهداری کنیم. در ادامه برخی از این موارد فهرست شده‌اند.

  • آن‌ها را می‌توان در پایگاه‌داده ذخیره کرد تا هر جایی که نیاز شد، با پرس و جو بازیابی شوند.
  • آن‌ها را به قالب JSON تبدیل کنیم و از آن برای فراخوانی برخی از APIها کمک بگیریم.
  • تبدیل داده‌های Scrape شده به فرمت‌های قابل خواندن برای افراد دیگر، در قالب‌هایی مانند CSV، که با مایکروسافت اکسل نیز قابل نمایش است.

این روش‌ها، فقط چندین نمونه رایج هستند. اما نکته مهم، این است که وقتی داده‌های Scrape شده را در کدهایتان دارید، می‌توانید آن‌ها را به هر نحوی که مایل بودید، استفاده کنید. به طور معمول، داده‌های Scrape شده به قالب مفیدتری برای بازاریابی، تجزیه و تحلیل داده‌ها یا تیم فروش شما تبدیل می‌شوند.

حریم خصوصی در Web Scraping با سی شارپ چگونه حفظ می‌شود؟

اگر می‌خواهید از مواردی همچون، افشای آدرس IP، مسدود شدن و افشای هویت خودتان جلوگیری کنید، پروکسی‌های وب اسکرپینگ، این کار را برای شما انجام می‌دهند. پروکسی سرور، به عنوان دروازه‌ای بین برنامه شما و سرور وب‌سایت مورد نظر عمل می‌کند و در نتیجه IP شما پنهان می‌شود. به این ترتیب، این سرویس به شما کمک می‌کند تا بر مشکل انسداد IP غلبه کنید و همچنین، داده‌ها را به صورت ناشناس Scrape و محتوای مورد نظر را در همه کشورها باز کنید. پروکسی‌ها انواع مختلفی دارند و در مقاصد متنوعی استفاده می‌شوند. بنابراین باید مطمئن شوید که پروکسی سرور مناسبی را انتخاب می‌کنید.

بر اساس رای ۴ نفر
آیا این مطلب برای شما مفید بود؟
اگر بازخوردی درباره این مطلب دارید یا پرسشی دارید که بدون پاسخ مانده است، آن را از طریق بخش نظرات مطرح کنید.
منابع:
brightdataZenRowsScrapingBeeimpervawikipediamozilla
نظر شما چیست؟

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *