Scraping situs mempunyai banyak tujuannya seperti melakukan otomatisasi pengambil URL/Link atau feed tertentu. Algoritma Scraping dilakukan secara rekursif yaitu persatu-satu link akan dikunjungi. Tak heran bila sebuah website bisa berisi ribuan link. Agar Scraping berjalan dengan baik, tentu kita membutuhkan library/tools yang mampu melakukan parsing.
Bila kalian pengguna bahasa Java, saya sarankan menggunakan JSOUP untuk scraping situs. Jsoup adalah perpustakaan Java open-source yang terdiri dari metode yang dirancang untuk mengekstrak dan memanipulasi konten dokumen HTML. Itu ditulis pada tahun 2009 oleh Jonathan Hedley, seorang manajer pengembangan perangkat lunak untuk Amazon Seattle. Jika Anda terbiasa dengan jQuery, kalian tidak akan kesulitan bekerja dengan metode Jsoup. Kegunaan JSoup yaitu
- scrape and parse HTML from a URL, file, or string
- find and extract data, using DOM traversal or CSS selectors
- manipulate the HTML elements, attributes, and text
- clean user-submitted content against a safe white-list, to prevent XSS attacks
- output tidy HTML
Library JSOUP tersedia dari mulai ant, maven, ataupun gradle. Kalian bisa kunjungi https://jsoup.org/download, tapi lebih suka menggunakan gradle saja
// jsoup HTML parser library @ https://jsoup.org/
implementation ‘org.jsoup:jsoup:1.14.3’
Setelah kalian menambahkan kode diatas pada gradle, kita coba saja untuk scraping situs
public class Crawler { public static void main(String[] args) { try { Document doc = Jsoup.connect("https://softscients.com/").get(); Elements links = doc.select("a[href]"); for (Element link : links) { System.out.println("nlink: " + link.attr("href")); } } catch (IOException e) { e.printStackTrace(); } } }
Namun kode diatas hanya menghasilkan scraping terhadap situs alamat situs utama saja. Harusnya kita bisa melakukan semua link yang berada di situs tersebut. Untuk membuat hal tersebut kita butuh sebuah method yang akan dijadikan rekursif. Caranya adalah
- Kita membuat variable array list yang berisi link yang sudah pernah dikunjungi sehingga tidak terjadi looping tak hingga karena looping dialamat yang sama.
- Mendefisiniskan MAIN_HOST yang digunakan untuk mengabaikan alamat website yang lain. Misalkan ketika melakukan scraping link https://softscients.com bila mendapatkan link https://facebook.com, maka situs facebook tidak akan discraping tingkat lanjut hanya sebatas link tersebut saja.
- Membuat extension untuk diabaikan, misalkan URL yang seperti gambar akan diabaikan, header, link comment juga
Saya coba otak-atik kodenya untuk menghasilkan scraping situs secara rekursif. Berikut kode yang saya buat
public class CrawlerRekursif { ArrayList <String> VISITED_URL; String MAIN_URL; String MAIN_HOST; int COUNT_INDEX = 1; public CrawlerRekursif(String url){ try { VISITED_URL = new ArrayList(); this.MAIN_URL=url; MAIN_HOST = new URL(url).getHost(); Thread tr = new Thread(new Runnable(){ @Override public void run() { scrap(url); } }){ }; tr.start(); } catch (MalformedURLException ex) { Logger.getLogger(CrawlerRekursif.class.getName()).log(Level.SEVERE, null, ex); } } /** * @param args the command line arguments */ public static void main(String[] args) { //https://softscients.com/ //http://www.detik.com/ //https://idschool.net/ //https://www.reyneraea.com/ CrawlerRekursif m = new CrawlerRekursif("https://www.reyneraea.com/"); } public void scrap(String f){ try { Document doc = Jsoup.connect(f).userAgent("Mozilla").get(); Elements links = doc.select("a[href]"); if(links.isEmpty()){ return; } ArrayList <String> local_url = new ArrayList(); for (Element link : links) { String lnk = link.attr("href"); //abaikan link yang mengandung image //comment, header, atau link kosong if(!local_url.contains(lnk) & !lnk.equals("") & !lnk.contains("#")&!lnk.contains(".png")&!lnk.contains(".jpg")&!lnk.contains(".jpeg")&!lnk.contains(".xlsx")&!lnk.contains("tag")&!lnk.contains(".csv")&!lnk.contains("category")){ String host = new URL(lnk).getHost(); //jika link tersebut milik HOST, lanjutkan saja if(host.equals(MAIN_HOST) & !lnk.equals(MAIN_URL)){ local_url.add(lnk); if(!VISITED_URL.contains(lnk)){ //masukan link jika belum pernah dikunjungi System.out.println("\t"+COUNT_INDEX+" : "+lnk); COUNT_INDEX++; VISITED_URL.add(lnk); scrap(lnk); } } } Thread.sleep(100); } } catch (IOException e) { } catch (InterruptedException ex) { Logger.getLogger(CrawlerRekursif.class.getName()).log(Level.SEVERE, null, ex); } } }
Melalui kode diatas Scraping Situs akan sangat mudah dan menghasilkan semua link yang berada pada MAIN_HOST dan menghasilkan Scraping Situs Secara Rekursif
Menyimpan hasil scraping ke database
Tidak lengkap rasanya bila hasil scraping yang banyak tidak disimpan dalam bentuk database. Nah kita bisa menggunakan sqlite saja. Kalian tambahkan saja kode di gradle untuk sqlitenya
implementation ‘org.xerial:sqlite-jdbc:3.30.1’
Kode dibawah ini sudah agak beda dengan kode diatas untuk penamaan variabelnya agar sesuai dengan fungsi / tujuaanya. Berikut kode lengkap untuk menyimpan hasil scraping ke database
public class CrawlerRekursif { ArrayList <String> VISITED_URL; String MAIN_URL; String MAIN_HOST; int COUNT_INDEX = 1; Connection conn = null; PreparedStatement pstmt; public CrawlerRekursif(String url){ try { String db = "jdbc:sqlite:D:/softcsients.db"; // create a connection to the database conn = DriverManager.getConnection(db); System.out.println("Connection to SQLite has been established."); // SQL statement for creating a new table String sql = "CREATE TABLE IF NOT EXISTS link (\n" + " id integer PRIMARY KEY,\n" + " name text NOT NULL, \n" + " error text \n" + ");"; Statement stmt = conn.createStatement(); // create a new table stmt.execute(sql); String insert = "INSERT INTO link (name,error) VALUES(?,?)"; pstmt = conn.prepareStatement(insert); VISITED_URL = new ArrayList(); this.MAIN_URL=url; MAIN_HOST = new URL(url).getHost(); Thread tr = new Thread(new Runnable(){ @Override public void run() { scrap(url); } }){ }; tr.start(); } catch (MalformedURLException ex) { Logger.getLogger(CrawlerRekursif.class.getName()).log(Level.SEVERE, null, ex); } catch (SQLException e){ } } /** * @param args the command line arguments */ public static void main(String[] args) { //https://softscients.com/ //http://www.detik.com/ //https://idschool.net/ //https://www.reyneraea.com/ CrawlerRekursif m = new CrawlerRekursif("https://softscients.com/"); } public void scrap(String f){ try { Document doc = Jsoup.connect(f).userAgent("Mozilla").get(); Elements links = doc.select("a[href]"); if(links.isEmpty()){ return; } ArrayList <String> local_url = new ArrayList(); for (Element link : links) { String lnk = link.attr("href"); //abaikan link yang mengandung image //comment, header, atau link kosong if(!local_url.contains(lnk) & !lnk.equals("") & !lnk.contains("#") & !lnk.contains(".png") & !lnk.contains(".jpg") & !lnk.contains(".jpeg") & !lnk.contains(".bmp") & !lnk.contains(".xlsx") & !lnk.contains(".xls") & !lnk.contains(".txt") & !lnk.contains(".docx") & !lnk.contains(".rar") & !lnk.contains(".gif") & !lnk.contains(".zip") & !lnk.contains("tag") & !lnk.contains("page") & !lnk.contains(".csv") & !lnk.contains("category")){ String host = new URL(lnk).getHost(); //jika link tersebut milik HOST, lanjutkan saja if(host.equals(MAIN_HOST) & !lnk.equals(MAIN_URL)){ local_url.add(lnk); if(!VISITED_URL.contains(lnk)){ //masukan link jika belum pernah dikunjungi pstmt.setString(1,lnk); //tambahkan ke db pstmt.setString(2,""); //tambahkan ke db pstmt.executeUpdate(); System.out.println("\t"+COUNT_INDEX+" : "+lnk); COUNT_INDEX++; VISITED_URL.add(lnk); scrap(lnk); } } } Thread.sleep(10); } } catch (IOException e) { } catch (InterruptedException ex) { Logger.getLogger(CrawlerRekursif.class.getName()).log(Level.SEVERE, null, ex); }catch (SQLException e) { System.out.println(e.getMessage()); } } }
Kode diatas sudah saya coba untuk scraping situs, 100% link akan ter extract dengan baik! Untuk kodenya bisa kalian peroleh di https://github.com/mulkan/scrapingsitus