- 28 Mar 2020
- 6,309
- 4,758
Giriş
Merhaba, bugünkü yazımda sizlere AngleSharp ile nasıl web kazıma yapılır onu anlatacağım.
Bu konuyu özellikle seçme sebeplerimden başında Türkiye'de bununla ilgili bir kaynak olmaması yer alıyor.
Bu alanda merakı olanların illa yabancı kaynaklara muhtaç olmasını istemiyorum. Bu yüzden elimden geldiğince detaylı anlatmaya çalışacağım.
Neyse çok uzatmadan konumuza geçelim, iyi okumalar dilerim!
Kullanım
Öncelikle işe bir proje dosyası oluşturmakla başlayalım.
Ben programın ismini "Web Kazıma Projesi" şeklinde koyuyorum, siz de kendinize göre isimlendirebilirsiniz.
Projemiz oluştuktan sonra gerekli kütüphanemizi eklememiz gerekiyor.
Bu işlem için sağ taraftaki "Çözüm Gezgini" kısmından projemizin üstüne sağ tık yapıyoruz ve çıkan kısımdan "NuGet Paketlerini Yönet..." diyoruz.
Açılan kısımdan "Gözat" kısmına tıklıyoruz ve arama kısmına "AngleSharp" yazıyoruz.
İlk çıkanı seçtikten sonra "Yükle" tuşuna basıyoruz.
Kütüphanemiz yüklendikten sonra
C#:
using AngleSharp;
using AngleSharp.Dom;
ile kodumuza dahil ediyoruz.
Kütüphanemizi kodumuza dahil ettikten sonraki işlem ise kazıma yapacağımız sitenin kaynak kodlarını çekmek olacak.
Ben kullanımı daha basit olsun ve anlaşılır olsun diye basit bir site tasarladım ve bunu localhostuma attım.
Bilmeyenler için şu konumdaki eklentinin site hali: Tarayıcılar için Sıfırdan Eklenti Oluşturma!
Sitenin Görünümü
Sizde bu örnek üzerinde işlemek isterseniz..
Sitenin Kaynak Kodları
HTML:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>THT Profiller</title>
</head>
<body>
<main>
<a href="https://www.turkhackteam.org/uye/rei-a.879110/">
<div class="uye">
<center>
<img class="profil_resmi" src="https://www.turkhackteam.org/data/avatars/l/879/879110.jpg?1661379848" alt="Reina">
<font color="#FF000E">
<h3 id="ust_duzey_yonetim" class="kullanici_adi">Reina</h3>
</font>
<p class="rutbe">Administrator</p>
</center>
</div>
</a>
<a href="https://www.turkhackteam.org/uye/grimner.892463/">
<div class="uye">
<center>
<img class="profil_resmi" src="https://www.turkhackteam.org/data/avatars/l/892/892463.jpg?1697033887" alt="Grimner">
<font color="#008000">
<h3 id="alt_duzey_yonetim" class="kullanici_adi">Grimner</h3>
</font>
<p class="rutbe">Deneyimli Moderatör</p>
</center>
</div>
</a>
<a href="https://www.turkhackteam.org/uye/ra.766994/">
<div class="uye">
<center>
<img class="profil_resmi" src="https://www.turkhackteam.org/data/avatars/l/766/766994.jpg?1702546219" alt="'Ra">
<font color="#008000">
<h3 id="alt_duzey_yonetim" class="kullanici_adi">'Ra</h3>
</font>
<p class="rutbe">Ticaret Kategorisi <br> Sorumlu Yrd.</p>
</center>
</div>
</a>
<a href="https://www.turkhackteam.org/uye/kruvazor.892346/">
<div class="uye">
<center>
<img class="profil_resmi" src="https://www.turkhackteam.org/data/avatars/l/892/892346.jpg?1702285052" alt="Kruvazör">
<font color="#84D2FF">
<h3 id="alt_duzey_yonetim" class="kullanici_adi">Kruvazör</h3>
</font>
<p class="rutbe">Global Moderatör</p>
</center>
</div>
</a>
<a href="https://www.turkhackteam.org/uye/pump.988625/">
<div class="uye">
<center>
<img class="profil_resmi" src="https://www.turkhackteam.org/data/avatars/l/988/988625.jpg?1701366802" alt="'pump">
<font color="#FFFFFFF">
<h3 id="normal_uye" class="kullanici_adi">'pump</h3>
</font>
<p class="rutbe">Uzman Üye</p>
</center>
</div>
</a>
<a href="https://www.turkhackteam.org/uye/teux.993846/">
<div class="uye">
<center>
<img class="profil_resmi" src="https://www.turkhackteam.org/data/avatars/l/993/993846.jpg?1701983064" alt="teux">
<font color="#FFFFFFF">
<h3 id="normal_uye" class="kullanici_adi">teux</h3>
</font>
<p class="rutbe">Katılımcı Üye</p>
</center>
</div>
</a>
</main>
<style>
main {
position: absolute;
left: 50%;
Top: 50%;
transform: translate(-50%, -50%);
margin-top: -100px;
width: 1200px;
height: 100px;
}
body {
margin: 0;
padding: 0;
background: url(https://i.hizliresim.com/g6aa7R.jpg);
background-size: cover;
background-position: center;
background-repeat: no-repeat;
height: 100vh;
}
.uye {
float: left;
width: 180px;
height: 250px;
background: yellowgreen;
background: rgba(0, 0, 0, 0.6);
border-radius: 5px;
margin: 10px;
}
.profil_resmi {
width: 150px;
height: 150px;
margin-top: 10px;
border-radius: 5px;
}
.kullanici_adi {
margin-top: 2px;
}
.rutbe {
color: white;
margin-top: -15px;
}
</style>
</body>
</html>
Evet, sitemiz belli olduğuna göre kaynak kodlarını çekmeye gelelim.
Bunun için kullanacağımız kod
C#:
string Url = "http://localhost/THTProfiller/";
// Kazıma yapacağımız sitenin adresi. Http olmasına dikkat yoksa hata veriyor..
HttpClient Client = new HttpClient();
// Burada bir http kullanıcısı oluşturuyoruz.
string Html = Client.GetStringAsync(Url).Result;
// Burada urlden dönen sonucu alıyoruz ki burası front end tarafın kaynak kodları oluyor.
Kaynak kodlarımızı çektiğimize göre yavaştan kazıma işlemlerine geçebiliriz.
Benim bu derste anlatacağım yapılar aşağıdaki sırayla olacak.
Başlık Kazıma
Yazı Kazıma
Link Adresi Kazıma
Resim Kaynağı Kazıma
Alt Etiketi Kazıma
Renk Kazıma
ID ve Class İşlemleri
ID ve Class Filtreleme
Çocuk (Child) İşlemleri
Ebebeyn (Parent) İşlemleri
Kardeş (Siblings) İşlemleri
Öncelikle kazıma işlemine başlamadan iki satır değişmeyecek kodlarımız var onları yazalım.
C#:
var Parser = new HtmlParser();
// Bu kodumuzu Html belgelerini ayrıştırmak için kullanıyoruz.
var Document = Parser.ParseDocument(Html);
// Buradaki değişkenimize ayrıştırdığımız html etiketlerini atıyoruz.
Evet, Html belgemizi ayrıştırdığımıza göre başlığımızı kazımakla devam edelim.
Bunun için iki farklı yolumuz mevcut birisi sadece başlığı çekmeye yararken diğerini tüm Html etiketleri için kullanabiliyoruz.
Öncelikle başlığa özel koda bakalım.
C#:
var Title = Document.Title;
Evet, bu yolumuzda Document'in içinden ayrıştırılmış başlığı direkt çektik.
Şimdi de tüm Html etiketlerinin içinden veri çekmemize ve daha çok kullanacağımız yönteme geçelim.
C#:
var Title = Document.QuerySelector("title").TextContent;
Bu yöntem de etiketi buluyor ve içindeki değeri ekrana yazdırıyor.
Başlık yazdırma işlemimiz kısaca bu kadardı.
Şimdi yazı etiketlerimizi yazdırmaya bakalım. Aslında bunda da mantık oldukça benzer.
Hatta değişen tek şey etiket ismi diyebiliriz.
Benim size verdiğim kodu incelediğimizde 2 farklı yazı etiketi görüyoruz. (a hariç..)
Bunlardan birisi başlık etiketi h3 birisi ise paragraf etiketi p.
Öncelikle ben h3 olan etiketin içindeki yazdırmak istiyorum diyelim.
Bunun için kullanmam gereken kod aşağıdaki gibi olacaktır.
C#:
var H3 = Document.QuerySelector("h3").TextContent;
Bu kodu ekrana yazdırmak için ise
C#:
Console.WriteLine(H3);
Bu arada buradaki TextContent kısmını illa değişkeni tanımlarken girmenize gerek yok.
C#:
var H3 = Document.QuerySelector("h3");
Console.WriteLine(H3.TextContent);
Şeklinde de kullanılabilir.
Evet, genel olarak etiket içindeki değerleri kazıma işlemi bu kadardı.
Şimdi ise programımızı çalıştıralım ve sonuca bakalım.
Gördüğünüz gibi program çalıştığında ekrana "Reina" yazısı geldi.
Peki neden Grimner, 'Ra veya 'pump değil de Reina?
Aslında bunun sebebi basit. Biz özel bir koşul belirtmedikçe, belirtilen etiket arasında ki ilkini seçer ve ekrana yazdırır.
ID ve Class kısmında filtreleme mantığını anlatınca daha iyi anlarsınız..
Peki sadece Reina yazdırmak yerine hepsini yazdırmak istersek ne yapacağız?
Bunun için kullandığımız kodda bir iki değişiklik yapmamız gerekmekte.
Mesela QuerySelector kısmını QuerySelectorAll şeklinde değiştirmek gibi.
Bu sayede artık ilk baştaki etiketi değil, tüm etiketleri almış olacağız.
Bu aldığımız etiketlerin tamamını ekrana yazdırmak için ise foreach döngüsü kullanabiliriz.
C#:
string Url = "http://localhost/THTProfiller/";
HttpClient Client = new HttpClient();
string Html = Client.GetStringAsync(Url).Result;
var Parser = new HtmlParser();
var Document = Parser.ParseDocument(Html);
var H3s = Document.QuerySelectorAll("h3");
foreach (var H3 in H3s)
{
Console.WriteLine(H3.TextContent);
}
Console.ReadKey();
Gördüğünüz gibi h3 etiketlerimizin içindeki tüm değerler ekrana yazdırıldı.
Bu işlemin aynısını <p> etiketi içinde yapabilirsiniz, ben şu an konu da aşırı resim kalabalığı olmasın diye her birini tek tek göstermeyeceğim.
Her birini görmek isterseniz yazının sonundaki videolu kaynağa bakabilirsiniz.
(Video küçük bir sıkıntıdan dolayı sonradan eklenecek..)
Yazı kazıma işlemimiz bittiğine göre şimdi diğer bir işlemimiz olan öznitelik almaya geçebiliriz.
Bu işlem sayesinde link, src, alt, color kazıma gibi işlemler yapabiliyoruz.
Öncelikle link kazıma ile başlayalım isterseniz.
Bunun için TextContent kısmını GetAttribute("") ile değiştirmemiz gerekiyor.
Bu şekilde etiketlerimizin özelliklerini alabiliyoruz.
Örneğin a etiketimizin içindeki linki almak istiyorsak GetAttribute("") içine linki barındıran öznitelik olan hrefi yazmamız gerek.
Buna göre kodumuzun alacağı son hal şu şekilde olacaktır.
C#:
var Links = Document.QuerySelectorAll("a");
foreach (var Link in Links)
{
Console.WriteLine(Link.GetAttribute("href"));
}
Konunun çok uzamaması için aşırı üzerinde durmayacak olsam da diğer öznitelik kullanımları da aşağıdaki gibidir.
C#:
Console.WriteLine(Color.GetAttribute("color"));
// Renk kazıma.
Console.WriteLine(Alt.GetAttribute("alt"));
// Alt kazıma.
Console.WriteLine(Source.GetAttribute("src"));
// Resim kaynağı kazıma.
Tabi ben burada 3 tane ekledim. Siz bunları "style, width, height, border" tarzında çeşitlendirebilirsiniz.
Evet, öznitelik kazıma kısmı da bu kadardı.
Şimdi ID ve Class alma sonrada Filtreleme yapma işlemlerine bakalım.
ID ve Class alırken bir kaç farklı yolla alabiliyoruz.
İlk olarak Id ve ClassName özellikleri ile.
C#:
var Class = Document.QuerySelector("a").ClassName;
// Bu kodumuzda ilk a etiketimizin class isimlerini alıyor.
var Id = Document.QuerySelector("a").Id;
// Burada ise ilk a etiketimizin id değerlerini alıyor.
// Tabi benim size verdiğim kod üzerinde denerseniz ekrana herhangi bir çıktı vermez çünkü <a> etiketi içinde id veya class yok :D
// H3 ile çıktı alırsınız ama..
Şimdi ID ve Class kullanımımızın farklı bir türüne bakalım.
Bu seferki işlemimizi QuerySelector ile yapacağız.
ID araması başına yaparken # Class araması yaparken . koymalısınız.
C#:
var Class = Document.QuerySelectorAll(".kullanici_adi");
// Burada class'ı kullanici_adi olan tüm etiletleri alıyoruz.
// Çıkacak sonuç: Reina, Grimner, 'Ra, Kruvazör, 'pump, teux
var Id = Document.QuerySelectorAll("#ust_duzey_yonetim");
// Burada id'si ust_duzey_yonetim olan etiketleri alıyoruz.
// Sonuç: Reina
Şimdi de filtreleme işlemimize bakalım ve bu kısmı da geçelim.
C#:
var H3s = Document.QuerySelectorAll("h3");
// Buradan tüm <h3> etiketlerini alıyoruz.
foreach (var H3 in H3s)
{
if (H3.Id == "normal_uye") // Burada ise Id'sinin normal_uye olup olmadığını kontrol ediyor.
Console.WriteLine(H3.TextContent); // Eğer filtreleme işleminden geçerse ekrana yazdırıyor.
}
Bu yöntem dışında öznitelik ile de filtreleme işlemi yapılabilir.
C#:
var H3s = Document.QuerySelectorAll("h3");
foreach (var H3 in H3s)
{
if (H3.GetAttribute("id") == "normal_uye")
Console.WriteLine(H3);
}
Burada seçim biraz da size kalıyor. Tabi Title, Id ve Class gibi belirli şeyler dışında GetAttribute kullanılması gerekiyor.
Evet, bunlarda bittiğine göre Child kısmına geçebiliriz.
Child kavramını bilmeyenler için çocuk demek.
Mesela size verdiğim koda bakarsak
HTML:
<font color="#FF000E">
<h3 id="ust_duzey_yonetim" class="kullanici_adi">Reina</h3>
<h3 id="alt_duzey_yonetim" class="kullanici_adi">Grimner</h3>
<h3 id="normal_uye" class="kullanici_adi">Pump</h3>
</font>
Burada <h3>'ler, <font> etiketinin içinde oldukları için onun çocuğu oluyor.
Mesela ben bunların içindeki ilkini ekrana yazdırmak istiyorum diyelim.
Bunun için FirstElementChild kodunu kullanmam gerek.
C#:
var font = Document.QuerySelector("font");
Console.WriteLine(font.FirstElementChild.TextContent);
Bunun sonucunda ekrana "Reina" diye çıktı verecektir.
Bir de sondaki child'i yazdırmak istiyorum diyelim.
Bunun için de LastElementChild kullanmam gerekir.
C#:
var font = Document.QuerySelector("font");
Console.WriteLine(font.LastElementChild.TextContent);
Bu seferde son etiket Pump olduğu için ekrana Pump diye yazdıracak.
Ben bunların hiçbirini istemiyorum index ile yapayım diyorsanız da, Children[] kullanmanız gerek.
Örneğin ben ikinci <h3> etiketini yazdırmak istiyorum.
Bunun için kullanmam gereken kod şu:
C#:
Console.WriteLine(font.Children[1].TextContent);
Child kısmında göreceğimiz son şey ise Child sayısını almak.
Yukarıdaki html örneğimizde font içinde 3 tane h3 vardı.
Bunun sayısını almak ve ekrana yazdırmak için kullanmamız gereken kod:
C#:
var font = Document.QuerySelector("font");
Console.WriteLine(font.ChildElementCount);
Evet, Child işlemleri bu kadardı.
Şimdi Siblings kullanımına bakalım.
Bu özellik sayesinde bir sonraki etikete hükmedebiliyoruz.
Mesela ben bir sonraki etiketin içindeki değeri ekrana yazdırmak istiyorum.
Bunun için kullanacağım kod:
C#:
var h3 = Document.QuerySelector("h3");
// Bu kod ile ilk h3 etiketini aldım (Reina yazan).
Console.WriteLine(h3.NextElementSibling.TextContent);
Bununla da 'Reina' yazandan bir sonrakini ekrana yazdırıyorum. Yani ekrana 'Grimner' diye yazdıracak.
Siblings de temel olarak bu kadardı. Şimdi son olarak Parent kısmına bakalım ve konumuzu bitirelim.
Parent kısmında da pek bir şey yok aslında. Sadece belirttiğimiz etiketin üstündeki etiketi bize bildiriyor.
Mesela ben h3 etiketimin parentini öğrenmek istiyorum.
Bunun için kullanacağım kod:
C#:
var h3 = Document.QuerySelector("h3");
Console.WriteLine(h3.ParentElement.LocalName);
Kapanış
Evet, yazımız bu kadardı.
Elbette anlatmadığım kısımlar ve detaylar var ancak konu bu haliyle bile bayağı bir uzun oldu zaten..
Gelecek yazılarımda bu kütüphaneyi kullanarak gerçek sitelerden veri çeken araçlarda yazarız.
Okuduğunuz için teşekkür ederim, iyi forumlar!