Hackyo’s Update — Week 9

Haryo Akbarianto Wibowo
Inspire Crawler
Published in
8 min readApr 24, 2016

Introduction

Kembali bersama saya Haryo A W. Dikesempatan ini saya akan memberitahukan lagi apa saja yang sudah saya kerjakan selama seminggu ini. Tidak sedikit, namun tidak banyak juga, itulah yang saya kerjakan selama seminggu ini.

What I Have Done

Untuk minggu ini, berikut list-list yang sudah saya kerjakan sesuai dengan user stories:

  1. Refactor Crawler + Documentation
  2. Add functional Mongo database to Crawler
  3. Integrate local laravel to MongoLabs
  4. API Documentation + Preview/Sample

Refactor Crawler + Documentation

Disini saya melakukan refactoring besar-besaran terhadap code-code yang sudah di code oleh teman-teman saya. Karena dokumentasi yang dibuat masih minim dan dokumentasi source code crawler ini nantinya akan ditaruh didalam website (Tugas Alief), maka diperlukan dokumentasi terhadap source codenya.

Refactor Class QuoteFilter

Class ini pada sprint sebelumnya dikerjakan oleh saya dan diedit oleh Alief Aziz. Karena ada class yang tidak digunakan (SentenceIdentifier), maka class tersebut saya hapus dan saya hilangkan dari source tersebut.

- SentenceIdentifier sen = new SentenceIdentifier(); //TIDAK DIPAKAI
- String result = sen.partialIdentify(hasilTag);
+ String result = sentenceTagger.partialIdentify(hasilTag);

Refactor Class SentenceTagger

Class ini pertama kali dibuat oleh Alief Aziz dan di tambah-tambahkan oleh saya. Sebelumnya, import class didalam class ini menggunakan * dimana import ini tidak baik. Oleh karena itu, saya ganti * dengan class yang benar-benar dipakai.

-import java.io.*;
-import java.util.*;
+import java.io.FileReader;
+import java.io.IOException;
+
+import java.util.List;
+import java.util.Properties;
import java.util.regex.Pattern;

import edu.stanford.nlp.ie.AbstractSequenceClassifier;
import edu.stanford.nlp.ie.crf.CRFClassifier;
import edu.stanford.nlp.ling.CoreAnnotations;
import edu.stanford.nlp.ling.CoreLabel;
+import org.json.simple.parser.ParseException;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;

Ada temporary file yang tidak digunakan sama sekali dan variabel yang tidak akan dipakai, didalam sini saya hapus

- private final String serializedClassifier = “model/english.all.3class.distsim.crf.ser.gz”;
private AbstractSequenceClassifier classifier;
- String tempFilename = “json.txt”;

Lalu saya taruh nama file yang sebenarnya akan digunakan oleh kami dengan access modifier private.

+private static final String serializedClassifier = “model/english.all.3class.distsim.crf.ser.gz”;

Lalu saya mengubah Exception yang di throws dari Exception menjadi IOException dan lain sebagainya.

