Android Jsoup ile HTML Parsing

Merhaba arkadaşlar,  Bugün sizlere Jsoup kütüphanesi kullanımı ile HTML parse işleminin nasıl gerçekleştirileceğini anlatacağım. HTML Parse , HTML ayrıştırma anlamına gelmektedir.   Herhangi bir Html sayfasından istediğimiz yerleri alabilir ve uygulamalarımızda kullanabiliriz. Örneğin web sitemizi , mobil uygulamaya dönüştürmek istiyoruz diyelim; web sitemizin html sayfasında bulunan tag leri ayrıştırarak verileri elde ederiz, bunu da uygulamamızda şekillendiririz.

Jsoup ise Java programlama diline ait açık kaynak kodlu html parser kütüphanesidir. Html element lerine ulaşmamız için bu kütüphaneyi kullanacağız , bu kütüphaneyi kullanabilmek için de projemize import etmemiz gerekiyor.

http://www.mobilhanem.com sitemizden bir kaç veri çekip uygulamamızda gösterelim Android Studio yu açıyoruz Gradle Scripts segmesinden build.gradle a aşağıdaki kodu yapıştırıyoruz, yapıştırdıktan sonra uygulamanızı  Rebuild project yapmayı unutmayın. Android Studio arka planda derleme işlemlerini tamamladıktan sonra artık Jsoup kütüphanemizi kullanabilir duruma geleceğiz.

compile 'org.jsoup:jsoup:1.7.3'

Az çok web sayfası kavramından anlayanlarımız bilir ki html tag larını oluştururken id ler kullanabiliriz yada class tag ı vererek onun içinde şekillendirmeler yapabiliriz. Jsoup kütüphanesinin mantığı ise , istenilen url ye bağlantıyı gerçekleştirip , select komutu ile html tag lerine ulaşarak verileri elde etmemizi sağlamaktır. Internet üzerinden bu verilere ulaşmak istediğimiz için Async Task yapısını kullanacağız. Nasıl Json Parse işlemlerinde bu yapıyı kullanıyorsak, Html Parse yaparken de bu yapıyı kullanmamız doğru olacaktır.

url ye bağlantıyı şu şekilde sağlayacağız.

Document doc  = Jsoup.connect(URL).get();

URL yazan kısma ulaşmak istediğimiz web sayfasının linkini vermemiz yeterli.

Daha sonra Html elemanlarına ulaşabilmek için belli başlı select komutları var onlardan ihtiyacımız olanları kullanacağız. Daha detaylı komutlara bakmak için tıklayınız.

html <div id=”yourDivName”> tag lerine ulaşabilmek için “#” kullanarak aşağıdaki gibi yazıyoruz.

Elements info = doc.select("div#yourDivName");

Elements info = doc.select("div[id=yourDivName"); // alternatif olarak bunuda kullanabilirsiniz.

html <div class=”yourClassName”> tagıne ulaşabilmek için “.” kullanarak aşağıdaki gibi yazıyoruz.

Elements info = doc.select("div.yourClassName");

Elements info = doc.select("div[class=yourClassName"); // alternatif olarak bunuda kullanabilirsiniz.

Yayınlamış olduğum Parse SDK ile Anlık Bildirim dersi sayfasından verileri çekeceğiz. Burada yer alan site başlığını , açıklamasını ve sitemizin logosunu çekmeye çalışalım. Uygulamamızda 4 adet buton bulunuyor. Bu butonların ne işe yaradığını kaynak kodların içinde yorum olarak belirttim.

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent"  tools:context=".MainActivity">


    <LinearLayout
        android:orientation="vertical"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:id="@+id/linearLayout">

        <Button
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="Başlık Göster"
            android:id="@+id/buttonTitle" />

        <LinearLayout
            android:visibility="gone"
            android:id="@+id/title_layout"
            android:orientation="horizontal"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content">

            <TextView
                android:textStyle="bold"
                android:id="@+id/txt_title"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content" />


        </LinearLayout>

        <Button
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="Açıklama Göster"
            android:id="@+id/buttonDesc" />

        <LinearLayout
            android:visibility="gone"
            android:id="@+id/desc_layout"
            android:orientation="horizontal"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content">


            <TextView
                android:textStyle="bold"
                android:id="@+id/txt_desc"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content" />


        </LinearLayout>

        <Button
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="Logo Göster"
            android:id="@+id/buttonImage" />

        <LinearLayout
            android:visibility="gone"
            android:id="@+id/logo_layout"
            android:orientation="horizontal"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content">

            <ImageView
                android:background="#0000ff"
                android:id="@+id/img_logo"
                android:layout_width="fill_parent"
                android:layout_height="100dp" />


        </LinearLayout>

        <Button
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="Yazarlar Göster"
            android:id="@+id/buttonYazarlar" />

        <LinearLayout
            android:visibility="gone"
            android:id="@+id/yazarlar_layout"
            android:orientation="horizontal"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content">


            <TextView
                android:textStyle="bold"
                android:id="@+id/txt_yazarlar"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content" />


        </LinearLayout>
    </LinearLayout>


