Merhabalar,


Bu yazıda Android'de Jsoup kütüphanesi kullanımını ve bir web sitesi üzerindeki Html'i Parse etme işlemini anlatacağım. Jsoup bir Java kütüphanesi olduğu için bu işlemi Java diliyle gerçekleştirmek daha uygun olacaktır. Ancak elbette ki isterseniz Kotlin ile de bu işlemi gerçekleştirebilirsiniz.


Örnek projede Bursa'daki nöbetçi eczaneleri ekranda göstereceğiz. Bu projeyi Github üzerinden paylaştım. İndirip inceleyebilirsiniz.


Örnek proje linki


İlk olarak build.gradle dosyasını açıp gerekli kütüphaneleri projeye ekliyoruz ve Sync'e basıyoruz. Ben Jsoup'un yanı sıra, tasarım kısmında CardView kullanmak istediğim için CardView kütüphanesini de ekledim:

implementation 'org.jsoup:jsoup:1.10.3'
implementation 'com.android.support:cardview-v7:28.0.0'


activity_main.xml dosyasını açıp tüm ekranı kaplayacak şekilde bir ListView yerleştiriyoruz:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <ListView
        android:id="@+id/lvPharmacy"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    </ListView>

</LinearLayout>


ListView'de bulunan her bir elemanı (item) temsil etmesi için item_pharmacy.xml adında bir layout dosyası oluşturuyoruz. Eczanenin adını, adresini ve telefonunu göstereceğiz. Adres ve telefon kısmı için kullanmış olduğum ikonları Github reposundan bulabilirsiniz.


item_pharmacy.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="top"
    android:orientation="horizontal">

    <android.support.v7.widget.CardView
        card_view:cardCornerRadius="0dp"
        card_view:cardUseCompatPadding="true"
        android:layout_height="wrap_content"
        android:layout_width="match_parent">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:paddingLeft="5dp">

            <TextView
                android:id="@+id/tvPharmacyName"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:textAppearance="?android:attr/textAppearanceMedium"
                android:textColor="#e74c3c" />

            <TextView
                android:id="@+id/tvPharmacyAddress"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:drawableLeft="@drawable/ic_location"
                android:gravity="center_vertical"
                android:textAppearance="?android:attr/textAppearanceSmall"
                android:textColor="#000" />

            <TextView
                android:id="@+id/tvPharmacyPhone"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:drawableLeft="@drawable/ic_call"
                android:gravity="center_vertical"
                android:textAppearance="?android:attr/textAppearanceSmall"
                android:textColor="#000" />

        </LinearLayout>

    </android.support.v7.widget.CardView>

</LinearLayout>


Veri modelimizi belirtmek adına model dosyamızı oluşturuyoruz.


PharmacyModel.java:

package com.yusufborucu.htmlparsesample;

public class PharmacyModel {
    private String name;
    private String address;
    private String phone;

    public PharmacyModel(String name, String address, String phone) {
        this.name = name;
        this.address = address;
        this.phone = phone;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    @Override
    public String toString() {
        return name + address + phone;
    }
}


Gelen verileri işleyerek ekrandaki ListView nesnesinde göstermek adına adapter dosyamızı oluşturuyoruz.

PharmacyAdapter.java:

package com.yusufborucu.htmlparsesample;

import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

import java.util.List;

public class PharmacyAdapter extends BaseAdapter {

    private Context context;
    private List<PharmacyModel> rowItems;

    public PharmacyAdapter(Context context, List<PharmacyModel> items) {
        this.context = context;
        this.rowItems = items;
    }

    private class ViewHolder {
        TextView txtName;
        TextView txtAddress;
        TextView txtPhone;
    }

    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder;

        LayoutInflater mInflater = (LayoutInflater) context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);

        if (convertView == null) {
            convertView = mInflater.inflate(R.layout.item_pharmacy, null);
            holder = new ViewHolder();
            holder.txtName = convertView.findViewById(R.id.tvPharmacyName);
            holder.txtAddress = convertView.findViewById(R.id.tvPharmacyAddress);
            holder.txtPhone = convertView.findViewById(R.id.tvPharmacyPhone);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }

        final PharmacyModel rowItem = (PharmacyModel) getItem(position);

        holder.txtName.setText(rowItem.getName());
        holder.txtAddress.setText(rowItem.getAddress());
        holder.txtPhone.setText(rowItem.getPhone());

        return convertView;
    }

    @Override
    public int getCount() {
        return rowItems.size();
    }

    @Override
    public Object getItem(int position) {
        return rowItems.get(position);
    }

    @Override
    public long getItemId(int position) {
        return rowItems.indexOf(getItem(position));
    }
}


Yararlanacağımız web sitesi url'si: https://www.nobetcieczanebul.com/bursa-nobetci-eczane

