Pull to refresh
5
0
Александр Семёнов @semenoffalex

User

Send message
Есть замечательная книга Interactive Data Visualization for the Web по D3.js с интерактивными примерами. Онлайн версия книги бесплатная.
Вот ещё одно недоделанное исследование аудитории групп VK. Оффлайн версия

Жаль кончилось свободное время на всё это
Год назад тоже баловался парсингом) image
Если честно, немного удивительно, что Вы используете модель мешка слов, ведь она не учитывает порядок слов.

На самом деле, реализация алгоритма шинглов использует тот же коэффициент Жаккара. Только в данном случае, вместо слов, оперируют шинглами (на практике — хэшами шинглов, но это уже детали...).

Попросту говоря, шинглы — это кортежи из нескольких слов, построенные следующим образом (рисунок схематический):

Чисто иллюстративный пример:

  • слон ест красное яблоко
  • яблоко ест красного слона

(у некоторых слов разные окончания, но будем считать, что в качестве предварительной обработки мы используем лемматизатор).

Если использовать модель мешка слов, то получится, что эти два предложения дубликаты, поскольку содержат идентичные наборы слов.

Что на это скажет алгоритм шинглов:

Если использовать в качестве шинглов — кортежы слов, взятых через одно, получим:
  • слон ест красное яблоко -> A = {слон, красный} и {ест, яблоко}
  • яблоко ест красного слона -> B = {яблоко, красный} и {ест, слон}

Множества А и В не содержат одинаковых кортежей. Поэтому, пересечение A и B, даст пустое множество. Таким образом, можно заключить что данные тексты не дубликаты.

Ещё раз обращаю внимание — пример чисто иллюстративный, но, надеюсь, что общую концепцию мне удалось проиллюстрировать :-)

P.S. На самом деле, именно характер данных, их объём и другие особенности предметной области диктуют алгоритм обработки. Так что, если в Вашем случае описанный алгоритм работает хорошо, то, действительно, не стоит усложнять систему.

В данном комментарии, я просто хотел показать, что в общем случае Алгоритм шинглов более эффективный для идентификации дубликатов.
С помощью join (он работает быстрее, чем последовательность конкатенаций).
Но данном случае это неактуально, потому что склеивание строк активно используется только при создании CSV вручную, а для этого, как уже написали выше, есть специальный модуль.
Хоть и не хочется обидеть, но… Похвально конечно, что боле менее разобрались и задачу решили, но статью такую лучше не показывать публично. И код тоже.
Вообще, как уже сказали, по стилю написания очень похоже на курсовую или какую-то именно студенческую работу. Типа 2 дня перед зачетом, быстренько прочитал первые 5 абзацев из каждого мануала и начал строчить статью с как можно большим наборов умных слов и растянутыми предложениями… Это уж очень в глаза бросается.

По коду:
* все-таки не понимаю зачем XPath вынесли в конфиг… SQL запросы в своих программах тоже в конфиг будете выносить?
* лесенки из if — это как-то очень подозрительно…
* вместо if len(src)==0 можно писать if not src: и т.п.
* писать if condition: do smth (if и тело подвыражения на одной строке) хоть и можно, но очень не рекомендуется
* строки кода длиннее 80 символов не рекомендуются. Если пишите цепочку функций, лучше переносите на след. строку, обернув в скобки:
m.synopsis = get_text(item,cfg['sgolub']['list']['xpath_synopsis']).strip('\n').replace('\n',u' ').replace(';',u'|').strip().encode('utf-8')
заменяем на
m.synopsis = (
    get_text(item,cfg['sgolub']['list']['xpath_synopsis'])
    .strip('\n')
    .replace('\n',u' ')
    .replace(';',u'|')
    .strip()
    .encode('utf-8'))

* генерировать CSV вручную — последнее дело. Есть специальный модуль, встроенный в Python docs.python.org/library/csv.html
* вместо
fdoc = open(fname, 'w')
fdoc.write(m.text)
fdoc.close()

пишем
with open(fname, 'w') as fdoc:
    fdoc.write(m.text)
