From 59c63eb204c8e5360db37ae7c3788953a005c784 Mon Sep 17 00:00:00 2001 From: Leonardo Robol Date: Mon, 26 Oct 2009 23:14:45 +0100 Subject: [PATCH] Prima versione pseudo funzionante, ma ci sono ancora un sacco di variabili globali che fungono da parametri --- spidy.py | 202 +++++++++++++++++++++++++++++++++++++++++++++++++++++---- test/test_1.py | 25 ++++++- 2 files changed, 214 insertions(+), 13 deletions(-) diff --git a/spidy.py b/spidy.py index 2b8feab..d24725b 100644 --- a/spidy.py +++ b/spidy.py @@ -6,12 +6,24 @@ import random import urllib2 import mutex import threading -import re +import re, time default_page = "http://poisson.phc.unipi.it" -def get_links(url): - content = get_page(url) +__author__ = "Leonardo Robol " + +mtx_url_dict = mutex.mutex() + +N = 10000 +url_dict = {} +url_counter = range(N) + +max_steps = 5 + +def get_links(page): + """Restituisce una lista con i link + presenti nella pagina data, in forma canonica""" + content = get_page(page.url) if(content == -1): return -1 @@ -20,7 +32,7 @@ def get_links(url): for link in links: # Espando il link in modo da (speriamo!) # garantire l'unicità - ret.append(expand_url(url, link)) + ret.append(expand_url(page.url, link)) return ret @@ -35,7 +47,8 @@ def expand_url(parent, url): """ ## Controllo che l'url non cominci con un punto - ## nel qual caso cerchiamo di rimediare subito + ## nel qual caso cerchiamo di rimediare subito, + ## ma non cadiamo nel tranello di ignorare i .. if url[0] == ".": if len(url) == 1: url = parent @@ -43,7 +56,21 @@ def expand_url(parent, url): else: if(url[1] != "."): url = url[1:] - + + ## Se all'inizio dell'url c'è uno slash non ci serve tutto + ## il parent, ma solo la prima parte + if url.startswith("/"): + parent = re.search(".+//[^/]*", parent).group(0) + else: + # in caso contrario dobbiamo assicurarci di troncare + # l'ultima parte dell'url dopo il /, a meno che non + # finisca senza estensione (in quel caso aggiungiamo un /) + if re.search("\.[^/]*$", parent): + parent = re.sub("[^/]*$", "", parent) + else: + parent += "/" + + ## Controlliamo prima di tutto se nell'url c'è un ## protocollo @@ -53,6 +80,8 @@ def expand_url(parent, url): return url def get_page(url): + """Cerca di scaricare l'url dato e restituisce + -1 se non ce la fa, il contenuto altrimenti""" try: req = urllib2.urlopen(url) except: @@ -60,21 +89,170 @@ def get_page(url): return req.read() +class Page(): + """Una pagina web. Questa classe, quando viene istanziata, + controlla se una pagina con quel nome è già presente (una + pagina è unica!) e se lo è restituisce lo stesso oggetto, + altrimenti ne crea uno nuovo con un nuovo ID""" + + def __repr__(self): + return "" % self.url + + def __init__(self, url=""): + + if(url != ""): + mtx_url_dict.lock(self.__new_page, url) + mtx_url_dict.unlock() + else: + mtx_url_dict.lock(self.__get_page, 0) + mtx_url_dict.unlock() + + def __get_page(self, num): + + if(len(url_counter) == 0): + self.exhausted = True + return + + page_found = False + + while(not page_found): + + for url in url_dict: + page = Page(url) + if not page.analyzed: + page_found = True + self.url = url + break + + if not page_found: + time.sleep(1) + + + + self.ID = page.ID + self.analyzed = page.analyzed + self.exhausted = False + url_dict[url].analyzed = True + + def __new_page(self, url): + # Questo ci serve per tenere il + # conto di tutti gli url + global url_dict + global url_counter + + self.exhausted = False + self.analyzed = False + self.url = url + + if(url_dict.has_key(url)): + # Preservo i parametri che esistono già! + self.ID = url_dict[url].ID + self.analyzed = url_dict[url].analyzed + + else: + try: + self.ID = url_counter.pop() + except IndexError: + self.exhausted = True + + + url_dict[url] = self + url_dict[url].links = [] + + def add_link(self, page): + + if(page.exhausted): + return -1 + print " => Adding link to %s" % page.url + mtx_url_dict.lock(self.__add_link, page.ID) + mtx_url_dict.unlock() + return 0 + + def __add_link(self, ID): + url_dict[self.url].links.append(ID) + + def links(self): + return url_dict[self.url].links + + + + class Crawler(threading.Thread): + """Partendo da startpage, segue tutti i link registrando + i vari collegamenti fra le pagine. Una volta raggiunto il + limite di pagine da controllare termina""" def __init__(self, startpage=default_page): threading.Thread.__init__(self) - start_page = start_page + self.start_page = startpage - def run(): + def run(self): + + step_counter = 0 # Capiamo che pagina ci serve - page = start_page + page = Page(self.start_page) + + while(not page.exhausted): + + if(step_counter > max_steps): + page = Page(self.start_page) + step_counter = 0 + else: + page = Page() + step_counter += 1 + + if page.exhausted: + break + + # Come prima cosa devo fare il parsing dei + # link che ci sono nella pagina + # Diamo una mixata per simulare meglio + # il caso.. dato che tanto è probabile che + # alcuni link rimarranno non visitati! + links = get_links(page) + random.shuffle(links) + + ## A questo punto io che mi occupo della pagina devo + ## aggiungere tutti i link alla pagina + + if not links == -1: + for l in links: + lpage = Page(l) + + if not lpage.exhausted: + page.add_link(lpage) + else: + break + - # Come prima cosa devo fare il parsing dei - # link che ci sono nella pagina + - links = get_links(page) +if __name__ == "__main__": + + concurrency = 25 + + threads = [] + for i in range(0, concurrency): + threads.append(Crawler()) + threads[i].start() + + + for i in range(0, concurrency): + threads[i].join() + + ## A questo punto mi devo preoccupare di salvare + ## la matrice in un formato soddisfacente + + out = open("ji.txt", 'w') + + for page in url_dict: + for link in url_dict[page].links: + out.write(page + "\t" + str(url_dict[page].ID) + "\t" + str(link) + "\n") + + + + diff --git a/test/test_1.py b/test/test_1.py index 238f68a..6a3aef9 100644 --- a/test/test_1.py +++ b/test/test_1.py @@ -2,6 +2,29 @@ import sys sys.path.append("../") import spidy +def confirm(test): + + print " => Test %s superato" % test + + print " => Provo ad ottenere i link di www.robol.it" -print spidy.get_links("http://poisson.phc.unipi.it/~robol") +page = spidy.Page("http://www.robol.it") +if len(spidy.get_links(page)) > 0: + confirm("links_1") + +print " => Provo ad effettuare il test sulla pagina" +page = spidy.Page("http://www.robol.it") +page.add_link("http://ciccio.org") +page = spidy.Page("http://www.robol.it") +page.exhausted +if len(page.links()) == 1: + confirm("page_1") +print " => Provo ad ottenere una pagina non analizzata" +page = spidy.Page() +page.exhausted +print " => Ho ottenuto %s" % page.url +page = spidy.Page() +page.exhausted +print " => Ho ottenuto %s" % page.url +confirm("page_2") -- 2.1.4