Eczane verilerinin bulunduğu Html içeriği:

<div class="col-lg-6 col-md-6 col-sm-6 col-xs-12">
    <div class="panel panel-default ecz">
        <div class="panel-heading" style="background-color:#E0E3D6;">Alagöz Eczanesi - <strong>Nilüfer</strong></div>
        <div class="panel-body">Çamlıca Mah. Kavakdere Cad. No:150/B-B (Çamlıca Asm Karşısı) Nilüfer/Bursa <b>© (18:30-08:30&nbsp;) Açık</b>
            <br>
            <br>Tel : 0 224 453 55 75&nbsp;&nbsp;&nbsp;&nbsp;<a href="/bursa/469/Nilüfer/Alagöz-Eczanesi" target="_blank"><strong style="color:#2554C7;">HARiTA</strong></a>
      	</div>
    </div>
</div>


Gördüğünüz üzere her bir eczane verisi "col-sm-6" class'ı bulunan div'lerin içinde verilmiş. Eczanenin adı "panel-heading", adres ve telefon bilgileri ise "panel-body" içerisinde mevcut. Ufak bir hesaplama, substring ve indexOf kullanımı ile verilere kolayca ulaşabiliriz.


Şimdi artık asıl işleme geçelim. Bir web sitesi üzerinden Html Parse işlemi yapacağımız için bu işlemi arkaplanda yürütmek ve bu sırada kullanıcıya bilgi vermek en sağlıklı yöntem olacaktır. Bu yüzden AsyncTask ve ProgressDialog kullanacağız. PharmacyTask.java adında bir dosya oluşturup içeriğini şu şekilde dolduruyoruz:

package com.yusufborucu.htmlparsesample;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

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

import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;

public class PharmacyTask extends AsyncTask<Void, Void, Void> {

    private ProgressDialog pd;
    private Context context;
    private List<PharmacyModel> pharmacyItems;
    public static String pharmacy;

    public PharmacyTask(Context context) {
        this.context = context;
        pharmacyItems = new ArrayList<>();
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        pd = new ProgressDialog(context);
        pd.setMessage("Lütfen bekleyiniz...");
        pd.setIndeterminate(false);
        pd.setCancelable(false);
        pd.show();
    }

    @Override
    protected Void doInBackground(Void... params) {
        // TODO Auto-generated method stub
        String address, phone;
        Document doc;
        String url = "https://www.nobetcieczanebul.com/bursa-nobetci-eczane";

        try {
            pharmacyItems.remove(pharmacyItems);
            doc = Jsoup.connect(url).ignoreContentType(true).get();
            for (Element row : doc.select("div.col")) {
                Elements header = row.select("div.card-header");
                Elements body = row.select("div.card-body");
                address = body.text().substring(0, body.text().indexOf("Harita"));
                phone = body.text().substring(body.text().indexOf("Tel :") + 6, body.text().indexOf("Tel :") + 21);
                PharmacyModel item = new PharmacyModel(header.text(), address, phone);
                pharmacyItems.add(item);
                pharmacy = header.text();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    protected void onPostExecute(Void result) {
        pd.dismiss();
        PharmacyAdapter adapter = new PharmacyAdapter(context, pharmacyItems);
        MainActivity.lvPharmacy.setAdapter(adapter);
    }

}

Burada şu işlemleri yaptık:

  • onPreExecute fonksiyonunda ProgressDialog nesnesini hazırlayıp çalıştırdık. Böylece kullanıcıya "Lütfen bekleyiniz..." mesajı vermiş olduk.
  • doInBackground fonksiyonunda ilgili web sitesinin içeriğini alıp Jsoup kütüphanesi yardımıyla Html Parse işleminden geçirdik. Elde ettiğimiz verileri önceden belirtmiş olduğumuz veri modeli şeklinde listemize aktardık.
  • onPostExecute fonksiyonunda ProgressDialog nesnesini durdurduk ve önceden belirtmiş olduğumuz adapter aracılığıyla verilerimizi ekrana bastırdık.


Son olarak MainActivity.java dosyamızın onCreate fonksiyonunda, oluşturmuş olduğumuz AsyncTask'ı çalıştırıyoruz:

package com.yusufborucu.htmlparsesample;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ListView;

public class MainActivity extends AppCompatActivity {

    public static ListView lvPharmacy;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        lvPharmacy = findViewById(R.id.lvPharmacy);

        new PharmacyTask(this).execute();
    }
}


Tabii ki AndroidManifest.xml dosyamızı açıp internet iznini vermeyi de unutmuyoruz :)

<uses-permission android:name="android.permission.INTERNET"/>


Uygulamamızın ekran görüntüsü şu şekilde olacaktır:


İyi çalışmalar.