In [1]:
import os
import logging
from time import sleep
from heapq import heappop, heappushpop
import networkx as nx
from link_parser import LinkParser
logging.basicConfig(filename="/media/ssd/simple.wiki/spider.log",
format="%(asctime)s - %(levelname)s - %(message)s",
datefmt='%I:%M:%S %p',
filemode='w',
level=logging.INFO)
На этапе фильтрации при помощи регулярного выражения отбираются url-ы, ведущие на уникальные вики-страницы. Эти страницы имеют доменное имя simple.wikipedia.org и лежат по пути wiki. По интересующему пути simple.wikipedia.org/wiki/ также лежат служебные страницы, начинающиеся на File:, Help:, Special: и т.д., которые отбрасываются во время фильтрации (при этом нельзя отбрасывать любой url с символом ':', т.к. существуют такие страницы, как "ISO_3166-2:BR" или "Star_Trek:_Phase_II"). Ещё одним особым случаем является url по вышеуказанному пути, чья уникальная часть начинается на символ '#' (например, simple.wikipedia.org/wiki/#blabla) - такой url редиректит на главную страницу. Его также считаем невалидным (*встретился после посещения половины всех страниц при самом первом заходе).
На этапе нормализации из url-а отбрасывается часть, начинающаяся с хештега, т.к. она содержит в себе лишь информацию об определённом положении на странице. Также отсекается внутренний путь страницы, идущий за слешем после названия страницы.
При обходе поддерживаются множества url-ов to_visit и visited (в первом не могут содержаться объекты из второго). Также во время обхода строится ориентированный граф из страниц для дальнейшего вычисления PageRank-а.
In [3]:
%%time
link_parser = LinkParser()
to_visit = {"https://simple.wikipedia.org/wiki/Main_Page"} # starting url
visited = set()
graph = nx.DiGraph()
bad_urls = []
def spider(delay=0.1):
global link_parser, to_visit, visited, graph
while len(to_visit):
url = to_visit.pop()
logging.info("%s: %s", len(visited), url)
graph.add_node(url)
visited.add(url)
try:
links = link_parser.get_links(url)
except Exception as e:
print e
logging.error(e)
bad_urls.append(url)
continue
to_visit = to_visit.union(links - visited)
graph.add_edges_from(zip([url] * len(links), links))
sleep(delay)
spider(0.01)
Как видно, у небольшого числа урлов оказалась проблема с кодировкой, дропнем их из графа. И посмотрим сколько страниц нашли.
In [6]:
graph.remove_nodes_from(bad_urls)
In [7]:
graph.number_of_nodes()
Out[7]:
135318 из 123771 уникальных страниц. Предполагаю, что причина превосходства числа найденных страниц связанно с наличием редиректов, которые не предлагалось обрабатывать.
Посчитаем PageRank и найдём 20 топовых страниц.
In [17]:
%%time
pagerank = nx.pagerank(graph)
In [18]:
top20 = [0.] * 20
for url, rank in pagerank.iteritems():
heappushpop(top20, (rank, url))
In [19]:
while top20:
rank, url = heappop(top20)
print rank, url