diff --git a/spidy b/spidy deleted file mode 100755 index 048cf51..0000000 --- a/spidy +++ /dev/null @@ -1,306 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# - -import random -import urllib2 -import mutex -import threading -import re, time -from optparse import OptionParser - -default_page = "http://poisson.phc.unipi.it" - -__author__ = "Leonardo Robol <leo@robol.it>" - -mtx_url_dict = mutex.mutex() - -size = 1000 -url_dict = {} -url_counter = range(size) - -max_steps = 5 - -debug = False -outfile = "connections.txt" - - -def get_links(page): - """Restituisce una lista con i link - presenti nella pagina data, in forma canonica""" - content, real_url = get_content(page.url) - - if(content == -1): - return -1 - - links = re.findall(r"<a href=\"(\S*)\"[^>]*>",content) - ret = [] - for link in links: - # Espando il link in modo da (speriamo!) - # garantire l'unicità - ret.append(expand_url(real_url, link)) - - return ret - - -def expand_url(parent, url): - """Questa funzione prende l'url della pagina parent - e l'url del link e dà all'url del link una forma unica - e canonica, del tipo - - http://www.example.com/pagina - http://www.example.com/pagina.html - """ - - ## Controllo che l'url non cominci con un punto - ## nel qual caso cerchiamo di rimediare subito, - ## ma non cadiamo nel tranello di ignorare i .. - if url[0] == ".": - if len(url) == 1: - url = parent - - 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: - if not parent.endswith("/"): - parent += "/" - - - - ## Controlliamo prima di tutto se nell'url c'è un - ## protocollo - protocol = re.search(r"(\w+):", url) - if protocol == None: - url = parent + url - return url - -def get_content(url): - """Cerca di scaricare l'url dato e restituisce - -1 se non ce la fa, il contenuto altrimenti""" - try: - req = urllib2.urlopen(url) - except: - return (-1, None) - - return (req.read(), req.geturl()) - -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 "<Page object: %s>" % 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 - if debug: - 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) - self.start_page = startpage - - - def run(self): - - step_counter = 0 - - # Capiamo che pagina ci serve - 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) - - ## A questo punto io che mi occupo della pagina devo - ## aggiungere tutti i link alla pagina - - if not links == -1: - random.shuffle(links) - for l in links: - lpage = Page(l) - - if not lpage.exhausted: - page.add_link(lpage) - else: - break - - - - -if __name__ == "__main__": - - parser = OptionParser() - parser.add_option("-c", "--concurrency", dest="concurrency", action="store", - help="Set level of concurrency (i.e. how many threads)", default=3) - parser.add_option("-d", "--debug", dest="debug", action="store_true", - help="Activate debug mode", default=False) - parser.add_option("-o", "--output", dest="outfile", action="store", - help="Name of the output file for the connection matrix", default="connections.txt") - parser.add_option("-n", "--number", dest="size", action="store", - help="Number of pages to analyze", default=1000) - parser.add_option("-m", "--max-steps", dest="max_steps", action="store", - help="Max steps to walk from the starting page", default=5) - parser.add_option("-s", "--start-page", dest="start_page", default="http://poisson.phc.unipi.it", - action="store") - - - (option, args) = parser.parse_args() - - concurrency = int(option.concurrency) - debug = bool(option.debug) - outfile = option.outfile - size = int(option.size) - url_counter = range(size) - max_steps = int(option.max_steps) - default_page = option.start_page - - - l = time.localtime(time.time()) - print " => Starting with this configuration at %s:%s:%s\n\ - %d thread(s)\n\ - %d pages to analyze\n\ - %d max steps from the start page, %s\n\ - Writing on file %s\n\ - " % (l.tm_hour,l.tm_min,l.tm_sec, concurrency, size, max_steps, default_page, outfile) - - - threads = [] - for i in range(0, concurrency): - threads.append(Crawler(default_page)) - threads[i].start() - - - ## Qui non c'è modo umano di terminare il - ## suo lavoro, bisognerà studiarci sopra - 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(outfile, 'w') - out.write(str(size) + "\n") - - - - 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") - - l = time.localtime(time.time()) - print " => Work completed at %s:%s:%s " % (l.tm_hour,l.tm_min,l.tm_sec) - - - - diff --git a/spidy.py b/spidy.py new file mode 100755 index 0000000..048cf51 --- /dev/null +++ b/spidy.py @@ -0,0 +1,306 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# + +import random +import urllib2 +import mutex +import threading +import re, time +from optparse import OptionParser + +default_page = "http://poisson.phc.unipi.it" + +__author__ = "Leonardo Robol <leo@robol.it>" + +mtx_url_dict = mutex.mutex() + +size = 1000 +url_dict = {} +url_counter = range(size) + +max_steps = 5 + +debug = False +outfile = "connections.txt" + + +def get_links(page): + """Restituisce una lista con i link + presenti nella pagina data, in forma canonica""" + content, real_url = get_content(page.url) + + if(content == -1): + return -1 + + links = re.findall(r"<a href=\"(\S*)\"[^>]*>",content) + ret = [] + for link in links: + # Espando il link in modo da (speriamo!) + # garantire l'unicità + ret.append(expand_url(real_url, link)) + + return ret + + +def expand_url(parent, url): + """Questa funzione prende l'url della pagina parent + e l'url del link e dà all'url del link una forma unica + e canonica, del tipo + + http://www.example.com/pagina + http://www.example.com/pagina.html + """ + + ## Controllo che l'url non cominci con un punto + ## nel qual caso cerchiamo di rimediare subito, + ## ma non cadiamo nel tranello di ignorare i .. + if url[0] == ".": + if len(url) == 1: + url = parent + + 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: + if not parent.endswith("/"): + parent += "/" + + + + ## Controlliamo prima di tutto se nell'url c'è un + ## protocollo + protocol = re.search(r"(\w+):", url) + if protocol == None: + url = parent + url + return url + +def get_content(url): + """Cerca di scaricare l'url dato e restituisce + -1 se non ce la fa, il contenuto altrimenti""" + try: + req = urllib2.urlopen(url) + except: + return (-1, None) + + return (req.read(), req.geturl()) + +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 "<Page object: %s>" % 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 + if debug: + 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) + self.start_page = startpage + + + def run(self): + + step_counter = 0 + + # Capiamo che pagina ci serve + 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) + + ## A questo punto io che mi occupo della pagina devo + ## aggiungere tutti i link alla pagina + + if not links == -1: + random.shuffle(links) + for l in links: + lpage = Page(l) + + if not lpage.exhausted: + page.add_link(lpage) + else: + break + + + + +if __name__ == "__main__": + + parser = OptionParser() + parser.add_option("-c", "--concurrency", dest="concurrency", action="store", + help="Set level of concurrency (i.e. how many threads)", default=3) + parser.add_option("-d", "--debug", dest="debug", action="store_true", + help="Activate debug mode", default=False) + parser.add_option("-o", "--output", dest="outfile", action="store", + help="Name of the output file for the connection matrix", default="connections.txt") + parser.add_option("-n", "--number", dest="size", action="store", + help="Number of pages to analyze", default=1000) + parser.add_option("-m", "--max-steps", dest="max_steps", action="store", + help="Max steps to walk from the starting page", default=5) + parser.add_option("-s", "--start-page", dest="start_page", default="http://poisson.phc.unipi.it", + action="store") + + + (option, args) = parser.parse_args() + + concurrency = int(option.concurrency) + debug = bool(option.debug) + outfile = option.outfile + size = int(option.size) + url_counter = range(size) + max_steps = int(option.max_steps) + default_page = option.start_page + + + l = time.localtime(time.time()) + print " => Starting with this configuration at %s:%s:%s\n\ + %d thread(s)\n\ + %d pages to analyze\n\ + %d max steps from the start page, %s\n\ + Writing on file %s\n\ + " % (l.tm_hour,l.tm_min,l.tm_sec, concurrency, size, max_steps, default_page, outfile) + + + threads = [] + for i in range(0, concurrency): + threads.append(Crawler(default_page)) + threads[i].start() + + + ## Qui non c'è modo umano di terminare il + ## suo lavoro, bisognerà studiarci sopra + 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(outfile, 'w') + out.write(str(size) + "\n") + + + + 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") + + l = time.localtime(time.time()) + print " => Work completed at %s:%s:%s " % (l.tm_hour,l.tm_min,l.tm_sec) + + + +