Azure Cloude Services ile Bir Web Sitesini Pars Edip İlgili Datayı Clientlara SignalR ile Push Etme

Selamlar;

Bugün bir web sitesindeki bilgileri çekip clientlara banner olarak verilen bir iframe, sayfasına basıcaz. Bu sırada web sayfasını sürekli pars etmeye devam edicez. Herhangi bir değişiklik durumunda ilgili bannerları güncelliyiceğiz. Bu amaç ile Azure Cloude Services’de, watin.dll’ini kullanarak, http://www.sahibinden.com/ portalında araba ilanları sayfasını pars edip, son 6 ilanın datasını çekicez. Eğer önceden çekilen datalardan farklılık var ise bir hub class’ının method’unu tetikleyip signalR kullanarak clientlara push edicez. Bu şekilde yeni girilen araba ilanları kullanıcılara gösterilmiş olucak. Öncelikle Pars edilecek siteyi aşağıda görüldüğü gibi http://www.sahibinden.com/otomobil inceleyelim.

ilan

Kaydedilecek alanlar İlan Başlığı :Title, Yıl:Year, Km:Km, Renk: Color, Fiyat: Price, İlan Tarihi: Date, İl/İlçe:Place .Solution’a yeni bir DAL isminde CodeFirst kullanılan bir projesi yaratılır.Banner isminde bir DBcontext ve SahibindenCars şeklinde Data Model  aşağıda görüldüğü gibi oluşturulur. CodeFirst için önceden yazdığım makaleyi inceleyebilirsiniz.

SahibindenCars.cs

Banner.cs:

SahibindenCars Tablosunun design’ı azure tarafında aşağıdaki gibidir.

table

Tüm projeler database işlemlerinde bu DAL projesini kullanacaktır. Şimdi de siteyi pars işlemini inceleyelim.

Öncelikle solution’a Cloud altından Windows Azure Cloud Service projesi eklenir.

Untitled

Daha sonra karşımıza çıkan Rolelerden Worker Role seçilir.

Untitled2

Karşımıza altta görüldüğü gibi sonsuz while döngüsü içinde belli zaman aralığında bekliyen bir kod bloğu çıkar.

Şimdi istenen siteyi pars etmek için aşağıda görülen Watin package indirilir. Watin’in esas amacı sitelere load test yapmaktır. Explorer bir browser’ı açarak belirlenen işlem adımlarını siteye uygular. Ama amaca yönelik olarak bu örnekde de olduğu gibi pars işlemi içinde kullanılabilir:)

Untitled3

Şimdi aşağıdaki kodları inceleyelim.

  • Öncelikle watin’in cloude serviste çalışması için yeni bir thread açılır ve ApertmentState’i STA olarak seçilir. Thread başlatıldıktan sonra tekrar çağrılana kadar 30sn bekletilir.

  • Watin için timeout ve tamamlanma süreleri set edilir. Pars işlemi yapılırken ilgili browserın gizlenmesi Settings.Instance.MakeNewIeInstanceVisible = false; ile ayarlanır. Ayrıca karşımıza çıkabilecek dialog kutucukları otomatik olarak kapatılması Settings.AutoCloseDialogs = true; ile ayarlanır. Gidilicek url string url = “http://www.sahibinden.com/otomobil”; şeklinde set edilir.

  •  Ilgili url’e using (var browser = new IE(url)) ile gidilir. Browser’ın yüklenmesi browser.WaitForComplete(); ile beklenilir. Sahibinden’den tüm resultlar aşağıda görüldüğü gibi searchResultsTable adlı tabloda altında gösterilmektedir.  İlgili table ekranda gözükene kadar beklemek için browser.Table(Find.ById(“searchResultsTable”)).WaitUntilExists(); komutu kullanılır. Daha sonra ilgili table bulunarak altındaki ilk 6 row tek tek  foreach (TableRow trow in browser.Table(Find.ById(“searchResultsTable”)).TableRows.Skip(1).Take(6)) şeklinde alınır. İlk satır başlık olduğu için atlanmıştır. Alınan her satırın hücreleri gezilerek ilgili data model doldurulur. Böylece ilgili site pars edilmiş ve data model oluşturulmuş olur.

html

  •  Önceden bu datalar çekilmemiş ise ilgili data model bir cacheDatas’ına atanır. Eğer çekilmiş ise değişiklik olup olmadı yani yeni ilan olup olmadığına ilanın resim yoluna bakılarak isDataChange() methodu ile yapılır. Değişiklik yok ise hernagi bir işlem yapılmaz. Eğer yeni ilan gelmiş ise data model var olan cacheDatas’ına tekrardan FillCache() methodu ile atanır. Database truncate edilip yeni data model insert edilir.

  • Son olarak clientlar’ın olan değişiklikten haberdar olması için signalR methodu asenkron olarak tetiklenir. Bunu yapılabilmek için projemize alttaki package’in indirilmesi gerekir.client