</RelativeLayout>

 

MainAcitivity sınıfımız aşağıdadır.

MainActivity.java

package com.mobilhanem.htmlparsingandroid;

import android.app.Activity;
import android.app.ProgressDialog;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.io.InputStream;


public class MainActivity extends Activity {

    private Button titleButton, descButton, logoButton, yazarlarButton;
    LinearLayout title_layout, desc_layout, logo_layout, yazarlar_layout;
    private ProgressDialog progressDialog;
    private static String URL = "http://www.mobilhanem.com/parse-sdk-ile-anlik-bildirim-gonderme-push-notification/";
    private static String baseUrl = "http://www.mobilhanem.com/";
    private static String authorUrl = "http://www.mobilhanem.com/yazarlar/";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        titleButton = (Button)findViewById(R.id.buttonTitle);
        descButton = (Button)findViewById(R.id.buttonDesc);
        logoButton = (Button)findViewById(R.id.buttonImage);
        yazarlarButton = (Button)findViewById(R.id.buttonYazarlar);

        titleButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                new FetchTitle().execute(); // başlık çekmek için
            }
        });

        descButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                new FetchDescription().execute(); // açıklama çekmek için
            }
        });

        logoButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                new FetchImageLogo().execute();  // logo çekmek için
            }
        });

        yazarlarButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                new FetchYazarlar().execute();    // yazarlar kısmını çekmek için
            }
        });

    }
    private class FetchTitle extends AsyncTask<Void, Void, Void> {

        String title;
        @Override
        protected void onPreExecute() {
            super.onPreExecute();

            progressDialog = new ProgressDialog(MainActivity.this);
            progressDialog.setTitle("BAŞLIK");
            progressDialog.setMessage("Başlık Çekiliyor...");
            progressDialog.setIndeterminate(false);
            progressDialog.show();
        }

        @Override
        protected Void doInBackground(Void... params) {

            try{

                Document doc  = Jsoup.connect(URL).get();    // web siteye bağlantıyı gerçeleştirme

                title = doc.title();  // ilgili sayfanın başlığını almak için

            }catch (Exception e){

                e.printStackTrace();
            }


            return null;
        }

        @Override
        protected void onPostExecute(Void aVoid) {

            title_layout = (LinearLayout)findViewById(R.id.title_layout);
            TextView txt_title = (TextView)findViewById(R.id.txt_title);
            title_layout.setVisibility(View.VISIBLE);
            txt_title.setText("Title: " + "" + title);
            progressDialog.dismiss();
        }
    }

    private class FetchDescription extends AsyncTask<Void, Void, Void> {

        String desc;
        @Override
        protected void onPreExecute() {
            super.onPreExecute();

            progressDialog = new ProgressDialog(MainActivity.this);
            progressDialog.setTitle("AÇIKLAMA");
            progressDialog.setMessage("Açıklama Çekiliyor...");
            progressDialog.setIndeterminate(false);
            progressDialog.show();
        }

        @Override
        protected Void doInBackground(Void... params) {

            try{

                Document doc  = Jsoup.connect(URL).get();
                Elements elements = doc.select("meta[name=description]");  // ilgili sayfanın açıklamasını almak için
                desc = elements.attr("content");


            }catch (Exception e){

                e.printStackTrace();
            }


            return null;
        }

        @Override
        protected void onPostExecute(Void aVoid) {

            desc_layout = (LinearLayout)findViewById(R.id.desc_layout);
            TextView txt_desc = (TextView)findViewById(R.id.txt_desc);
            desc_layout.setVisibility(View.VISIBLE);
            txt_desc.setText("Description: " + "" + desc);
            progressDialog.dismiss();
        }
    }

    private class FetchImageLogo extends AsyncTask<Void, Void, Void> {

        Bitmap bitmap;

        @Override
        protected void onPreExecute() {
            super.onPreExecute();

            progressDialog = new ProgressDialog(MainActivity.this);
            progressDialog.setTitle("LOGO");
            progressDialog.setMessage("Logo Çekiliyor...");
            progressDialog.setIndeterminate(false);
            progressDialog.show();
        }

        @Override
        protected Void doInBackground(Void... params) {

            try{

                Document doc  = Jsoup.connect(baseUrl).get();
                Elements elements = doc.select("img[src]");
                String imgSrc = elements.attr("src");
                InputStream input = new java.net.URL(imgSrc).openStream();
                bitmap = BitmapFactory.decodeStream(input);

            }catch (Exception e){

                e.printStackTrace();
            }


            return null;
        }

        @Override
        protected void onPostExecute(Void aVoid) {

            logo_layout = (LinearLayout)findViewById(R.id.logo_layout);
            ImageView img_logo = (ImageView)findViewById(R.id.img_logo);
            logo_layout.setVisibility(View.VISIBLE);
            img_logo.setImageBitmap(bitmap);
            progressDialog.dismiss();
        }
    }

    private class FetchYazarlar extends AsyncTask<Void, Void, Void> {

        String authors;
        @Override
        protected void onPreExecute() {
            super.onPreExecute();

            progressDialog = new ProgressDialog(MainActivity.this);
            progressDialog.setTitle("YAZARLAR");
            progressDialog.setMessage("Yazarlar Çekiliyor...");
            progressDialog.setIndeterminate(false);
            progressDialog.show();
        }

        @Override
        protected Void doInBackground(Void... params) {

            try{

                Document doc  = Jsoup.connect(authorUrl).get();
                Elements elements = doc.select("div[class=post-content]");  // class ismi post-content olan verileri çekmek için
                authors = elements.text();

            }catch (Exception e){

                e.printStackTrace();
            }


            return null;
        }

        @Override
        protected void onPostExecute(Void aVoid) {

            yazarlar_layout = (LinearLayout)findViewById(R.id.yazarlar_layout);
            TextView txt_yazarlar = (TextView)findViewById(R.id.txt_yazarlar);
            yazarlar_layout.setVisibility(View.VISIBLE);
            txt_yazarlar.setText(authors);
            progressDialog.dismiss();
        }
    }
}

