Düzenli İfadeler ( Regular Expressions) Robot Yazımı

Kodla Büyü

togius

Süper Üye
Süper Üye
Mesajlar
1,730
Düzenli ifadeler bir metin içerisinde belirlenmiş kurallara ve desenlere uyan büyük veya küçük metin ve metin parçalarını sorgulamaya yarayan yapılardır. Düzenli ifadeleri aklınıza gelecek her alanda kullanabilirsiniz. Javascript kullanarak bir input kontrole e-posta adres türünün girilmesini zorlayabileceğimiz gibi robot yazarak belirtilen hedef sitelerdeki verilerin otomatik olarak sistemimize yüklemesini sağlamak gibi. Peki bu düzenli ifadeler nedir? Csharpnedir.com ve benzer sistemlerden derlediğim açıklamaları belirteyim akabinde de MEB’in bazı genel müdürlük sayfalarındaki duyuruları otomatik olarak indeksleyecek basit bir kod yazalım.

Regular Expression’larda Kullanılan Özel Karakterler ve Etkileri

Regular expression desenleri tanımlamada kullanılan özel karakterleri örnekleri ile anlatırsak sanırım regular expressionlar daha tanıdık ve kolay gelebilir.
1.) “.” Karakteri
Tek bir karakteri temsil eder(yeni satır karakteri hariç).
“CSharp.edir” şeklindeki bir desen CSharpnedir, CSharpNedir, CSharpSedir, CSharp3edir gibi stringleri döndürebilir.
2.) “[]” Karakterleri
Bir arrayi yada aralığı temsil eder.
“CSharp[SNY]edir” deseni, CSharpSedir, CSharpNedir ve CSharpYedir stringlerini döndürür.
“CSharp[a-z]edir” şeklindeki kullanım aralık belirtmeye yarar.
“CSharp[0-9]edir” şeklindeki kılanlım ise sayısal aralık belirtmeye yarar.
3.) “?” Karakteri
Kendinden önceki karakterin stringte olması yada olmamasını sağlar.
“CSharpn?edir” deseni CSharpedir yada CSharpnedir döndürür.
4.) “\” Karakteri
Kendinden sonraki özel karakterin stringe dahil edilmesini sağlar.
“CSharpnedir\?” deseni CSharpnedir? Stringini döndürür. (Eğer “\” karakterini kullanmamış olsaydık CSharpnedi yada CSharpnedir dönerdi.)
5.) “*” Karakteri
Kendinden önceki karakterin yada stringin hiç olmaması yada istediği sayıda olmasını sağlar.
“CSharpnedir*” deseni, CSharpnedi, CSharpnedir, CSharpnedirr, CSharpnedirrr, ... döndürür. “CSharp(nedir)*” deseni ise CSharp, CSharpnedir, CSharpnedirnedir, ... döndürür.
6.) “{}” Karakterleri
Kendinden önce gelen karakterin belirtilen sayıda tekrar etmesini sağlar.
“C{4}Sharpnedir” deseni, CCCCSharpnedir stringini döndürür.
7.) “^” Karakteri
Satır başını ifade eder.
“^CSharpnedir” deseni, satır başında “CSharpnedir” stringi varsa bunu döndürür.
8.) “$” Karakteri
Satır sonunu ifade eder.
“CSharpnedir$” deseni, satır sonunda “CSharpnedir” stringi varsa bunu döndürür.

Gelelim Uygulamamıza

Kod:
using System.Text.RegularExpressions;
using System.IO;
using System.Net;
using System.Text;

protected void Page_Load(object sender, EventArgs e)
    {

    }
    /*
     * linkBolumleri adında 2 özellikli bir yapı tanımlıyoruz. Neden class yerine yapı tanımladık.
     * Yapılar, sınıflar ile büyük benzerleklik gösterirler. Sınıf gibi tanımlanırlar. 
     * Hatta sınıflar gibi, özellikler,metodlar,veriler, yapıcılar vb... içerebilirler. 
     * Buna karşın sınıflar ile yapılar arasında çok önemli farklılıklar vardır. 
     * 
     * Herşeyden önce en önemli fark, yapıların değer türü olması ve sınıfların referans türü olmasıdır. 
     * Sınıflar referans türünden oldukları için, bellekte tutuluş biçimleri değer türlerine göre daha farklıdır. 
     * Referans tiplerinin sahip olduğu veriler belleğin öbek(heap) adı verilen tarafında tutulurken,
     * referansın adı stack(yığın) da tutulur ve öbekteki verilerin bulunduğu adresi işaret eder. 
     * Ancak değer türleri belleğin stack denilen kısmında tutulurlar.
     * 
     * Şimdi bunun bizim için ne önemi var?
     * Küçük boyutlarda veriler ile çalışırken bu verileri sınıflar içerisinde kullandığımızda 
     * bu kezde gereksiz yere bellek kullanıldığı öbek şişer ve performans düşer. 
     * Bu konudaki uzman görüş 16 byte'tan küçük veriler için yapıların kullanılması, 
     * 16 byte'tan büyük veriler için ise sınıfların kullanılmasıdır. 
     */
    private struct linkBolumleri
    {
        public string[] _basliklar;
        public string[] _url;
    }

    /* getPageInformation() fonksiyonu bize hedef sayfanın aşağıda strUrl olarak nitelendiriliyor;
     * Html kodlarını getirir. Bunun için WebRequest ve WebResponse methodlarından yararlanacağız.
     * Bunların burada nasıl kullanıdığına deyinmeyeceğim.
     * StreamReader sr = new StreamReader(webCevap.GetResponseStream(), Encoding.GetEncoding("ISO-8859-9"));
     * ile tüm kodları sr StreamReader nesnesine aktaradık. sr.ReadToEnd() tüm sayfa kodlarını 
     * string ifadeye çevirdi.
     */
    private string getPageInformation()
    {
        string icerik = "";
        string strUrl = "";
        strUrl = "http://www.meb.gov.tr/duyurular/index.asp?ID=4";
        WebResponse webCevap;
        WebRequest webTalep = WebRequest.Create(strUrl);
        webCevap = webTalep.GetResponse();
        StreamReader sr = new StreamReader(webCevap.GetResponseStream(), Encoding.GetEncoding("ISO-8859-9"));
        icerik = sr.ReadToEnd();
        sr.Close();
        webCevap.Close();
        return icerik;
    }

    //Tüm duyuru kısımlarının tutulduğu bölüm
    /* İşte dananın kuyruğunun koptuğu kısım
     * string _pattern = "<li class=\"im[3|6]\">((.|\n)*)?</li>"; ifadesi ne demek?
     * hedef urlden talep ettimiz html kodlarına bakıyoruz. ben burada <li class="im3">..</li> veya
     * <li class="im6">..</li> lı hedef ifadeleri hedef aldım bunu _patter adında bir metne bu deseni
     * atadık. bu bizim metin sorguları için kullanacağımız desenimiz.
     * Regex _regex = new Regex(_pattern); ile _regex adında bir düzenli ifade tanımladık.
     * 
     * Match bulunan = _regex.Match(this.getPageInformation()); Match türünde bulunan adlı nesnemizi
     * tanımladık. Matches türü kullansaydık sonuçları dizi olarak alacaktık.
     * 
     * string _tmpIcerik = "<ul>";
        _tmpIcerik = bulunan.Value.Replace(_tmpIcerik, "");
        _tmpIcerik = _tmpIcerik.Replace("</ul>", ""); 
     * 
     * bu kod ise elde ettiğimiz veride yaptığımız temizlik işlemi.
     */
    private linkBolumleri fnklinkBolumleri()
    {
        string _pattern = "<li class=\"im[3|6]\">((.|\n)*)?</li>";
        Regex _regex = new Regex(_pattern);
        Match bulunan = _regex.Match(this.getPageInformation());
        string _tmpIcerik = "<ul>";
        _tmpIcerik = bulunan.Value.Replace(_tmpIcerik, "");
        _tmpIcerik = _tmpIcerik.Replace("</ul>", "");

        return this.liMatch(_tmpIcerik);
    }

    /* Burada benzer bir işlemide linkleri elde etmek için kullandık.
     * MatchCollection _matches = _regex.Matches(metin); ile sonuçları
     * dizi olarak aldık.
     * 
     */

    private linkBolumleri liMatch(string metin)
    {
        linkBolumleri li = new linkBolumleri();
        string _pattern = "<a(.|\n)*?>(.*?)\n*</a>";
        Regex _regex = new Regex(_pattern);
        MatchCollection _matches = _regex.Matches(metin);
        int i = 0;

        li._basliklar = new string[_matches.Count];
        li._url = new string[_matches.Count];

        foreach (Match bulunan in _matches)
        {
            li._basliklar[i] = this.toBaslik(bulunan.Value, li).
                Replace("</a>", "").Replace(">", "");
            li._url[i] = this.toUrl(bulunan.Value, li).
                Replace("\"", "");
            if ((li._url[i].IndexOf("/", 0) == 0))
                li._url[i] = "http://www.meb.gov.tr" + li._url[i];
            if(li._url[i].IndexOf("http", 0) == -1)
                li._url[i] = "http://www.meb.gov.tr/" + li._url[i];
            i++;
        }
        return li;
    }

    // İlgili haberlerin urllerini elde ediyoruz.
    private string toUrl(string metin, linkBolumleri li)
    {
        string _pattern = "\"(.*?)\n*\"";
        Regex _regex = new Regex(_pattern);
        Match _match = _regex.Match(metin);
        return _match.Value;
    }

    // İlgili haberlerin başlıklarını elde ediyoruz.
    private string toBaslik(string metin, linkBolumleri li)
    {
        string _pattern = ">(.*?)\n*</a>";
        Regex _regex = new Regex(_pattern);
        Match _match = _regex.Match(metin);
        return _match.Value;
    }

    // Burada da elde ettiğimi sonuçları veritbanına aktarıtoruz.
    /*
     * databaseProcess.KayitIslemi_MebBilgilendirme(b._basliklar[i], lb._url[i]) > 0) bu method
     * aklınızı karşıtırmasın bu benim kendi veritabanıma eklemek için kullandığım bir class
     * siz b._basliklar[i] ve  lb._url[i] ile başlıklar ve urlleri veritabanınıza ekleyebilirsiniz.
     */
    protected void btnAktar_Click(object sender, EventArgs e)
    {
        linkBolumleri lb = this.fnklinkBolumleri();
        int linkSayisi = lb._basliklar.Length;
        int _basariliKayit = 0;
        int _basarisizKayit = 0;

        for (int i = linkSayisi - 1; i >= 0; i--)
        {
            if (databaseProcess.KayitIslemi_MebBilgilendirme(
                lb._basliklar[i], lb._url[i]) > 0)
                _basariliKayit++;
            else
                _basarisizKayit++;
        }
        lbDurum.Text = "Dikkat!: " + _basariliKayit.ToString() + " adet başarılı kayıt." + "\n";
        lbDurum.Text += _basarisizKayit.ToString() + " adet başarısız kayıt vardır.";
    }