Bu işlem için öncelikle Hub’ın bulunduğu domain belirlenir(http://sahibindenbanner2.azurewebsites.net/). Daha sonra bağlanılacak olan hub class’ı tanımlanır(GetCars). Son olarak hub’daki hangi method çağrılacak ise ismi belirtilir(RefreshCars). Bu işlemin asenkron yapılmasındaki amaç dış bir sisteme bağlanılırken var olan akışın durmasını engellemek ve bu işlemi arka planda bağımsız olarak çalıştırmaktır.

Tüm bu adımlar 30 sn’de bir tekrarlanmaktadır.

WorkerRole.cs:

Aynı işlemi bir de claude services olmadan windows application ile yazalım. Amaç azure kullanılmadan  uygulamanın local makinada da test edilebilmesidir. İlgili kodlar aşağıdadır. Burada cloude servicesden farklı olarak while sonsuz döngüsü yoktur ve yerine timer vardır. Timer 30 sn de bir çalışmaktadır. Windows application’da watin için thread’e gerek yoktur. İlgili siteyi pars etmek için açılacak explorer browser başlangıçta protected override void OnVisibleChanged(EventArgs e){ base.OnVisibleChanged(e); this.Visible = false; } komutu ile gizlenmektedir. Ayrıca notifyIcon1 ile exit’e basılarak uygulama kapatılabilmektedir.

SahibindenWidget/Form1.cs :

Şimdi de clientlara göstereceğimiz view’ı mvc ile yazalım. Öncelikle HomeController’da Index Action’ını aşağıda görüldüğü gibi yazalım. GetCars() diye bir method oluşturulur. Amcı sahibinden pars edilen son 6 datayı database’den çekmektir. Url’de clear adlı request parametresi var ise cache temizlenir. İlgi data 1 dakikalık cache’e konup Index view’ına gönderilir. Bir de GetCars:Hub sınıfı signalR ile clientları, data değişiminde tetiklemek için oluşturulur. Datada farklılık olduğu zaman ilgili data, databaseden çekilip SahibindenCars.cshtml partial view’ı ile birlikte Helper.GetRazorViewAsString() method’una gönderilip Result View string’e dönüştürülür. Ve client’lardaki reloadCars() function’ına browser destekliyor ise websocket ile desteklemiyorsa önceden SignalR makalesinde bahsettiğim diğer yöntemler ile push edilir.

HomeController.cs:

 Helper.cs:

View tarafında aşağıda görüldüğü gibi jquery ve signalR.js’ler konur. Bir de signalr/hubs aslında olmayan magic script’i eklenir. GetCars hub classına var messagehub = $.connection.getCars ile connect olunur. <div id=”sahibindenCars”> içine çekilen ilan datalarının gösterildiği SahibindenCars partial view’ı basılır. Ayrıca signalR’a reloadCars()’ şeklinde client script’i tanımlanır. İlanlarda değişim olduğu zaman 30sn de bir çalışan Cloud Servis’i GetCars hub classındaki RefreshCars() methodunu invoke()’ lar.Bu da bağlı olan tüm clientlar’daki reloadCars() scriptini tetikler ve gelen değişmiş data yukarıda bahsedilen sahibindenCars div’ine basılır. SignalR için önceden yazdığım makaleyi inceleyebilirsiniz.

SignalR’ın projede çalışması için öncelikle nuget’den aşadaki package’in indirilmesi gerekir.

signalR

Ayrıca aşağıda görüldüğü gibi StartUp.cs’de app.MapSignalR()’ın configuratin’a eklenmesi gerekir.

Index.cshtml:

 

Sahibinden Banner:

ilan

SahibindenCars partial view’ında aşağıda görüldüğü gibi  yaratılan table içine her 2 kayıtta bir, yeni bir row eklenerek, gelen data model içinde gezilip herbir ilan view’a razor engine ile basılmaktadır. Örnek çıktı yukarıda gözükmektedir.

SahibindenCars.cshtml:

Bu sayfanın client’lara banner olarak verilmesi için writeFrame.js aşağıdaki gibi yazılır.

Clientlar sahibinden banner’ının kendi sayfalarında gözükmesi için; banner’ın çıkmasını istedikleri div’in altına aşadaki gibi yukarıda belirtilen script dosyasını eklemeleri gerekmektedir.

Sonuç olarak yukarıdaki örmekte de görüldüğü gibi, sahibinden sitesi pars edilip son eklenen 6 ilan clientlara frame olarak script yardımı ile basılmaktadır. Yazılan azure cloud veya windows  servis ile ilgili portal 30sn de bir pars edilmekte ve kayıt değişikliği olması durumunda signalR teknolojisi kullanılarak çekilen yeni datalar clientlardaki frame bannerlara pushlanmaktadır. Böylece sayfa refresh olmadan sahibinden sitesindeki son 6 ilan güncel olarak takip edilebilmektedir.

Geldik bir makalenin  daha sonuna.

Yeni bir makalede görüşmek üzere hoşçakalın.

Örnek Banner Url (İptal): http://sahibindenbanner2.azurewebsites.net/?clear=1

Örnek Sayfaya Konucak Script Url(İptal): writeFrame.js

Örnek Source Code: http://www.borakasmer.com/projects/SahibindenWidget.rar

Herkes Görsün:

Bunlar da hoşunuza gidebilir...

2 Cevaplar

  1. Bilal dedi ki:

    Merhaba, Buradaki “ServicePointManager.DefaultConnectionLimit” tam olarak ne anlama geliyor, 13 kişi aynı anda sistemi kuallanamaz mı? Teşekkürler.

  2. borsoft dedi ki:

    Selamlar Bilal;

    Öncelikle DefaultConnectionLimit’in user ile alakası yok. Bu uygulamayı zaten azure üzerindeki bir windows servis olarak düşünürsen tek bir user yani admin user üzerinden işlem yürütülmektedir. DefaultConnectionLimit aynı anda ihtiyaca göre kullanılabilecek cpu sayısını belirtmek için kullanılır Zaten .Net 4.5 ile bu değer default olarak atanmaktadır. Ama ben genede her ihtimale karşı değeri setledim.

    İyi çalışmalar.

Bir cevap yazın

E-posta hesabınız yayımlanmayacak.