MainActivity sınıfımızda yer alan kodları incelemeye başlayalım. Uygulamayı çalıştırdığınız zaman göreceksiniz ki ilk butona tıklandığı an ilgili sayfanın başlığını çekip ekrana yazdırıyoruz. Bunu FetchTitle ismini verdiğim methodu incelersek eğer Async Task yapısında bildiğiniz üzere ilk olarak onPreExecute methodu çalışıyor orada kullanıcıya mesajı gösteriyoruz ve hemen ardından çalışan doInBackground methodu ile ilgili url ye bağlanıyoruz. ( http://www.mobilhanem.com/parse-sdk-ile-anlik-bildirim-gonderme-push-notification/ )  bu sayfamızda çekmeye çalıştığımız başlık kısmına sayfanın source-code nu görüntüleyerek bakarsak eğer ; resimde de görüldüğü gibi title kısmında yer alan yazıyı onPostExecute methodunda TextView e yazdırdık.

resim_title

İkinci butona tıklandığı zaman ise FetchDescription isimli method çalışarak; ilgili sayfanın açıklaması çekilip ekrana yazdırılıyor. Yukarıda anlatmış olduğum yapı burası içinde geçerli bu yüzden tekrardan aynı şeylerden bahsetmeyeceğim. meta tagında yer alan description un content değişkenine  ulaştıktan sonra bunu TextView e yazdırıyoruz. Bu veriyi çektiğimiz ilgili sayfanın html görüntüsüne bakacak olursak ;

img_desc

Üçüncü butona tıklandığı zaman ise FetchImageLogo isimli method çalışarak; ilgili sayfanın logo su çekilip ekranda gösteriliyor. Bu dersimizin kaynak kodunu incelerseniz eğer, başka bir url segmesine bağlantıyı gerçekleştirdiğimi göreceksiniz. Burada ilgili web sayfalarının farklı kısımlarına da ulaşabileceğimizi göstermek istedim. Sayfanın logo sunu çekerken img[src] ifadesini kullandığımı göreceksiniz burada sayfanın kaynak resim dosyasını çekebilmemiz için gerekli olan bu kodu kullanarak, çekilen veriyi önce Bitmap e çevirip daha sonra ImageView e set ettik.  Logo yu çektiğimiz ilgili sayfanın html görüntüsüne bakacak olursak ;

 

img_logo_new

ve son olarak dördüncü butona basıldığında FetchYazarlar methodunu çağırdık burada yine ilgili web sitesinin başka bir sayfasına bağlantıyı gerçekleştirdik ve yazarlar bölümünü çekip ekrana yazdırdık. Zaten bağlantıyı kurduğumuz url yi görüntüleyecek olursanız class adının post-content verildiğini göreceksiniz, div[class=post-content] komutunu kullanarak gerekli işlemleri gerçekleştirdik. Yazarlar kısmını çektiğimiz ilgili sayfanın html görüntüsüne bakacak olursak ;

img_yazarlar

Html parse nasıl yapılır böylece sizlere göstermiş oldum, gerçekten çok kullanışlı ve  biraz html bilginiz var ise bunu Android ile birleştirip işinize yarayabilecek işlemleri kolayca gerçekleştirebilirsiniz. Jsoup mantığını ilerletmek istiyorsanız eğer uygulamalarınızda kullanmadan önce online-tool kullanarak alıştırmalar yapabilirsiniz.     ( http://try.jsoup.org/~iayWCMYVlvXEUrAws7ziRaMU3bM ) Kullanmak istediğiniz web sayfasına gelip sağ tıklayarak Inspect Element deyin ve html kodlarını seçip bu online-tool a yapıştırın. Daha sonrasında Jsoup daki Select komutlarını kullanmaya çalışın gerçekten çok işinize yaradığını göreceksiniz.

Tüm Android Ders, Proje ve Kaynak Kodlar için tıklayınız.

Ders hakkında soru ve önerilerinizi çekinmeden yorum bırakabilirsiniz. Bol Android’li günler sizin olsun :)

Sizlerden ricamız facebook.com/mobilhanem sayfamızı beğenmenizdir. Diğer dersimde görüşmek üzere kendinize iyi bakın..

5

Alper Beyler

Yüksek Lisans: Çankaya Üniversitesi / Bilgisayar Mühendisliği
Lisans: Çankaya Üniversitesi / Bilgisayar Mühendisliği (4/3.30) (2010-2014)
Lisans : Viyana Teknik Üniversitesi / Bilgisayar Bilimleri (2013)

39 Yorum

  • uzun bir aradan sonra yeni ders eklenmiş. gerçekten faydalı bir yazı olmuş teşekkürler

  • merhaba hocam benim bir uyglama oluşturdm webview birkaç menü ekledim fakat webview sayfa kaynak kodunu view-source kodlarını göstermiyor.aslında yapmak istedigim şu webviev da herhangi bir linkle tıklandıgında o linki otomatik kopyalamak yardımcı olursanız sevinirim.

  • merhaba hocam Document doc değeri debug esnasında sürekli null dönüyor bunun sebebi ne bir çözüm bulamadım cevaplarsanız sevinirim

    • bu dersin kaynak kodlarını indirip denediğinizde mi null geliyor ? null gelmemesi lazım bu yazdığım derste verileri düzgün basıyor ekrana. internet ayarları yada verdiğiniz url yi kontrol eder misiniz

  • Merhaba sizin jsoup dersinizi inceledim elinize sağlıkyalnız form elementi nasıl çekilir bulamadım. textbox button filan yardımcı olabilir misiniz ?

    • merhabalar, formElement.select(“input[name=id]”).first() bu yapıda bir kod kullanmanız gerekmektedir form elementini çekebilmeniz için

      yukarıdaki örnek yapıya baktığımızda formElement.attr(“action”) dediğimizde deneme.php yı getirmesi gerekiyor. Verdiğim örnekleri dener misiniz ayrıca daha detaylı bilgi edinmek istersen jsoupun kendi sitesini incelemeni tavsiye ederim. ( http://jsoup.org/cookbook/extracting-data/dom-navigation )

  • HTML sayfasında birden çok title etiketine sahip veri varsa eğer, bu
    durumda Android uygulaması HTML sayfasındaki tüm title içeriklerini mi
    alıyor yoksa sadece HTML sayfasında ilk önce title etiketinin içeriğini
    alıp, diğerlerini almıyor mu? Bu sorunun cevabına ciddi anlamda çok
    ihtiyacım var.

    • Merhabalar,
      Document doc = Jsoup.connect(URL).get();
      title = doc.title(); // burada url sini verdiğiniz ilgili web sayfasının başlığı ne ise onu alıyoruz bütün hepsini çekmiyor

  • resimleri çekmiyo yukarda gösterilen gibi yaptım ama olmuyo bi yardımcı olursanız sevinirim

  • S.a
    Anlatım için teşekkür ederim çok yardımcı oldu.
    Bir sorum olacaktı;
    ben logo çeker gibi yüklenen sayfanın içindeki linkleri almak istiyorum.
    bunun için ;
    Elements elements = doc.select(“a[href]”);
    title = elements.attr(“href”);
    şeklinde kullandım ve sayfanın içindeki ilk linki alıyorum fakat bütün linkleri almak için döngü içine almam gerek .Sayfa içindeki bütün linkleri alıp istediğim link adresini bulunca click yaptırtmak istiyorum yardımcı olabilirmisiniz ?
    Şimdiden teşekkür ederim.İyi çalışmalar.

  • Merhabalar, Ben wp sitenin belli bir tag aralığını resimleriyle birlikte css kodları ve javascript kodları çalışacak şekilde nasıl çekebilirim ?
    Hızlı çekmek için en iyi yöntem nedir. Teşekkür ederim

      • Siz beni anlamadınız sanırım. Tmm yukardaki örnek de bunu anlatıyor ama şöyle bir durum var; Ben belirttiğim tag arasındaki sadece yazıyı veya sadece resimi almak yerine ikisini de aynı anda almak istiyorum. Mesela div class.haberler olan taglarımı bir döngü yardımıyla kaç haber varsa o haberler hakkında tüm veriyi çekmek istiyorum ama bazılarında video olabilir olmayabilir de. Bunu nasıl ayarlayabilirim? Anlatabildim mi?

  • Merhabalar, kaynak kodlarını almak istediğim site girişte şifre ile destekli , bu şifre alanını nasıl doldurup asıl sayfa kaynak dosyasına ulaşabilirim yardımcı olursanız çok sevinirim..

  • internet bağlantısının olmadığı lokal netwroklerde kullanabiliyor muyuz jsoup u ? Çekeceğim veri tamamen xml’den oluşmakta. Jsoup internet bağlantısı olmayan local networklerde kullanılamıyorsa, başka bir tavsiyeniz var mı?

    • Merhaba ne yazık ki kullanamazsınız internet bağlantısı olması gerekiyor. burada da sizin sorduğunuz soruyu sormuşlar incelemeniz faydalı olacaktır.

      • Size sorduktan sonra denedim, internet bağlantısı olmadan da çekti. Ama Siz böyle cevap verince bi şaşırdım. Neden çektiğini araştırıyorum şuan =)

  • Ben Sitedeki dersleri çekmek istiyorum ve dersler video direk videonun başka bir pencere açmadan aynı pencerede izlemesini istiyorum bunu nasıl yapa bilirim lütfen yardımcı olurmusunuz

  • Hocam çok iyi anlatım teşekkür ederim. Peki login yapılması gereken sayfalarda ne yapmamız gerekiyor ?

  • merhaba ,genelde parse işlemlerinde web servis yazılıyormuş.Biarkaç araştırmama göre json formatında veriler çekiliyormuş.örneğin bir yemek listesini çekmek istiyorum .ama json formatında değil.ne yapmam lazım ?ikinci olarak json dosyasını sunucuda barındırmak gerekiyomuş.İlla bir sunucu mu kiralamam lazım en basit işler için biler ?

Haftalık Bülten

Mobilhanem'de yayınlanan dersleri haftalık mail almak ister misiniz?