- // w.close();
- }catch(Exception e){
- System.out.println(“Error”);
+
+ }catch(IOException e){
+ System.out.println(“IO Error”);
+ e.printStackTrace();
+ }catch(ParseException e){
+ System.out.println(“Error on parse”);

Terakhir, pada class ini, saya lakukan dokumentasi. Contoh Dokumentasi:

/** * This class is used to parse the text and tag NER * @author haryoaw and alief

Refactor Class TreeNode

Class ini dibuat oleh Alieff dan direfactor oleh saya. Saya hanya menghilangkan comment-comment dan menghapus hal-hal yang tidak diperlukan. Selain itu, saya lakukan dokumentasi method.

Refactor Class ConfigReader

Class ini dibuat oleh Kevin Ega Pratama. Disini, classnya banyak melakukan hal-hal yang tidak berguna (casting yang tidak perlu misalnya), berikut adalah perubahannya:

-package main;/*
- * To change this license header, choose License Headers in Project Properties.
- * To change this template file, choose Tools | Templates
- * and open the template in the editor.
- */
+package main;
import java.io.*;
-import static java.lang.Integer.parseInt;
+
import java.util.ArrayList;

/**
@@ -18,47 +14,47 @@
private String proxyUser;
private String proxyPass;
private boolean resumable;
- private ArrayList<String> result;
private ArrayList<String> webAddress;
- String line;
- final String CONFIG = “config.txt”;
-
- //Read CONFIG with parameter CONFIG
-
+
+
+ /**
+ * Constructor for config reader
+ */
public ConfigReader(){
- line = “”;
- result = new ArrayList<String>();
+ String line;
+ ArrayList<String> result = new ArrayList<>();
+ final String CONFIG = “config.txt”;
+
try {
- /*
- * File Reader to read the CONFIG
- */
+
+ //File Reader to read the CONFIG
FileReader fileReader = new FileReader(CONFIG);
- BufferedReader bufferedReader;
- bufferedReader = new BufferedReader(fileReader);
+ BufferedReader bufferedReader = new BufferedReader(fileReader);
+
//with buffered reader read each line and add to ArrayList result
while((line = bufferedReader.readLine()) != null) {
result.add(line);
}
+
//set nilai-nilai CONFIG dengan file hasil baca
- pageToCrawl = parseInt(result.get(0).substring(12));
- crawlDepth = parseInt(result.get(1).substring(11));
- String[] proxy;
- proxy = ((String)result.get(2)).substring(6).split(“,”);
+ pageToCrawl = Integer.parseInt(result.get(0).substring(12));
+ crawlDepth = Integer.parseInt(result.get(1).substring(11));
+ String[] proxy = result.get(2).substring(6).split(“,”);
proxyUser = proxy[0];
proxyPass = proxy[1];
resumable = Boolean.parseBoolean(result.get(3).substring(12));

- webAddress = new ArrayList();
+ webAddress = new ArrayList<>();

- for (int i = 5;i<result.size();i++){
+ for (int i = 5; i< result.size(); i++){
webAddress.add((result.get(i)));
}
bufferedReader.close();

}catch(FileNotFoundException ex) {
System.out.println(
- “Unable to open file ‘” +
- CONFIG + “’”);
+ “Unable to open file ‘” +
+ CONFIG + “’”);
}
catch(IOException ex) {
System.out.println(
@@ -72,41 +68,23 @@ public int getPageToCrawl()
return pageToCrawl;
}

Bisa dilihat, code ini kebanyakan menginstantiate variable dengan 2 line. Padahal bisa disatukan menjadi 1 line. Setelah itu saya menghapus setter pada class ini, karena class ini bersifat immutable.

Refactor Class Crawler Controller

Disini hanya penghapusan comment-comment tak jelas.

Refactor Class LogCrawl

Disini saya melakukan penghapusan baris yang tidak diperlukan beserta penggantian variable hasilCrawl yang sebenarnya tidak diperlukan.

-package main; /**
- * Class LogCrawl yang akan digunakan untuk men-generate log crawler
- * Created by pflarasati on 3/19/16.
- */
+package main;
+
import java.io.File;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.io.BufferedWriter;
import java.io.IOException;
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
+
import java.util.Calendar;

+/**
+ * Class LogCrawl yang akan digunakan untuk men-generate log crawler
+ * @author pflarasati
+ * @version 3/19/16.
+ */
public class LogCrawl {

/**
- * Constructor dari class LogCrawls
- */
- public LogCrawl() {
-
- }
-
-
- /**
* Method ini digunakan untuk membuat log_results.txt berisi log aktivitas crawler
- * @return void
+ * @param hasilCrawler quote yang akan dimasukan ke database
*/
public void getLogFile(Quote hasilCrawler){
- Quote hasilCrawl = hasilCrawler;
+
try{
- File file =new File(“../log_results.txt”);
+ File file = new File(“../log_results.txt”);
+
if(!file.exists()){
file.createNewFile();
}
+
FileWriter fw = new FileWriter(file,true);
BufferedWriter bw = new BufferedWriter(fw);
PrintWriter pw = new PrintWriter(bw);
+
//This will add a new line to the file content
pw.println(“”);

// Add text to log results
- DateFormat dateFormat = new SimpleDateFormat(“yyyy/MM/dd HH:mm:ss”);
Calendar cal = Calendar.getInstance();
+
pw.println(cal.getTime()); //2014/08/06 16:00:22
- pw.println(“Quotes : “ + hasilCrawl.getQuote());
- pw.println(“Author : “ + hasilCrawl.getAuthor());
- pw.println(“Source : “ + hasilCrawl.getSource());
+ pw.println(“Quotes : “ + hasilCrawler.getQuote());
+ pw.println(“Author : “ + hasilCrawler.getAuthor());
+ pw.println(“Source : “ + hasilCrawler.getSource());

System.out.println(cal.getTime()); //2014/08/06 16:00:22
- System.out.println(“Quotes : “ + hasilCrawl.getQuote());
- System.out.println(“Author : “ + hasilCrawl.getAuthor());
- System.out.println(“Source : “ + hasilCrawl.getSource());
+ System.out.println(“Quotes : “ + hasilCrawler.getQuote());
+ System.out.println(“Author : “ + hasilCrawler.getAuthor());
+ System.out.println(“Source : “ + hasilCrawler.getSource());

System.out.println();

@@ -59,6 +56,5 @@ public void getLogFile(Quote hasilCrawler){
System.out.println(“Exception occurred:”);
ioe.printStackTrace();
}
-
}
}

Refactor Class SentenceTagger

Class ini dibuat oleh Alief dan saya

Banyak code yang berantakan yang bisa ditemukan disini, dan beberapa comment yang tidak diperlukan (sisa debug) dan method yang tidak dipakai. Karena terlalu banyak, tidak akan saya tampilkan disini.

Add functional Mongo database to Crawler

Selagi saya refactoring, saya mencoba untuk mengintegrasikan database kedalam mongolabs, dan hasilnya berhasil. Berikut adalah code saya untuk menyambugkan ke mongolabs:

package main;

import com.mongodb.MongoClient;
import com.mongodb.MongoClientURI;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import org.bson.Document;

/**
* Connect the Mongo DB with this class
* @author Aulia Chairunisa
*/
public class DBConnect {

private MongoDatabase db;

/**
* HOST IP, DEFAULT "localhost"
*/
private static final String HOST = "ds023520.mlab.com";

/**
* HOST PORT, DEFAULT 27017
*/
private static final int PORT = 23520;
private static final String USER = "admin";
private static final String PASSWORD = "admin";
/**
* Database's Name, change it to your Database's name
*/
private static final String DBNAME = "inspirecrawlerdb";
/**
* Collection's Name, change it to your collection's name
*/
private static final String COLNAME = "Quote";

/**
* Constructor for DBConnect that will connect to localhost
*/
public DBConnect() {
MongoClientURI mongoClientURI = new MongoClientURI(
"mongodb://"+
USER +
":"+
PASSWORD +
"@" +
HOST +
":" + PORT + "/" +
DBNAME
);

db = (new MongoClient(mongoClientURI)).getDatabase(DBNAME);
}

/**
* Put the quote into mongodb
* @param fullQuote the quote that want to be inputed
*/
public void putData(Quote fullQuote) {
MongoCollection<Document> dBCollection = db.getCollection(COLNAME);
dBCollection.insertOne(
new Document("quote", fullQuote.getQuote())
.append("author", fullQuote.getAuthor())
.append("category", fullQuote.getCategory())
.append("language", fullQuote.getLanguage())
.append("source", fullQuote.getSource())
);
}
}

Oiya, bagian code ini juga termasuk refactoring, mengapa? Karena sebelumnya Aulia Chairunisa sudah membuat class ini. Namun method yang digunakan sudah deprecated atau usang. Untuk memperbaruinya, saya ganti dengan code diatas.

TIME: 5 Jam

BUKTI : Lihat Github, Lihat Mongolab tim kami

Integrate local laravel to MongoLabs

Karena minggu kmarin saya sudah mencoba install laravel dengan extension mongodb, sekarang dicoba untuk integrasi ke mongolabs dan hasilnya: BERHASIL.

Berikut adalah configurasinya:

+ ‘mongodb’ => [
+ ‘driver’ => ‘mongodb’,
+ ‘host’ => env(‘DB_HOST’, ‘ds023520.mlab.com’),
+ ‘port’ => env(‘DB_PORT’, 23520),
+ ‘database’ => env(‘DB_DATABASE’,’inspirecrawlerdb’),
+ ‘username’ => env(‘DB_USERNAME’,’admin’),
+ ‘password’ => env(‘DB_PASSWORD’,’admin’),
+ ‘options’ => [
+ ‘db’ => ‘admin’ // sets the authentication database required by mongo 3
+ ]
+ ],

Setelah itu saya ganti nama Collection saya pada Class Quote menjadi

class Quotes extends Eloquent
{
- protected $collection = ‘quotes’;
+ protected $collection = ‘Quote’;
}

O iya, karena pada crawler, id disini belum auto increment tapi dengan id yg tergenerate. Karena pada method di JsonController membutuhkan key yang auto increment, maka method API GetQuote belum bisa dipakai dan menunggu Aul menyelesaikan ini.

Setelah itu beberapa saya edit lagi dikarenakan kesalahan pada code saya. (Misal pada author, author harus namanya pas, padahal harusnya substring saja, kalau di basis data pakai query where LIKE %author%)

TIME : 1,5 jam

Bukti : Cek Github

API Documentation + Preview/Sample

Terakhir, disini saya melakukan API Documentation dan preview dengan software bernama http://apidocjs.com/ . Dia menggunakan nodejs dalam mengenerate APIDOC nya. Untuk itu perlu dilakukan install

sudo apt-get install npm

pada komputer saya. Setelah terinstall, langsung saja panggil:

npm install apidoc -g

Setelah terinstall, lakukan dokumentasi *HORE* pada controller saya.

Pertama-tama saya buat apidoc.json di folder app, karena API yang digenerate beraada pada folder tersebut. Berikut adalah isinya:

{
- “name”: “Contoh”,
+ “name”: “Inspire Crawler”,
“version”: “0.1.0”,
- “description”: “apiDoc basic example”,
- “title”: “Custom apiDoc browser title”,
- “url” : “http://localhost/timAul/timAul/web/public/api/",
- “sampleUrl” : “http://localhost/timAul/timAul/web/public/api/",
+ “description”: “API to extract quotes form web”,
+ “title”: “Inspire Crawler Doc”,
+ “url” : “http://localhost/timAul/web/public/api/",
+ “sampleUrl” : “http://localhost/timAul/web/public/api/",
“withGenerator” : “true”
}

Code diatas itu seperti tanda pengenal untuk dokumentasinya.

Untuk awalnya saya buat lalu disempurnakan oleh Puti Fitri Larasati. Setelah itu saya lakukan dokumentasi bersama Puti, berikut adalah dokumentasinya:

Panduan mengenai dokumentasinya bisa dilihat disini:

Intinya dia akan mendokumentasi apa yang kita tulis, baik itu parameter apinya, cara requestnya, akan return apa, dll.

Setelah saya dokumentasikan, saya mencobanya dengan :apidoc -i ../timAul/timAul/web/app/ -o sini/

Dimana di dalam folder sini akan menghasilkan halaman html yang tergenerate oleh apidoc.

Berikut contoh tampilan apidocnya.

Blom di edit dokumentasinya

Untuk tampilan dokumentasi yang sudah diedit sudah digenerate oleh Puti.

TIME : 5 jam

Bukti : Cek Github

Nulis Blog

TIME : 1 jam

Bukti : Klo ga nulis, halaman ini apa dong?

What is my problem?

Disini akan saya tuliskan kendala saya dalam mengerjakan task saya:

  1. Perlu belajar teknologi baru tersebut. Hal inilah yang membuat waktu saya mengerjakan tidak singkat, namun butuh waktu buat search cara menggunakan teknologi tersebut (misal mongodb, apidocjs)
  2. Crash saat install composer laravel. Ada beberapa file di laravel yang perlu di buat ulang dengan bantuan laravel dikarenakan ngepull dari github. Nah, ada momen ketika saya melakukan install dan komputer saya crash. Akhirnya, laravel saya rusak dan saya bingung cara membetulkannya. Hal ini membutuhkan waktu 1 jam untuk menemukan solusinya.
  3. Ga ngumpul, ini mungkin penyebab ga sinkronnya kelompok kami dalam mengerjakan ini. Sebenarnya sabtu kemarin harusnya ngumpul, tapi karena berhalangan hadir semua kecuali Puti, saya dan Alief, maka terjadi kebingungan. Alhasil Alief kabur sebelum ngumpul.
  4. Error Error Error. “Loh kok ini ga ada returnnya” hal ini saya temukan saat saya generate Apidoc. ternyata perlu ditambah apisample pada apidoc.jsonnya. Yak hal ini memakan waktu lama untuk googling agar ketemu solusinya

What Will I Do till end sprint?

  1. Testing Crawler
  2. UAT US 6,7

Afterwords

Yak , selesailah laporan saya pada minggu ini. Berikut saya suguhi quote yang saya dapatkan dari hasil crawler code kami :D.

“Unless you’re willing to have a go, fail miserably, and have another go, success won’t happen.” — Phillip Adams

--

--

Haryo Akbarianto Wibowo
Inspire Crawler

Mad AI Enthusiast. I write mostly about Artificial Intelligence and Self Development. I also love to read Engineering, Psychology and Startup. Love to share!