Aynı yapıyı ben şu anda http://www.testsinavi.com da kullanıyorum. Bunun bir benzeri bir uygulamayı da http://www.videoege.com da filmleri veritabanıma eklemek için kullanıyorum. Film sitelerindeki filmleri buluyor, resimleri ayrı açıklamaları ayrı ve videolarını ayrı olarak sisteme ekliyor. Siz pleskten gidip Zamanlayıcı (Crontab) oluşturarak böyle bir uygulamayı otomatikleştirebilir ve sisteminize otomatik olarak haberleri girebilirsiniz. Haber scriptiniz kendi kendine haber ekler.
Arkadaşlar bu ileri düzey bir uygulama olduğu için bazı temel methodlara ve veritabanı kayıt işlemlerine deyinmedim bunları zaten biliyor olmanız gerekiyor. Kolay gelsin arkadaşlar
 
hocam emeğine sağlık, bu sıcakta uğraşıyorsun, senden başka (1-2 kişi dışında) uğraşan da yok, millet futbol kavgasında ...
bazı eleştirilerim var da, umarım yanlış anlaşılmam. dediğin gibi bot yazma konusu biraz ileri düzey, iyi bir regex bilgisi olmadan (baştaki not yetersiz bence) bu konunun anlatılması biraz garip olmuş, ayrıca diğer konu başlıkarı birbiriyle ilgisiz... amaç asp.net öğretmekse basitten zora doğru gitsek daha iyi olur bence. asp.net nedir ile başlansa değişkenler, diziler, kontrol yapıları .... şeklinde gitse ve video anlatım olsa çok güzel olur bence.
bu şekilde asp.nette temeli olmayanlar birşey anlamaz
asp.net ile ilgilenmeyeli yıllar oldu :) (söylediklerim gözümden kaçmış olabilir) baktığım kadarıyla direk bütün linkleri alıyor, url'leri okuyor. ama daha önceden kaydedilmiş mi diye bir kontrol yok. yani sürekli bütün url'leri okur. onun yerine yazdığımız bot, yeni veri eklenip eklenmediğini kontrol etse (yeni veri varsa bot çalışır), ve onları kategorilese daha hoş olur bence. ayrıca php'deki gibi get_meta_tags gibi regex gerektirmeden sayfanın meta taglarını çeken bir komut yok mu, bot konusunda bu da çok işimize yarar bence. ayrıca bu kodlar hızlı mı? mesela php'de sıkça kullanılan 2 yöntem var. file_get_contents diğeri curl. curl , daaha hızlıdır ve sayfalara üye girişi yapabilir, veri yollayabilir. ama file_get_contents hem yavaştır hem de sayfanın son gözüken html halini çeker...
bence en önemlisi de bot yazarken hedefimizdeki siteyi iyi tanımak gerekiyor.
 
Rüzgara Karşı hocam teşekkürler İlgin için öncellikle teşekkürler :)

1. Evet bu konu gayet ileri düzeyde başta da belirttim bunu kullanacak arkadaşların WebClient işlemleri veya WebRequest , WebRespose daha doğrusu System.Net isim alanını bilmesi gerekir. Ancak konular neden bu kadar dağınık. Ona değineyim. bbnet e bu bölümü açmayı düşündüğümde ileri - orta - giriş seviyesi şeklinde 3 katman halinde ele almayı düşündüm zaten bu olacak bende bu arada kendi kütüphanemdeki makalelerimi ( ki bende en eskiden güncele) siteye ekleyeyim ki daha sonra bunları belli bir kategoride listeletmek daha kolay olacağı için eklemeye başladım. Zaten o zamana kadar makaleler iyice ilgi çekmeye başlar. Burada asıl amaç sitede başı boş muhabbet yapan arkadaşlara tepki çekmek ve ilgili arkadaşlara yardımcı olmak. Makaleleri derleme işini en son makalemden sonra hep beraber yaparız çok daha düzgün şeyler çıkarabiliriz :)

2. databaseProcess.KayitIslemi_MebBilgilendirme(b._basliklar, lb._url) > 0) burada zaten veritabanında eklenen kayıt karşılaştırması yapılıyor ama amacım veritabanı anlatmak olmadığı için ilgiyi kaybetmemek adına burada ona değinmedim.

3. Regex php ninde kullandığı malumun bir yapı gayette hızlı bot yazımında dediğin gibi hedef sitenin iyi analiz edilebilmesi gerekir yoksa düzenli ifadeyi oluşturamazsın.

Programlama ile ilgilenen tüm arkadaşlara selamlar...
 
togius' Alıntı:
Rüzgara Karşı hocam teşekkürler İlgin için öncellikle teşekkürler :)

1. Evet bu konu gayet ileri düzeyde başta da belirttim bunu kullanacak arkadaşların WebClient işlemleri veya WebRequest , WebRespose daha doğrusu System.Net isim alanını bilmesi gerekir. Ancak konular neden bu kadar dağınık. Ona değineyim. bbnet e bu bölümü açmayı düşündüğümde ileri - orta - giriş seviyesi şeklinde 3 katman halinde ele almayı düşündüm zaten bu olacak bende bu arada kendi kütüphanemdeki makalelerimi ( ki bende en eskiden güncele) siteye ekleyeyim ki daha sonra bunları belli bir kategoride listeletmek daha kolay olacağı için eklemeye başladım. Zaten o zamana kadar makaleler iyice ilgi çekmeye başlar. Burada asıl amaç sitede başı boş muhabbet yapan arkadaşlara tepki çekmek ve ilgili arkadaşlara yardımcı olmak. Makaleleri derleme işini en son makalemden sonra hep beraber yaparız çok daha düzgün şeyler çıkarabiliriz :)

2. databaseProcess.KayitIslemi_MebBilgilendirme(b._basliklar, lb._url) > 0) burada zaten veritabanında eklenen kayıt karşılaştırması yapılıyor ama amacım veritabanı anlatmak olmadığı için ilgiyi kaybetmemek adına burada ona değinmedim.

3. Regex php ninde kullandığı malumun bir yapı gayette hızlı bot yazımında dediğin gibi hedef sitenin iyi analiz edilebilmesi gerekir yoksa düzenli ifadeyi oluşturamazsın.

Programlama ile ilgilenen tüm arkadaşlara selamlar...

önemli değil hocam :)
hızlı mı derken regex'i kastetmedim. zaten regexten başka seçenek de gözükmüyor. WebRequest.Create fonksiyonunu sormuştum. ayrıca sayfaya üye girişi de gerekebilir, curl şifreli sayfalara da giriş yapabiliyor.
 
Tolga hocam, konuyla ilgili bilgilendirme icin tesekkur ederiz. Regex'in gucu gercekten inanilmaz.

Konuyu gorunce eklemek istedim: Kodos diye bir program vardi. Duzenli ifade desenleri ve eslesmeleri uzerinde gorsel olarak calismak icin. Konuyla ilgilenenler icin tavsiye ederim.
 
erkan kodosu sen tavsiye etmiştin bana evet 10 numara bir program işinizi epey kolaylaştırıyor.
 
Geri
Üst