— после выхода из with или если случится Exception файл закроется автоматически. Файловые дескрипторы гарантированно не утекают
* self.mlist+=[m] заменяем на self.mlist.append(m)
* Хранить ВСЕ скачанные материалы в памяти (self.mlist) не рационально. Лучше записывать в файл сразу после распарсивания очередной статьи. yield вам в помощь. Хотя тут много уже переписывать придется.
* Везде по коду натыканы .encode('utf-8') .encode('cp1251'). Может названия кодировок в конфиг вынести? Да и внутри программы лучше юникодом пользоваться (в Python юникод != utf8).
* Склеивать строки сложением (+) считается дурным тоном. Но тут есть варианты.

Можно и дальше продолжать в принципе…
У Scrapy есть преимущество в том, что он обладает высокой поизводительностью (может качать десятки документов одновременно) и кучей готовых вспомогательных модулей, например для защиты от повторной загрузки уже загруженных страниц и зацикливания, поддержка Cookies и пр.
Есть модули для создания к нему веб-интерфейса. Есть встроенная telnet консоль (т.е. можно подключиться к запущенному и работающему пауку по telnet и выполнять внутри него любые команды Python прям во время работы). Но при этом нужно иметь в виду, что он работает асинхронно и для сохранения собранных данных в БД уже нужно изворачиваться.
Чтобы сохранить данные не в файл а в GoogleDocs тоже придется дополнительно потрудиться…
Вызвать Scrapy из кода можно, но эта возможность по-моему не документирована. Я как-то так его стартовал:
""" run as `python this_file.py <spider_name> <start_url>` """
import os
os.environ.setdefault('SCRAPY_SETTINGS_MODULE', 'forums.settings')

import sys
from scrapy.core.queue import ExecutionQueue
from scrapy.core.manager import scrapymanager
from scrapy.spider import spiders
import scrapy_syslog_log as syslog_log

def main():
    syslog_log.patch()
    scrapymanager.configure(control_reactor=True)
    q=ExecutionQueue()
    spider_name, url=get_spider_and_url()
    spider=spiders.create(spider_name)
    q.append_url(spider.getFetchUrl(url), spider)
    scrapymanager.queue=q
    scrapymanager.start()#this is blocking call
    sys.stdout.write('OK')
    sys.exit(0)


def get_spider_and_url():
    if len(sys.argv)<3:
        sys.stdout.write('ERR')
        sys.exit('NOT ALL ARGS')

    return sys.argv[1:]

if __name__=='__main__':
    main()
Чтоб этот кусок кода написать, пришлось «погрузиться в Srapy по самые гланды».

Для GoogleDocs попробуйте официальную библиотеку от Google code.google.com/p/gdata-python-client/.
Вот примеры: code.google.com/p/gdata-python-client/source/browse/samples/docs/docs_example.py code.google.com/p/gdata-python-client/source/browse/samples/docs/resumable_upload_sample.py
Но со Scrapy ее будет не очень легко интегрировать. Разве что пул потоков организовать т.к. Scrapy неблокирующий а библиотека блокирующая.
UFO landed and left these words here
Очень интересно хотелось бы больше информации

По вот этой части:
>>выполнение POST запросов, поддержка куков и сессий, аутентификации

Раньше я для этого использовал mechanize — конкретно авторизация, заполнение и отправка форм, получение данных из форм редактирования.

Scrapy позволяет это?
По сравнению с Mechanize есть одно очень важное преимущество — производительность. Scrapy работает поверх Twisted — асинхронного фреймворка. Поэтому держать по тысячи соединений одновременно вполне реально.
Да, все это можно. Делается так:
FormRequest.from_response(response,
                    formdata={'username': 'john', 'password': 'secret'},
                    callback=self.after_login)


