C# ile Spider (Crawler - Web Örümcek) Örneği Bölüm 1

Uzunca bir aradan sonra yeniden birlikteyiz. Bu makalemizde kendimizce yazdığımız bir spider namı diğer web crawler göstereceğiz. Programımızın içeriği şu olacak: Belirlediğimiz alışveriş siteleri için programı çalıştıracağız, sonra oturup bir çay içeceğiz. Biz çayımızı yudumlarken programımız örneğin hepsiburada.com'a gidip, site içinde ne kadar ürün varsa hepsini bizim için programımızdaki veritabanına atacak. Bu işi yapan bir site de mevcut: akakce.com. Biz de acaba yapabilir miyiz diyerek oturup kendi masaüstü programımızı yazdık. Ancak makaleyi 3 parçaya bölmek istiyoruz. Birinci bölümde Türkçe fazla kaynak bulunmayan Regular Expressions yani Düzenli İfadeleri anlatmaya çalışacağız. Kendi çapımızda öğrendiğimiz şeyleri sizlerle paylaşmak isteriz. Herkes paylaşırsa Türkçe kaynak kıtlığı çektiğimiz bu konuda oldukça fazla ilerlemeler sağlayabiliriz. Düzenli İfadeler (Regex) hakkındaki yazımızı görmek için burdan devam edebilirsiniz.

Regular Expression yani Düzenli İfadeler belli bir kaynak metin içinde istediğimiz karakterlerin olup olmadığını kontrol eden bir çeşit dildir. Kendine has düzenleme ifadeleri, dil kuralları vb. özellikleri vardır. Düz bir metin için bir desen belirleriz ve o metinin içinde belirlediğimiz desenlere uyan eşleşmeler olup olmadığına bakarız. Peki bu bizim projemizde ne işe yaramıştır ?

Bir spider ya da Türkçesiyle örümceğin çalışma mantığını şu şekilde özetleyebiliriz: Programımız bir web sitesine girer. Web sitesinde, o an gezilen sayfadaki linkleri kontrol eder ve link bulursa bu linkleri daha sonra ziyaret etmek üzere hafızasına kaydeder. Sonra sırasıyla linkler taranarak, web sitesinde hiç link kalmayıncaya kadar bu işleme devam edilir. İşte burada bir web sayfasını gezerken sayfada link olup olmadığını anlamak için bir düzenli ifade kullanmayı tercih ettik. Ancak bu işlem için .net ortamında c#'ın bir sınıfı olan htmldocument da kullanılabilir. Programın hem hızlı çalışması için ve hem de maksat daha fazla bilgi paylaşımı olduğu için düzenli ifadeleri kullanmayı tercih ettik.

Artık düzenli ifadelerle ilgili minik örnekler vermeye başlayabiliriz. En baştan söyleyeyim, türkçe karakterler için düzenli ifadeler sıkıntı yaşatıyor. En azından ben biraz sıkıntı çektim. Ama bu şu an bizim için sorun değil çünkü sitelerin linklerinde Türkçe karakter (maalesef) bulunmuyor. En basitiyle bir düzenli ifade gösterecek olursak, örneğin araba kelimesi içindeki a harfini bulmak için [a] yazmamız yeterli olacaktır. Burada [a] bir desen oluyor. Aslında '[' ve ']' işaretlerini de koymanıza gerek yok. Bunlar yerine '(' ve ')' kullanabiliriz. Bu şekilde sadece 'a' harfini eşlemiş oluruz. Bunun yanında (ab) yazarsak araba eşlenmiş olur. Ama bir an önce ilerlemek için [a] yazmakta fayda var. Daha farklı bir örneği de şu şekilde verebiliriz: örneğin tek[ie]r ifadesini bir metin içinde kullanırsak, bu durumda tekir veya teker kelimelerini eşleyebiliriz. Peki elimizde birden fazla e harfi olursa? örneğin tek[e]{1,5}r deseni teker, tekeer, tekeeer, tekeeeer ve tekeeeeer kelimelerini eşleyebiliriz. Burada {1,5} ifadesinin {min,mak} değerlerine karşılık geldiği sanırım anlaşılmaktadır. {}Parantezleri yerine kullanılabilecek bir ifade de, * (yıldız) veya + (artı) 'dır. Bu karakterlerden * (yıldız) , kendinden önceki karakterin olmaması veya birden fazla olması anlamına gelmektedir. Örneğin ara(ba)* desenini kullanacak olursak, ara, araba, arababa, arabababa kelimelerini eşleyebiliriz. Burada (ba) ifadesi olsa da eşleme yapılır, olmasa da. Ancak + (artı) işaretinde durum biraz farklıdır. + karakterinin önündeki ifade, aranacak kelime içinde en az bir kez mutlaka geçmelidir. Aksi takdirde eşleme yapılmaz. Az önceki örneğimizde
ara(ba)+ desenini kullanırsak, araba,arababa,arabababa eşlenir, ancak ara eşlenmez çünkü (ba) en az bir kez tekrar etmemiştir.

İşler bu şekilde yolunda giderken, farzedin ki bir site yapmaya başladınız ve üyelik sisteminiz var. Kullanıcı kaydı yaparken bir e-posta hesabı talep ediyorsunuz. İyi niyetli kullanıcımız, e-posta adresini girerken "@" karakterini eklemeyi unuttu. Peki şimdi ne olacak ? Bu tip durumlarda internette yüzlerce örneğine rastlayabileceğiniz hazır desenler mevcut ama biz kendimizin ki yazmaya çalışalım. Öncelikle bir e-posta adresini göz önünde bulunduralım: abc@def.com . E-posta adresi temel olarak 3 kısımdan oluşur ki bu kısımlar kullanıcı adının bulunduğu kısım, "@" karakteri ve domain ismidir. Burada kullanıcı adı abc, domain ismi de def.com 'dur. Ancak bildiğimiz üzere e-posta adresleri sadece harflerden oluşmamaktadır. Farzedelim ki abc_DEF-85@xyz.com şeklinde bir e-posta adresimiz var. Şimdi burada desenimizi adım adım oluşturalım. İlk olarak [a-z] yazalım. Burada bir adım daha öne gittiğimizin farkına varmışsınızdır: [a "-" z] burada "-" işareti "a ve z karakterleri arasında kalan tüm karakterleri al" anlamına gelmektedir. Yani ister abc olsun, ister str olsun, yeter ki küçük harf olsun tüm karakterler eşlenecektir. Bir sonraki adım büyük harfleri eşlemek olsun. Bu durumda küçük harfler için yaptığımız şeyin aynını büyük harfler için yaparız: [a-zA-Z]. İşte bu kadar. Sayıları eşlemek için de aynı şeyi yapabiliriz: [a-zA-Z0-9] dersek küçük harf, büyük harf veya rakamlar eşlenebilir. ANCAK BURADA DİKKAT EDİLMESİ GEREKEN ŞEY; bu desen sadece tek bir karakter eşleyebilecektir. Bir tekrar söz konusu değildir. tekrarı sağlamak için + karakterini kullanmak zorundayız. Yukarda belirttiğim gibi, +, kendinden önceki karakterin en az bir kez olmasını gerektirir. Desenimizin son hali, [a-zA-Z0-9]+ şekline gelmiş olur. Ancak e-posta adresimizde -(tire), _ (alt çizgi) gibi karakterler de bulunmaktadır. Bu karakterleri eşlemek için de, desenimizdeki harf grubuna ekleme yapmamız gerekir: [a-zA-Z0-9-_]+. Evet, şimdiye kadar "@" karakterinden önceki tüm karakterleri eşlemiş olduk." @ " karakterini kontrol etmek için ise desenimize sadece "@" eklemek yeterli olacaktır: [a-zA-Z0-9-_]+@. Bu şu anlama gelmektedir: Verilen metin içinde, "@" karakterini görünceye kadar tüm karakterleri oku, "@" karakteri okuduğunda karakter okumayı durdur. Şimdi de domain ismini okumaya başlamalıyız. Kullanıcı isminde olduğu gibi karakter okuma işlemini devam ederiz, ancak burada ".com, .net, .tr" gibi ifadeler olabilir. Bu durumda desenimizi şu şekilde düzenlersek sorunumuz çözülmüş olacaktır: [a-zA-Z0-9-_]+@[a-zA-Z0-9]+\.[a-zA-Z]{2,4}. ".(nokta)" karakteri, düzenli ifadeler için özel bir karakter olduğundan \. ile belirtilmek zorundadır. Ancak kod yazarken derleyici kurallarına da dikkat etmek zorundasınız. örneğin \. ifadesini C#'ta belirtmek için \\. ifadesi kullanılır çünkü "\" karakteri de C# için özel bir karakterdir. Evet görüldüğü gibi temel anlamda, e-posta adresi kontrolü yapan bir desen düzenlemiş olduk.

Şimdi dilerseniz visual studio'nun bize sağladığı bir güzellikten de biraz bahsedelim: Validators (Doğrulayıcılar). Visual Studio ortamında proje geliştirirken, bu tip e-posta, telefon numarası gibi kontrolleri yapmak için kullanabileceğimiz hazır bileşenler mevcuttur. Yeni bir web sitesi projesi oluşturarak işe başlayalım. Daha sonra sayfamıza bir textBox ve bir de Label ekleyelim. Son olarak da, araç kutusundaki Validation sekmesinden, regular expression validator bileşenini sayfamıza sürükleyip bırakalım. Sayfamızın son hali aşağıdaki gibi olsun:


Şimdi bir e-posta doğrulaması yapmaya çalışalım. Resimde görülen adımları sözlü olarak anlatmakta da fayda var. Öncelikle doğrulayıcı nesnemizin özelliklerine girerek, doğrulama işlemi yapılacak olan kontrol belirlenir ki bu özellik ControlToValidate'tir. Ardından doğrulama işlemi gerçeklenmediğinde ekranda gösterilecek olan hata mesajı girilir. Son olarak da ne tür bir doğrulama uygulayacağımız ValidationExpress özelliği ile seçilir. Seçim işlemini resimden görmek de mümkün. Örneğimiz gereği biz bir İnternet Email Adresi regexini seçtik ve visual studio bizim için \w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)* düzenli ifade desenini (regex) üretti. Yukarıda anlattıklarımıza paralel bir desenle karşı karşıyayız. Burada "w" karakteri, her türlü metin karakterini temsil etmektedir. Bu harf yerine \s de kullanılabilmektedir. Bu tür kısaltmalara nette yapılacak küçük bir araştırmayla ulaşabilirsiniz.



Örneğimizi çalıştırıp yanlış bir email adresi girdiğimizde aşağıdaki resimdeki gibi bir durumla karşılaşırız:



Çeşitli örnek desenler için, visual studio'daki validator nesnesinden yararlanabilirsiniz. Şimdi artık düzenli ifadeleri bizim projemizde ne aşamada kullandığımızı anlatmanın zamanı geldi sanırım. Projemiz www.abc.com sitesine girdiğinde aslında tek yaptığı şey, www.abc.com html dokümanını alıp gelmektir. Biz bu html dokümanını kullanıcıya göstermek yerine, kendimiz arka planda işlemeye çalışıyoruz. Peki bu işlemeden kastımız nedir ? Kastımız bildiğimiz dosya okuma işlemidir. Sorgu gönderdiğimiz (Request ettiğimiz) sayfayı satır satır okuma işlemini gerçekleştirirken, html linklerini bulan bir desen yardımıyla, sayfa üzerinden diğer sayfalara verilmiş olan linkleri toparlayabiliyoruz. Bu işlemi href="[a-zA-Z0-9=:/.?&-_+;][^"]+ düzenli ifadesiyle veya daha kolay olarak href=.[^"]+ şeklinde gerçekleştirebiliriz. Burada amacımız, eğer elde ettiğimiz html dokümanındaki o an okuduğumuz satırda href=" ile başlayıp '"(çift tırnak)' işaretiyle biten yazıları belleğe almaktır. Malumunuz htmlde linkler formatındadır. Biz burada minimum deseni oluşturmaya çalıştığımız için href ile başlayan kısımdan href'in son çift tırnağına kadar olan veriyi almak yeterli oldu.

Evet, bu yazımızın amacı, düzenli ifadeler (regular expressions) hakkında küçük de olsa bilgi verebilmekti. Ben konuyu öğrenmek için regularexpression.info sitesine sık sık başvurdum. Çeşitli online desen test eden yerler var, bunlardan biri de ReTester Umarım konuyla ilgili olanlara bir faydam dokunur. Paylaşımı artırmak için, yorumlarda soru cevap ortamının oluşmasını ümit ediyorum. İkinci bölümde görüşünceye kadar, herkese iyi çalışmalar...

6 yorum:

Unknown dedi ki...

Merhabalar
Öncelikle kod paylaşımınız için teşekkür ederim.Kodlarını inceledim, mükemmel olmuş.Fakat bir sorum olacaktı.Site eklerken ürün başlık ve fiyat regex'lerini neye göre ekliyoruz?
Teşekkürler

z.burak güven dedi ki...

Merhabalar,
Belirttiğiniz regexler tamamen sitenin dizaynına göre ekleniyor. Örneğin a sitesinde ürünler bir html tablo içinde gösterilirken, b sitesinde bir div içinde gösterilebilir. Bu durumda a sitesi için regex table ayırmaya(parse) göre tasarlanırken, b sitesi için div ayırmaya göre tasarlanır. Bunun için sitenin ürün sayfasındaki html sayfanın kaynak kodlarına bakmak gerekir tabi ki. İyi çalışmalar dilerim...

Sinan dedi ki...

merhaba. kaynak kodları gönderirseniz sevinirim. netsinan(at)gmail.com

Adsız dedi ki...

çok faydalı bir paylaşım. teşekkürler

Unknown dedi ki...

cok guzel bi bilgi olmuş yazılımcılar ıcın be botcular ıcın

scrueface dedi ki...

Selamlar,
Öncelikle paylaşım için teşekkürler. Buna benzer bir proje üzerinde çalışoyorum. Size zahmet kaynak kodları gönderebilir misiniz?

email: aligunerali@gmail.com

İyi çalışmalar...