viewgit/index.php:465 Only variables should be passed by reference [2048]

viewgit/index.php:466 Non-static method GeSHi::get_language_name_from_extension() should not be called statically [2048]

  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. #
  4.  
  5. import random, urllib2, threading, re, time, sys
  6. from optparse import OptionParser
  7.  
  8. default_page = "http://poisson.phc.unipi.it"
  9.  
  10. __author__ = "Leonardo Robol <leo@robol.it>"
  11.  
  12. freepages = threading.Event()
  13.  
  14. size = 1000
  15. url_stack = range(size)
  16. link_counter = 0
  17.  
  18. max_steps = 5
  19.  
  20. debug_value = 0
  21. outfile = "connections.txt"
  22.  
  23. ExitRequired = False
  24.  
  25. def debug(message, level):
  26. """Stampa debug se il livello è abbastanza alto"""
  27. if debug_value >= level:
  28. print " => " + message
  29.  
  30. class UrlDict():
  31.  
  32. def __init__(self):
  33. ## Creo il dizionario che mi servirà
  34. ## in seguito
  35.  
  36. self.url_dict = {}
  37. self.lock = threading.RLock()
  38. freepages.set()
  39.  
  40. def getPage(self, url):
  41. """Ritorna un oggetto Page per URL, oppure
  42. None se non è presente"""
  43.  
  44. self.acquire()
  45. if self.url_dict.has_key(url):
  46. ## Effettuiamo una copia locale e
  47. ## poi usciamo
  48. page = self.url_dict[url]
  49. else:
  50. page = None
  51.  
  52. self.release()
  53. return page
  54.  
  55. def addPage(self, page):
  56. """Aggiunge una pagina al database"""
  57. self.acquire("addPage")
  58. self.url_dict[page.url] = page
  59. if not page.analyzed:
  60. freepages.set()
  61. debug("Aggiunta %s" % str(self.url_dict[page.url]), 3)
  62. self.release("addPage")
  63. return None
  64.  
  65. def getNewPage(self):
  66. """Ottiene una pagina non analizzata"""
  67. ## Aspetto che ci siano pagine libere
  68. freepages.wait()
  69. debug("Abbiamo ottenuto una nuova pagina", 3)
  70.  
  71. self.acquire("getNewPage")
  72. resp_page = None
  73. for url in self.url_dict:
  74. page = self.url_dict[url]
  75. if (not page.analyzed) & (page.step <= max_steps):
  76. resp_page = page
  77. debug("Restituisco la pagina %s" % str(resp_page), 3)
  78. break
  79.  
  80. debug("Page vale %s" % str(resp_page), 4)
  81. last = True
  82. for url in self.url_dict:
  83. page = self.url_dict[url]
  84. if (not page.analyzed) & (page.step <= max_steps):
  85. last = False
  86. if last:
  87. freepages.clear()
  88.  
  89. self.release("getNewPage")
  90. return resp_page
  91.  
  92. def hasKey(self, url):
  93. """Ritorna True se la key url è presente"""
  94. self.acquire("hasKey")
  95. resp = self.url_dict.has_key(url)
  96. self.release("hasKey")
  97. return resp
  98.  
  99. def addLink(self, url, ID):
  100. global link_counter
  101. self.acquire("addLink")
  102. self.url_dict[url].links.append(ID)
  103. link_counter += 1
  104. self.release("addLink")
  105.  
  106. def getLinks(self, url):
  107. """Ritorna una lista con i link della pagina
  108. contrassegnata da url"""
  109. self.acquire("getLinks")
  110. links = self.url_dict[url].links
  111. self.release("getLinks")
  112. return links
  113.  
  114. def __iter__(self):
  115. """Iteratore sulle pagine nel dizionario"""
  116. # self.acquire("__iter__")
  117. try:
  118. for url in self.url_dict:
  119. try:
  120. yield url
  121. except Exception, e:
  122. print " => Exception: %s" % e
  123. except Exception, e:
  124. print " => Exception caught, %s" % e
  125. # self.release("__iter__")
  126.  
  127. def setAnalyzed(self, url):
  128. """Contrassegna un url come analizzato"""
  129. self.acquire("setAnalyzed")
  130. if self.url_dict.has_key(url):
  131. self.url_dict[url].analyzed = True
  132. self.release("setAnalzyed")
  133. return None
  134.  
  135. def acquire(self, message=""):
  136. debug("Thread %s acquiring lock -- %s " % (str(threading.currentThread()), message), 4)
  137. self.lock.acquire()
  138.  
  139. def release(self, message = ""):
  140. debug("Thread %s releasing lock -- %s" % (str(threading.currentThread()), message), 4)
  141. self.lock.release()
  142.  
  143. url_dict = UrlDict()
  144.  
  145.  
  146. def get_links(page):
  147. """Restituisce una lista con i link
  148. presenti nella pagina data, in forma canonica"""
  149. content, real_url = get_content(page.url)
  150.  
  151. if(content == -1):
  152. return -1
  153.  
  154. links = re.findall(r"<a href=\"(\S*)\"[^>]*>",content)
  155. ret = []
  156. for link in links:
  157. # Espando il link in modo da (speriamo!)
  158. # garantire l'unicità
  159. ret.append(expand_url(real_url, link))
  160.  
  161. return ret
  162.  
  163.  
  164. def expand_url(parent, url):
  165. """Questa funzione prende l'url della pagina parent
  166. e l'url del link e dà all'url del link una forma unica
  167. e canonica, del tipo
  168.  
  169. http://www.example.com/pagina
  170. http://www.example.com/pagina.html
  171. """
  172.  
  173. if len(url) == 0:
  174. return url
  175.  
  176. ## Controllo che l'url non cominci con un punto
  177. ## nel qual caso cerchiamo di rimediare subito,
  178. ## ma non cadiamo nel tranello di ignorare i ..
  179. if url[0] == ".":
  180. if len(url) == 1:
  181. url = parent
  182.  
  183. else:
  184. if(url[1] != "."):
  185. url = url[1:]
  186.  
  187. ## Se all'inizio dell'url c'è uno slash non ci serve tutto
  188. ## il parent, ma solo la prima parte
  189. if url.startswith("/"):
  190. parent = re.search(".+//[^/]*", parent).group(0)
  191. else:
  192. # in caso contrario dobbiamo assicurarci di troncare
  193. # l'ultima parte dell'url dopo il /, a meno che non
  194. # finisca senza estensione (in quel caso aggiungiamo un /)
  195. if re.search("\.[^/]*$", parent):
  196. parent = re.sub("[^/]*$", "", parent)
  197. else:
  198. if not parent.endswith("/"):
  199. parent += "/"
  200.  
  201.  
  202.  
  203. ## Controlliamo prima di tutto se nell'url c'è un
  204. ## protocollo
  205. protocol = re.search(r"(\w+):", url)
  206. if protocol == None:
  207. url = parent + url
  208. return url
  209.  
  210. def get_content(url):
  211. """Cerca di scaricare l'url dato e restituisce
  212. -1 se non ce la fa, il contenuto altrimenti"""
  213. try:
  214. req = urllib2.urlopen(url)
  215. except:
  216. return (-1, None)
  217.  
  218. return (req.read(), req.geturl())
  219.  
  220. class Page():
  221. """Una pagina web. Questa classe, quando viene istanziata,
  222. controlla se una pagina con quel nome è già presente (una
  223. pagina è unica!) e se lo è restituisce lo stesso oggetto,
  224. altrimenti ne crea uno nuovo con un nuovo ID"""
  225.  
  226. def __repr__(self):
  227. return "<Page object: %s>" % self.url
  228.  
  229. def __init__(self, url="", parent=None):
  230.  
  231. if(url != ""):
  232. self.__new_page(url, parent)
  233. else:
  234. self.__get_page(parent)
  235.  
  236. def __get_page(self, parent):
  237.  
  238. if(len(url_stack) == 0):
  239. self.exhausted = True
  240. return
  241.  
  242. page = None
  243. while(page == None):
  244.  
  245. page = url_dict.getNewPage()
  246.  
  247. # Questo è un punto dove il Crawler
  248. # si potrebbe bloccare e quindi facciamo
  249. # un check sull' ExitRequired
  250. # Ovviamente poi sarà necessario che anche
  251. # il chiamante lo faccia!
  252. if ExitRequired:
  253. debug("Ho incontrato exit required!", 2)
  254. return
  255. if not page.exhausted:
  256. self.ID = page.ID
  257.  
  258. self.analyzed = page.analyzed
  259. self.exhausted = page.exhausted
  260. self.step = page.step
  261. self.url = page.url
  262. url_dict.setAnalyzed(page.url)
  263.  
  264. def __new_page(self, url, parent):
  265. # Questo ci serve per tenere il
  266. # conto di tutti gli url
  267. global url_dict
  268. global url_stack
  269.  
  270. self.exhausted = False
  271. self.analyzed = False
  272. self.url = url
  273.  
  274.  
  275. if(url_dict.hasKey(url)):
  276. # Preservo i parametri che esistono già!
  277. page = url_dict.getPage(url)
  278. if page.exhausted:
  279. self.exhausted = page.exhausted
  280. return
  281.  
  282. self.ID = page.ID
  283.  
  284. self.analyzed = page.analyzed
  285. self.step = page.step
  286. if parent == None:
  287. self.step = 0
  288. else:
  289. if(parent.step < self.step):
  290. self.step = parent.step + 1
  291.  
  292. else:
  293. try:
  294. self.ID = url_stack.pop()
  295. except IndexError:
  296. self.exhausted = True
  297.  
  298. # Conto in quanti passi si raggiunge questa pagina
  299. if parent == None:
  300. self.step = 0
  301. else:
  302. self.step = parent.step + 1
  303. self.links = []
  304. url_dict.addPage(self)
  305.  
  306.  
  307.  
  308. def add_link(self, page):
  309.  
  310. if(page.exhausted):
  311. return -1
  312. if debug >= 2:
  313. debug("Adding link to %s" % page.url, 2)
  314. url_dict.addLink(page.url, page.ID)
  315. return 0
  316.  
  317. def links(self):
  318. return url_dict.getLinks(url)
  319.  
  320.  
  321.  
  322.  
  323. class Crawler(threading.Thread):
  324. """Partendo da startpage, segue tutti i link registrando
  325. i vari collegamenti fra le pagine. Una volta raggiunto il
  326. limite di pagine da controllare termina"""
  327.  
  328. def __init__(self, startpage=default_page):
  329. threading.Thread.__init__(self)
  330. self.start_page = startpage
  331. self.waitingforpage = False
  332.  
  333. def WaitingForPage(self):
  334. """Ritorna True se il Crawler sta cercando di ottenere
  335. una nuova pagina"""
  336. return self.waitingforpage
  337.  
  338.  
  339. def run(self):
  340.  
  341. # Capiamo che pagina ci serve
  342. page = Page(self.start_page)
  343.  
  344. while(not page.exhausted):
  345. self.waitingforpage = True
  346. ## Stiamo attenti a non fare troppi passi
  347. ## dalla pagina di partenza
  348. page = Page()
  349.  
  350. while page == None:
  351. page = Page()
  352.  
  353.  
  354. ## Se ci chiedono di uscire perché abbiamo
  355. ## analizzato tutte la pagine ce ne andiamo
  356. if ExitRequired:
  357. return
  358.  
  359. ## Analogamente ce ne andiamo se non ci sono
  360. ## più vie da seguire in questa direzione
  361. if page.exhausted:
  362. break
  363.  
  364. self.waitingforpage = False
  365.  
  366. if debug >= 1:
  367. debug("Analyzing page %s" % str(page), 1)
  368.  
  369.  
  370. # Come prima cosa devo fare il parsing dei
  371. # link che ci sono nella pagina
  372. # Diamo una mixata per simulare meglio
  373. # il caso.. dato che tanto è probabile che
  374. # alcuni link rimarranno non visitati!
  375. try:
  376. links = get_links(page)
  377. except:
  378. ## Questo potrebbe andare male se per caso la rete
  379. ## va giù o simili. A costo di non avere dati esatti
  380. ## mettiamo la pagina così com'è, ovvero assumiamo
  381. ## che non abbia link
  382. links = -1
  383.  
  384. ## A questo punto io che mi occupo della pagina devo
  385. ## aggiungere tutti i link alla pagina
  386.  
  387. if not links == -1:
  388. random.shuffle(links)
  389. for l in links:
  390. lpage = Page(l, page)
  391.  
  392. if not lpage.exhausted:
  393. page.add_link(lpage)
  394. else:
  395. break
  396.  
  397.  
  398.  
  399.  
  400. if __name__ == "__main__":
  401.  
  402. parser = OptionParser()
  403. parser.add_option("-c", "--concurrency", dest="concurrency", action="store",
  404. help="Set level of concurrency (i.e. how many threads)", default=3)
  405. parser.add_option("-d", "--debug", dest="debug", action="store",
  406. help="Set debug level", default=0)
  407. parser.add_option("-o", "--output", dest="outfile", action="store",
  408. help="Name of the output file for the connection matrix", default="connections.txt")
  409. parser.add_option("-n", "--number", dest="size", action="store",
  410. help="Number of pages to analyze", default=1000)
  411. parser.add_option("-m", "--max-steps", dest="max_steps", action="store",
  412. help="Max steps to walk from the starting page", default=5)
  413. parser.add_option("-s", "--start-page", dest="start_page",
  414. default="http://poisson.phc.unipi.it",
  415. help="Starting page for all the crawlers",
  416. action="store")
  417. parser.add_option("-l", "--legend-file", dest="legend_file", action="store",
  418. help="Conversion table from integers indexes to urls", default="legend.txt")
  419.  
  420.  
  421. (option, args) = parser.parse_args()
  422.  
  423. concurrency = int(option.concurrency)
  424. debug_value = int(option.debug)
  425. outfile = option.outfile
  426. legend_file = option.legend_file
  427. size = int(option.size)
  428. url_stack = range(size)
  429. url_stack.reverse()
  430. max_steps = int(option.max_steps)
  431. default_page = option.start_page
  432.  
  433.  
  434. l = time.localtime(time.time())
  435. print " => Starting with this configuration at %s:%s:%s\n\
  436. %d thread(s)\n\
  437. %d pages to analyze\n\
  438. %d max steps from the start page, %s\n\
  439. %d level of debug\n\
  440. Writing on file %s and %s\n\
  441. " % (l.tm_hour,l.tm_min,l.tm_sec, concurrency, size, max_steps, default_page, debug_value, outfile, legend_file)
  442.  
  443.  
  444. ## Avvio i thread, di modo che si impegnino a lavorare
  445. ## Ora il mio scopo sarà controllare che non finiscano
  446. ## le pagine
  447. threads = []
  448. for i in range(0, concurrency):
  449. threads.append(Crawler(default_page))
  450. threads[i].start()
  451.  
  452. while threads[0].isAlive():
  453. ## Controllo se tutti i thread sono
  454. ## alla ricerca di una pagina. Se la
  455. ## risposta è sì le pagine sono finite
  456. ## e possiamo uscire
  457. PageAreExhausted = True
  458. for t in threads:
  459. if not t.WaitingForPage():
  460. PageAreExhausted = False
  461. break
  462.  
  463. if PageAreExhausted:
  464. ## Questa variabile globale farà
  465. ## uscire tutti i thread
  466. ExitRequired = True
  467. print " => There are no more pages in my range, exiting"
  468. break
  469.  
  470. ## Se non c'è niente da fare posso
  471. ## anche rilassarmi ed aspettare un
  472. ## secondo prima di rieseguire il check
  473. try:
  474. time.sleep(1)
  475. except KeyboardInterrupt:
  476. sys.exit()
  477.  
  478.  
  479. ## Qui non c'è modo umano di terminare il
  480. ## suo lavoro, bisognerà studiarci sopra
  481. for t in threads:
  482. t.join()
  483.  
  484.  
  485. ## A questo punto mi devo preoccupare di salvare
  486. ## la matrice in un formato soddisfacente
  487.  
  488. out = open(outfile, 'w')
  489. leg = open(legend_file, 'w')
  490.  
  491. ## Il numero massimo di pagine meno quelle avanzate =
  492. ## le pagine effettivamente usate!
  493. out.write(str(size - len(url_stack)) + "\n")
  494.  
  495. ## Il numero di elementi non 0 sono i link!
  496. out.write(str(link_counter) + "\n")
  497.  
  498. ## Con questa contiamo quante pagine abbiamo
  499. ## perso troncando il procedimento
  500. no_id = 0
  501.  
  502. for url in url_dict:
  503. try:
  504. leg.write(str(url_dict.getPage(url).ID) + "\t" + url + "\n" )
  505. except AttributeError:
  506. no_id += 1
  507. for link in url_dict.getLinks(url):
  508. out.write(str(url_dict.getPage(url).ID) + "\t" + str(link) + "\n")
  509.  
  510. print " => %d pagine sono state analizzate ma non incluse per rispettare \n\
  511. la dimensione della matrice scelta" % no_id
  512.  
  513. out.close()
  514. leg.close()
  515.  
  516. l = time.localtime(time.time())
  517. print " => Work completed at %s:%s:%s " % (l.tm_hour,l.tm_min,l.tm_sec)
  518.  
  519.  
  520.  
  521.