Scrapy также следует редиректам, хранит куки, устанавливаемые с сервера (иногда нужно отключать).
JavaScript код не выполняет, поэтому если сайт на Ajax, запросы необходимо прописывать вручную.
И все это из коробки.
Не, ну если знаете Node лучше, чем Twisted/Scrapy то пишите на нем. Хотя XPath запросы везде должны быть одинаковые, не вижу здесь проблемы)))
Просто Sсrapy это не «еще одна библиотека для ПАРСИНГА страничек». Это фреймворк для написания веб-пауков. В Scrapy при желании можно использовать любую библиотеку для парсинга. Я использую lxml, хотя по-умолчанию там libxml2.

Фишка Scrapy в том, что он не говорит, что «Twisted это в первую очередь надстройка над Python. А то, какого вы паука на нем напишете зависит от вашей фантазии и знания Python». Он говорит — скачиванием страничек я занимаюсь сам, диспетчеризацией данных, очередью запросов, приоритетами, обработкой исключений, поиском ссылок, защитой от зацикливания, защитой от того, что странички "/catalog.php?p1=1&p2=2" и "/catalog.php?p2=2&p1=1" это одно и то же, удаленная консоль, отладка памяти, REST интерфейс для управления, логгирование, генератор кода, отличная документация и куча других штуковин. Причем все это можно легко отключить или доработать. Есть готовая инфраструктура, вам остается только написать стартовую страницу, XPath запросы и (опционально) механизм для сохранения результатов (только если нужно что-то сложнее CSV/XML — для этих есть уже готовые экспортирующие конвейеры).
Если там AJAX-запрос, возвращающий структурированные в JSON/XML/whatever данные — просто пишем Request на адрес хэндлера, входные параметры придётся упаковывать вручную, с результатом делаем что хотим. Если запрос возвращает кусок HTML, предназначенный для встраивания в разметку — можно использовать прямо XPathItemLoader (правда, если у этого куска несколько элементов верхнего уровня, придётся обернуть в фиктивный элемент, иначе парсер расстроится).
С частичными постбэками ASP.NET, возможно, будет сложнее.
Как это не странно, но основные усилия при разработке Web Mining приложений уходят не на анализ данных а на 'исполнительную обертку' вокруг парсеров — отслеживание и корректное реагирование на ошибки (смена дизайна, проблемы с интернетом или с сайтами..), сокрытие робота от владельцев (в т.ч. борьба с теми кто борется против роботов — паузы, имитация браузеров, каптчи), много потоковая работа (загрузка с 1 сайта происходит значительно медленнее канала на сервере) и подстановка разных интерфейсов (IP адрес загрузчика), сбор статистики и оптимизация параметров работы (очень большой и важный раздел при написании веб-сканеров) и банальные проблемы с имеющимися БД (медленные они) — прикручивание различных key-value БД, memory-БД и т.п.
А в чем собственно проблема? Сайт парситься на ура. он же сео-френдли — в нем по определению нет проблем с доступом к информации.
Для примера вот дерево рубрик c yell.ru

http://pastebin.com/BmVXNeiC

Время написания скрипта — минут 8 с просмотром исходника сайта, регулярок нет, dom, xpath не используется.
Размер скрипта 50 строк, 40 из которых сохраняют атрибуты для xml вывода, можно и меньше — но бессмысленно.

Время работы скрипта — 27054ms = 27 секунд.
Итого — 2157 рубрик (учитывая промежуточные разделы)

Так в чем проблема? Посмотрел остальные страницы с информацией по компаниям — абсолютно не вижу проблем при наличии правильных рук.
Вам правильно говорят — у любого браузера есть инструмент, с помощью которого можно отследить посылаемые запросы. Тот же Fiddler, на пример.

Не нужно анализировать url на странице — нажимаете кнопку на сайте и смотрите какой запрос посылается на сервер.
Вы, судя по каментам, не понимаете, о чем вам пишут.

1. Нужный URL прекрасно находится в том же firebug'e. Это даже проще, чем ковыряться в исходнике странички.
2. При этом не нужно разбирать и выполнять JS. Совсем не нужно.

В итоге, что нам остается? Получить нужные данные по прямому URL и заняться их разбором, а не разбирать всю страницу целиком. Профит? Однозначно!

Information

Rating
Does not participate
Location
Москва, Москва и Московская обл., Россия
Date of birth
Registered
Activity