Skip to content

Instantly share code, notes, and snippets.

@sheh
Last active November 16, 2016 14:27
Show Gist options
  • Save sheh/3e35304a879c62b0f406fc00f77ef740 to your computer and use it in GitHub Desktop.
Save sheh/3e35304a879c62b0f406fc00f77ef740 to your computer and use it in GitHub Desktop.
site-wc
import re
import sys
import aiohttp
import asyncio
from html.parser import HTMLParser
from collections import defaultdict
from operator import itemgetter
'''
Python 3.5.2
Требует установку aiohttp (pip install aiohttp)
Выводит наиболее часто встречающиеся слова ресурса (сайта). С главное страницы ресурса (первый
параметр скрипта) собираются абсолютные и относительные ссылки на другие страницы в рамках
ресурса, затем обход продолжается рекурсивно для всех страниц. Для отправки запросов используется
асинхронная библиотека aiohttp и возможности python 3.5.2.
Текст каждой страницы разбивается по разделителям (не словам), затем берутся только слова
длиннее 2 символов и не входящте в топ-100 самых популярных лемм русского языка.
> python3 calc-site-wc.py https://lenta.ru/ 30
'''
MAX_DEEP = 10 # максимальная глубина обхода
MAX_LINKS_BATCH = 100 # максимальное число одновременно запрашиваемых ссылок
HEADERS = {'User-Agent': "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:47.0) Gecko/20100101 Firefox/47.0"}
SPLIT_TEXT_RE = re.compile(r"\W+")
ONLY_DIGITS_RE = re.compile(r"[0-9]+")
try:
COMMON_WORDS = {l.strip() for l in open("common_words.txt", 'r', encoding='utf8').readlines()}
except OSError:
COMMON_WORDS = set()
print('common_words.txt is not found')
class MyHTMLParser(HTMLParser):
def __init__(self, root_url):
super().__init__()
self.links = set()
self._root_url = root_url
self._curr_tag = None
self.words = defaultdict(int)
def handle_starttag(self, tag, attrs):
if tag == 'a':
href = dict(attrs).get('href', '')
if len(href) > 2 and href[0] == '/' and href[1] != '/':
href = self._root_url + href
if href.startswith(self._root_url):
self.links.add(href)
self._curr_tag = tag
def handle_data(self, data):
if self._curr_tag != 'script' and self._curr_tag != 'style':
for w in SPLIT_TEXT_RE.split(data):
w = w.lower()
if len(w) > 2 and not ONLY_DIGITS_RE.match(w) and w not in COMMON_WORDS:
self.words[w] += 1
async def fetch(session, url, root_url):
parser = MyHTMLParser(root_url)
page = ''
with aiohttp.Timeout(10):
async with session.get(url, headers=HEADERS) as response:
page = await response.text()
parser.feed(page)
return parser.links, parser.words
def print_usage():
print("Usage: site-wc.py site_url [N]")
print(" site_url example: http://lenta.ru")
print(" N print N most popular words, default 10")
if __name__ == '__main__':
if len(sys.argv) < 2:
print("Error: 'site url' - is required")
print_usage()
sys.exit(1)
if sys.argv[1] == '-h':
print_usage()
sys.exit(0)
if len(sys.argv) > 2:
try:
N = int(sys.argv[2])
except ValueError:
print("Error: 'N' - must be integer")
print_usage()
sys.exit(1)
else:
N = 10
root_url = sys.argv[1].rstrip("/")
urls = [root_url]
i = 0
loop = asyncio.get_event_loop()
conn = aiohttp.TCPConnector(verify_ssl=False)
processed_links = set()
words = defaultdict(int)
with aiohttp.ClientSession(loop=loop, connector=conn) as session:
while urls and i < MAX_DEEP:
tasks = [asyncio.ensure_future(fetch(session, url, root_url)) for url in urls]
loop.run_until_complete(asyncio.wait(tasks))
links = set()
for t in tasks:
expt = t.exception()
if expt is None:
ret = t.result()
links |= ret[0]
for w,c in ret[1].items():
words[w] += c
else:
print(expt)
processed_links |= set(urls)
urls = list(links - processed_links)
urls = urls[0:MAX_LINKS_BATCH]
# import pdb; pdb.set_trace()
i += 1
print(i, root_url, "-", "words:", len(words), "processed links", len(processed_links))
print("Most popular words on '{}':".format(root_url))
for w,c in sorted(words.items(),key=itemgetter(1),reverse=True)[0:N]:
print("{}: {}".format(w, c))
loop.close()
и
в
не
на
я
быть
он
с
что
а
по
это
она
этот
к
но
они
мы
как
из
у
который
то
за
свой
что
весь
год
от
так
о
для
ты
же
все
тот
мочь
вы
человек
такой
его
сказать
только
или
ещё
бы
себя
один
как
уже
до
время
если
сам
когда
другой
вот
говорить
наш
мой
знать
стать
при
чтобы
дело
жизнь
кто
первый
очень
два
день
её
новый
рука
даже
во
со
раз
где
там
под
можно
ну
какой
после
их
работа
без
самый
потом
надо
хотеть
ли
слово
идти
большой
должен
место
иметь
ничто
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment