C# ile WebCrawler Uygulaması

Google, Bing, Yahoo gibi arama motorları, internetteki sayfaları indexlemek için web crawler denilen programcıklar kullanırlar.

Crawler’ların çalışma mantığı basittir;

  1. Web sayfasına git
  2. Sayfanın içeriğini indexle
  3. Sayfadaki her link için 1. adıma geri dön Crawler’ın, sayfadaki linkleri bulabilmesi anahtar adımdır.

Yazacağımız uygulamada, bir web crawler gibi sayfadaki linkleri bulacağız.

Ekran görüntüsündeki formu oluşturduktan sonra, Buton‘un Click olayına ait kodu yazmaya başlayalım.

private void btnLinkleriBul_Click(object sender, EventArgs e) { WebRequest wr = WebRequest.Create(txtAdres.Text); WebResponse ws = wr.GetResponse(); StreamReader sr = new StreamReader(ws.GetResponseStream(), Encoding.UTF8); string response = sr.ReadToEnd(); sr.Close(); ws.Close();

Regex r = new Regex("<a.+href=\"http.+://(.+)\">(.*)</a>");
foreach (Match m in r.Matches(response))
{
    string link = m.Groups[1].Value;
    if (link.IndexOf("\"") > -1)
        link = link.Substring(0, link.IndexOf("\""));
    string metin = m.Groups[2].Value;

    ListViewItem oItem = new ListViewItem(new string[] { metin, link });
    lvSonuc.Items.Add(oItem);
} }</pre> [Code Challenge #1](http://www.enginpolat.com/code-challenge-1/) ve [C# ile Google PageRank Bulma](http://www.enginpolat.com/csharp-ile-google-pagerank-bulma/) yazılarında kullandığım tekniğin aynısı ile sayfanın içeriğini string değişkene alıyoruz.
WebRequest wr = WebRequest.Create(txtAdres.Text);
WebResponse ws = wr.GetResponse();
StreamReader sr = new StreamReader(ws.GetResponseStream(), Encoding.UTF8);
string response = sr.ReadToEnd();
sr.Close();
ws.Close();

Daha sonra, *Regex* sınıfından yeni bir örnek oluşturup (constructer'ına verdiğimiz parametre önemli), dönen sonuç kümesinin içeriğini *ListView* kontrolüne dolduruyoruz.

Eğer sayfanın içeriğini tuttuğumuz değişkeni veritabanına yazsak, ve sayfada bulduğumuz her link için bu adımları tekrar yapsak, tam bir web crawler uygulaması yazmış olacaktık.

Ama bu noktadan itibaren uygulamayı geliştirmeyi size bırakıyorum (BilgeAdam'daki öğrencilerime hep dediğim gibi, "Bundan sonrası size ödev!")

Projenin bu halini şuradan indirebilirsiniz.

C# ile Google PageRank Bulma

Google‘ın PageRank uygulaması, web sitelerinin Google tarafından önemini bulmakta kullanılan bir algoritmadır.

Wikipedia’daki şu adresten, PageRank algoritması ile ilgili ayrıntılı bilgiye erişebilirsiniz.

Siz de sitenizin PageRank değerini http://www.prchecker.info adresinden bulabilirsiniz.

Yazacağımız uygulama ile, sitenizin Google PageRank değerini programatik olarak buldurabileceğiz.

Google sitelerin PageRank değerlerini, http://toolbarqueries.google.com/search adresine gönderilen sorgulara cevap olarak verebiliyor. Fakat sonuç alabilmemiz için bu adrese doğru parametreleri vermemiz gerekiyor, aksi halde HTTP403 : Forbidden hatası alıyoruz.

Parametreler:

  • features=Rank
  • client=navclient-auto
  • q=info:{adres}
  • ch={checksum} Checksum bilgisini hesaplamak için Google’ın yayınladığı bir algoritma var. Uygulamamızda, bu algoritmayı C# ile yazacağız.

Yukarıdaki resimde görünen arayüzü hazırladıktan sonra, projemize GooglePageRank isminde static class ekliyoruz.

GooglePageRank static class’ı üç tane static method’dan oluşuyor.

private static void Mix(ref uint a, ref uint b, ref uint c) { a -= b; a -= c; a ^= c >> 13; b -= c; b -= a; b ^= a << 8; c -= a; c -= b; c ^= b >> 13; a -= b; a -= c; a ^= c >> 12; b -= c; b -= a; b ^= a << 16; c -= a; c -= b; c ^= b >> 5; a -= b; a -= c; a ^= c >> 3; b -= c; b -= a; b ^= a << 10; c -= a; c -= b; c ^= b >> 15; }</pre>

private static string GoogleChecksum(string url)
{
    uint GoogleMagic = 0xE6359A60;

    uint a, b;
    uint c = GoogleMagic;

    a = b = 0x9E3779B9;

    int k = 0;
    int length = url.Length;

    while (length >= 12)
    {
        a += (uint)(url[k + 0] + (url[k + 1] << 8) + (url[k + 2] << 16) + (url[k + 3] << 24));
        b += (uint)(url[k + 4] + (url[k + 5] << 8) + (url[k + 6] << 16) + (url[k + 7] << 24));
        c += (uint)(url[k + 8] + (url[k + 9] << 8) + (url[k + 10] << 16) + (url[k + 11] << 24));

        Mix(ref a, ref b, ref c);

        k += 12;
        length -= 12;
    }

    c += (uint)url.Length;

    switch (length)
    {
        case 11:
            c += (uint)(url[k + 10] << 24);
            goto case 10;
        case 10:
            c += (uint)(url[k + 9] << 16);
            goto case 9;
        case 9:
            c += (uint)(url[k + 8] << 8);
            goto case 8;
        case 8:
            b += (uint)(url[k + 7] << 24);
            goto case 7;
        case 7:
            b += (uint)(url[k + 6] << 16);
            goto case 6;
        case 6:
            b += (uint)(url[k + 5] << 8);
            goto case 5;
        case 5:
            b += (uint)(url[k + 4]);
            goto case 4;
        case 4:
            a += (uint)(url[k + 3] << 24);
            goto case 3;
        case 3:
            a += (uint)(url[k + 2] << 16);
            goto case 2;
        case 2:
            a += (uint)(url[k + 1] << 8);
            goto case 1;
        case 1:
            a += (uint)(url[k + 0]);
            break;
        default:
            break;
    }

    Mix(ref a, ref b, ref c);

    return string.Format("6{0}", c);
}
public static string PageRankHesapla(string adres)
{
    string checkSum = GoogleChecksum("info:" + adres);
    string url = "http://toolbarqueries.google.com/search?client=navclient-auto&ch=" + checkSum + "&features=Rank&q=info:" + adres;

    try
    {
        WebRequest request = WebRequest.Create(url);
        WebResponse response = request.GetResponse();

        StreamReader reader = new StreamReader(response.GetResponseStream());
        string data = reader.ReadToEnd();

        reader.Close();
        response.Close();

        if (data.IndexOf(':') != -1)
            data = data.Substring(data.LastIndexOf(':') + 1);

        return data;
    }
    catch (Exception)
    {
        return "-1";
    }
}


Şimdi yapmamız gereken, Butonun *Click* olayında, *GooglePageRank* static class'ının *PageRankHesapla* method'unu çağırmak ve dönen değeri Label'da göstermek.

Uygulamanın çalışır halini bu adresten indirebilirsiniz.

Code Challenge #1

Dün Emre (nam-ı diğer kara) arkadaşımla internette gezerken, bir youtube video’suna denk geldik. Emre’nin bilgisayarındaki hosts dosyasında güncel youtube ip adresleri olmadığı için videoyu izleyemedik.

Aklımıza, youtube domainine ait ip adreslerini otomatik olarak bulacak ve hosts dosyasını güncelleyecek bir uygulama yazmak geldi. Öğle yemeğine çıkmamıza 15 dakika olduğu için, bunu bir yarışa dönüştürmeye karar verdik.

İşte Yarışmanın Kuralları;

  • youtube.com, www.youtube.com, img.youtube.com alan adlarının ve v{1-24}.lscache{1-8}.c.youtube.com formatındaki alan adlarının ip adresleri otomatik olarak çözümlenecek
  • Domain adından IP adresini çözen bir servis kullanılacak (Ben böyle bir web service bulamadım, o yüzden http://www.hcidata.info/host2ip.cgi adresindeki formu kullandık)
  • Sonuç bilgisi C:\Windows\System32\drivers\etc\ altındaki hosts dosyasına otomatik olarak yazılacak
  • Uygulamayı yazma - test etme ve çalıştırma sonucunda, ilk kimin uygulaması hosts dosyasını güncellerse kazanmış olacak YoutubeHostDuzenleyici_2

Sizinde 15 dakikanız var, code challenge‘ımıza katılmak ister misiniz?

Benim çözümümü görmek için 

Ben öncelikle http://www.hcidata.info/host2ip.cgi adresindeki formu inceleyerek başladım;

YoutubeHostDuzenleyici_1

WebRequest sınıfından bir örnek oluşturdum, sayfanın çıktısını GetResponse() methodu ile alarak WebResponse sınıfında bir nesnede sakladım. StreamReader nesnesini kullarak, sayfanın HTML çıktısını string tipinde bir değişkene atadım.

v{1-24}.lscache{1-8}.c.youtube.com adreslerinin ip adreslerini bulmak için içiçe iki paralel for döngüsü kurdum.

response değişkeninde oluşan HTML’i parse ederek, ip adresine ulaştım.

hosts dosyasında youtube.com adresli satırları bulmak ve güncellemek için .Net Regular Expression (Regex) classını kullandım.

Son olarak, bu kodları fonksiyon haline getirdim;

private void btnIPBul_Click(object sender, EventArgs e) { txtHosts.Clear(); StringBuilder sb = new StringBuilder(); sb.AppendLine(string.Format(“{0}\t{1}”, FindIP(“youtube.com”), “youtube.com”)); sb.AppendLine(string.Format(“{0}\t{1}”, FindIP(“www.youtube.com”), “www.youtube.com”)); sb.AppendLine(string.Format(“{0}\t{1}”, FindIP(“img.youtube.com”), “img.youtube.com”)); Parallel.For(1, 9, iLoop => { Parallel.For(1, 25, yLoop => { string url = string.Format(“v{0}.lscache{1}.c.youtube.com”, yLoop, iLoop); sb.AppendLine(string.Format(“{0}\t{1}”, FindIP(url), url)); }); });

txtHosts.Text = sb.ToString(); }

private string FindIP(string AddressToLookUp) { WebRequest r = WebRequest.Create(string.Format(“http://www.hcidata.info/host2ip.cgi?domainname={0}&findIP=Find IP Address&ipaddress=127.0.0.1”, AddressToLookUp)); WebResponse s = r.GetResponse();

StreamReader sr = new StreamReader(s.GetResponseStream(), Encoding.UTF8);
string response = sr.ReadToEnd();

sr.Close();
s.Close();

string ipAddress = response.Substring(response.IndexOf("IP Address : ") + 13, 16);

return ipAddress.Substring(0, ipAddress.IndexOf("\n")); }

private void btnHostsGuncelle_Click(object sender, EventArgs e) { if (txtHosts.Text == “”) btnIPBul.PerformClick();

Regex r = new Regex(@"^(.*youtube\.com)");
StringBuilder sb = new StringBuilder();

foreach (string line in File.ReadAllText(@"C:\Windows\System32\drivers\etc\hosts").Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries))
    if (!r.IsMatch(line))
        sb.AppendLine(line);

sb.AppendLine();
sb.AppendLine();
sb.AppendLine("# youtube.com IP'leri Buradan Başlıyor");
sb.Append(txtHosts.Text);

File.WriteAllText(@"C:\Windows\System32\drivers\etc\hosts", sb.ToString()); }

Uygulamanın kodlarını buradan indirebilirsiniz.

VB.NET'te anahtar kelimeyi değişken ismi olarak kullanma

Daha önce yazdığım C#’ta anahtar kelimeyi değişken ismi olarak kullanma yazımda, aynı işin VB.NET’te nasıl yapılacağını yazmamıştım.

Değişken isminin, dilin anahtar kelimelerinden biri olmasına verbatim identifier deniyor.

MSDN’de C# dili için verbatim identifier nasıl tanımlanır makalesi mevcut, fakat VB.NET için nasıl yapılacağı dökümante edilmemiş.

Hala verbatim identifier tanımlamanın KÖTÜ bir fikir olduğunu düşünüyorum, fakat VB.NET’te verbatim identifier nasıl tanımlanır, merak edenler için;

Dim [String] As String = “” Dim [For] As Boolean = True Dim [While] As Integer = 6 Dim [False] As DateTime = DateTime.Now Dim [ReadOnly] As File

Kısa Sınav - 9

Sql Server’da veritabanında zaten varolan bir tabloya yeni bir alan eklemek istiyorsunuz. Yeni ekleyeceğiniz alanda, PersonelNo bilgisini saklayacaksınız.

PersonelNo bilgisi herzaman 5 karakterden oluşuyor. Dünya üzerinde çeşitli ülkelerde çalışan yüzlerce çalışanınız olduğu için, PersonelNo alanında saklayacağınız bilgiler genelde Unicode karakterlerden oluşuyor.

PersonelNo alanı için en uygun veritipi ne olmalı?

  • nvarchar(5)
  • varchar(50)
  • nchar(5)
  • char(5) Sorunun doğru cevabı için; Doğru cevap: nchar(5)

nchar veritipi sabit-uzunluklu unicode veri saklayabilir. Sorudaki ihtiyaçlar için, nchar(5) veritipini seçmek en mantıklısı olacaktır.

varchar veritipi değişken-uzunluklu metin bilgisi saklayabilir. Sorudaki ihtiyaç, sabit uzunluk (5) olduğu için, bu veritipini seçmek gereksizdir.

nvarchar veritipi değişken-uzunluklu unicode veri saklayabilir. Sorudaki ihtiyaç, sabit uzunluk (5) olduğu için, bu veritipini de seçmemeliyiz.

char veritipi unicode veri saklayamaz.

Engin Polat hakkında

Senior Software Engineer, @Microsoft

Ada ve Ege'nin babası ;)

Kategoriler

İstatistik

Makale Adedi: 484

Creative Commons Lisansı