Fase final:
Após a criação do anterior programa, que faz o parsing, procurando pelos links de apenas uma página, apenas é necessário criar as condições para que o crawler aceda a esses links (rapidamente) e arrume as correspondentes páginas, associadas ao link em questão. Utilizei uma Hashtable para manter todos os links já encontrados e o código HTML correspondente à página. A rapidez é conseguida através de threads (o 3º parametro do crawler indica o número de threads que irão tratar das páginas).
O segundo parametro indica a profundidade do crawling. Pode-se considerar como parametro de paragem.
Não é 100% fiável, visto que não tenho nenhuma forma de controlo das threads, mas já serve para demonstrar como é um web crawler minimalista.
import java.util.*;
import java.util.regex.*;
import java.io.*;
import java.net.*;
public class myCrawler extends Thread {
private String initURL;
private myCrawler sObj = null;
protected int depth = 0, maxDepth;
protected LinkedList<String> currentURLList;
protected LinkedList<String> nextURLList;
protected Hashtable<String, String> urlDataHT;
public static void main(String args[]) {
myCrawler mC = new myCrawler(args[0], Integer.parseInt(args[1]));
mC.init(Integer.parseInt(args[2]));
}
public myCrawler(String initURL, int maxDepth) {
this.initURL = initURL;
this.maxDepth = maxDepth;
urlDataHT = new Hashtable<String, String>();
sObj = this;
currentURLList = new LinkedList<String>();
nextURLList = new LinkedList<String>();
}
public myCrawler(myCrawler sObj) {
this.sObj = sObj;
}
public void init(int threads) {
try {
parse4URLs(initURL, getWebPage(initURL), depth);
}
catch (Exception e) {
System.out.println("Bad URL - check if it ends with /");
e.printStackTrace();
}
for (int i = 0; i < threads; i++) {
(new myCrawler(this)).start();
}
}
public void run() {
while (true) {
String url = "";
int myDepth = 0;
synchronized (sObj.currentURLList) {
if (sObj.currentURLList.isEmpty()) {
if (++sObj.depth < sObj.maxDepth) {
synchronized (sObj.nextURLList) {
sObj.currentURLList = sObj.nextURLList;
}
myDepth = sObj.depth;
url = sObj.currentURLList.remove(0);
}
}
else {
myDepth = sObj.depth;
url = sObj.currentURLList.remove(0);
}
}
if (url.equals("")) {
return;
}
try {
parse4URLs(url, getWebPage(url), depth);
}
catch (Exception e) {
System.out.println("Oh... crap... shit happens! " + url);
e.printStackTrace();
}
}
}
private String getWebPage(String myURL) throws Exception {
String response = "", line;
URL url = new URL(myURL);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
while((line = rd.readLine()) != null)
response += line + "\n";
sObj.urlDataHT.put(myURL, response);
return response;
}
private void parse4URLs(String urlString, String htmlData, int currentDepth) {
String regEx = " href=\"(.+?)\"";
String urlParser = "http://(.+?)/";
Pattern regExPattern = Pattern.compile(urlParser);
Matcher matchRegEx = regExPattern.matcher(urlString);
if (!matchRegEx.find()) {
urlParser = "http://(.+?)";
regExPattern = Pattern.compile(urlParser);
matchRegEx = regExPattern.matcher(urlString);
}
String domain = "http://" + matchRegEx.group(1);
// Extract image, flash, etc. addresses
//regEx = " src=\"(.+?)\" ";
regExPattern = Pattern.compile(regEx);
matchRegEx = regExPattern.matcher(htmlData);
String dom = urlString.substring(urlString.indexOf("."), urlString.indexOf("/", urlString.indexOf(".")+1));
dom = dom.replace(".", "\\.");
String domRegEx = "^http://([^\\.]+?)" + dom;
Pattern domRegExPattern = Pattern.compile(domRegEx);
Matcher domRegExMatcher;
while (matchRegEx.find()) {
String found = matchRegEx.group(1);
if (!found.startsWith("http")) {
if (found.startsWith("/"))
found = domain + found;
else
found = "http://" + found;
}
domRegExMatcher = domRegExPattern.matcher(found);
if (domRegExMatcher.find()) {
if (!sObj.urlDataHT.containsKey(found)) {
synchronized (sObj.urlDataHT) {
sObj.urlDataHT.put(found, "");
}
if (currentDepth == sObj.depth)
synchronized (sObj.nextURLList) {
sObj.nextURLList.add(found);
}
else
synchronized (sObj.currentURLList) {
sObj.currentURLList.add(found);
}
System.out.println(found);
}
}
}
}
}