Как стать автором
Обновить

Комментарии 41

Код совершенно не в стиле питона. Рекомендую заглянуть в PEP 8. Также небесполезно будет взять какой-нибудь букварь и почитать про возможности языка (словари, условный оператор, elif, format и так далее).
Спасибо за совет, особенно, за elif.
_GetSection не статичен, а self в аргументах заменяется на item, но при этом используется self в тексте.
if parser is not None: = if parser:
Чем вызван выбор lxml?
А вы бы что посоветовали?

Как по мне — одна из наиболее функциональных и удобных библиотек для работы с XML. Пожалуй даже самая удобная из всех, с которыми я работал.
Html5lib как более универсальную обертку. Хождение по ссылкам с помощью Scrapy. Более pythonic.
Не знаю чем оно более универсальное, судя по коду (быстро пролистал) функционал там только базовый. Тем не менее, как я смотрю, html5lib в lxml уже интегрирована lxml.de/html5parser.html

Насчет Scrapy поддерживаю.
Там кроме этого синтаксиса поддерживается синтаксис BeautifulSup и другие вкусности. Не понимаю логику минусующих.
За 10 минут сложилось такое впечатление: Документации нет. Что умеет не понятно. Написана целиком на Pyhton — скорее всего медленнее и памяти больше надо. Умеет ли XPath — не понятно. Умеет ли CSS селекторы — не ясно. Чем универсальнее — тоже не совсем понимаю. Может пример небольшой дадите?

Например спарсить топик и его метаданные с хабра:
import urllib # urllib для краткости примера. Обычно Scrapy или celery.
from lxml import etree
topic={}
tree=etree.HTML(urllib.urlopen('http://habrahabr.ru/blogs/python/121815/').read())
_topic_block=tree.cssselect("div.hentry")[0]
topic['title']=_topic_block.xpath("h2/span[@class='topic']/text()")[0]
topic['body']=etree.tounicode(_topic_block.xpath("div[@class='content']")[0])
topic['tags']=_topic_block.xpath("ul[@class='tags']/li/a/text()")
topic['author']=_topic_block.cssselect("a.nickname")[0].xpath("span/text()")[0]
При этом я обычно использую пару своих функций — расширений для XPath чтобы проще @class обрабатывать и не использую CSS селекторы. Тут уж совсем для краткости сделал.

По поводу минуса — это я сгоряча. А карму плюсанул для равновесия.
хм… а до этого мы о каком html5lib говорили?
То что вы приводили — часть lxml, тот который на гуглокоде отдельный проект на сколько я понимаю.
Ну, я написал про lxml.de/html5parser.html просто чтоб показать что lxml и html5 умеет парсить.
А так да, я про гуглокодовскую говорил.
Познав разницу вы остались с lxml? Он на мой взгляд сильно низкоуровневый.
Зато lxml почти не глючит и очень быстро работает. Когда нужно парсить в сутки от сотен тысяч страниц и более это выливается в банальную экономию денег.
Прежде всего, решением задачи. lxml дал самый быстрый отклик в плане работающего примера. Тут наверное нужно пояснить. До этого я писал полноценный скрипт на python только один раз (не считая всяких «hello world»), сам язык знаю плохо и потратил на решение задачи минимум времени (написание и отладку кода, копание в документации, сравнение различных инструментов). То есть то, что не заработало сразу или требовало длительного изучения, я отбрасывал сразу.

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

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

Что касается lxml, то он оказался простым, эффективным в плане гибкости применения, хорошо и с разных сторон документированным инструментом.
А код кривоватый, да
Статья очень похожа на курсовую работу.
Да ладно, я такое девушке постоянно пишу, когда какой-нибудь цитатник Конфуция нужно выкачать. Курсовая работа это все же посерьезнее, хотя бы на несколько недель интенсивной реализации. Не принижайте вы уж так технические вызу.
Курсовая работа — это все таки образцово-показательное выступление. Я же только брался показать, что всего за один день, со скромными познаниями в пайтоне, еще меньшим опытом и без углубления в документации и мучительный выбор, что ставить — пробелы или табуляцию (я, кстати, сразу выбрал табуляцию, просто потому что быстрее им ошибок меньше в отступах) — вполне реально решить конкретную задачу, буде такая появится.
«Чем вызван выбор lxml?» — тут вопросов нет, говорю Вам как Профессиональный Парсер. все правипльно. аналигов по скорости и адеквате нет!, но чтение статьи закончилось на первой строчке — urllib — получение HTML-страниц сайтов;, на этом Все. урл либ хорошо но при ПАРСИНГЕ соверщенно не подходит. я не говорю про проблемы с кодировкой и получением контенста, выы даже ИП не сможете нормлаьно поменять.

pycurl намного адекватный выбор.
э. а где urllib имеет дело с кодировкой? O_o
urllib — нативно на пейтоне, не требуется собирать pycurl (что может представлять проблему для win машин). Единственное, смена IP чуть геморойна.
НЛО прилетело и опубликовало эту надпись здесь
Scrapy удобно соединяет все, что нужно для web-краулинга, последующего парсинга html и сохранения результатов. Советую взглянуть в его сторону, и не изобретать велосипедов.
Поддерживаю. Хотя у меня впечатление что автор не осилит (не в обиду сказано).
Пытаюсь осилить. Однако, тут вот какая штука. Scrapy — мощный фреймворк. Он облегчает решение стандартных задач, но и устанавливает рамки. И он не подходит для первого знакомства с парсингом для таких новичков как я. Причины просты:
1. Требуется время на изучение, чтобы понять, чем именно он упрощает решение задач и как.
2. Заранее неизвестны неочевидные ограничения, которые начнут всплывать на практике и уже после того, как затрачены усилия на освоение базы.
3. Количество различных примеров и разноплановой документации для простого инструмента в несопоставимое количество раз больше, чем для фреймворка.
4. Дополнительные библиотеки, необходимые для установки. Во-первых это масса возможностей сделать ошибку. Так, например, я пытался twisted поставить на Win с помощь easy-install и все вроде бы хорошо ставилось, вот только библиотека не нашлась. Может надо было просто пути прописать к каталогу scripts, а может действительно нужно ставить через msi, но процесс на время затормозился.
4. Дополнительные библиотеки. Неминуемы отсылки документации к возможностям библиотек и время на изучение особенностей их использования во фреймворке.

В частности, сейчас я знаю (благодаря доброму совету и чтению документации по Srapy), что смог бы переписать решение задачи с использованием фреймворка. Но в очереди следующие, для решения которых нужно выбирать инструменты с оглядкой на фреймворк. Как подвесить краулер сервисом windows? Возникнут ли какие-нибудь особенности, если нужно записать данные не в файл, а в документ через API Google Docs? Можно ли вызывать Srapy из кода, а не из командной строки?
Есть и другие смутные вопросы, ответы на которые есть смысл искать, погрузившись в Srapy по самые гланды.

В любом случае, Srapy попробую. Спасибо за наводку!
У 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 неблокирующий а библиотека блокирующая.
Спасибо за пример! Утащил к себе в избранное.

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

Впрочем, думаю рано или поздно такие задачи появятся, и тогда советы придутся очень кстати.
Архив Голубятен в студию!
Ужас ужас.
Если используете lxml — используйте xpath
Почитайте про PEP8

Учитесь кодить на пайтоне, зачем здесь else?

if parser.group('gsource')=='Бизнес-журнале':
return 'Бизнес-журнал'
else:
return parser.group('gsource')


ну и т.д.
НЛО прилетело и опубликовало эту надпись здесь
Хоть и не хочется обидеть, но… Похвально конечно, что боле менее разобрались и задачу решили, но статью такую лучше не показывать публично. И код тоже.
Вообще, как уже сказали, по стилю написания очень похоже на курсовую или какую-то именно студенческую работу. Типа 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).
* Склеивать строки сложением (+) считается дурным тоном. Но тут есть варианты.

Можно и дальше продолжать в принципе…
Можно и дальше продолжать в принципе…

Так вы продолжайте не стесняйтесь, между прочим очень интересно и автору подозреваю тоже, как вы говорите надо склеивать строки?
С помощью join (он работает быстрее, чем последовательность конкатенаций).
Но данном случае это неактуально, потому что склеивание строк активно используется только при создании CSV вручную, а для этого, как уже написали выше, есть специальный модуль.
Спасибо за развернутые и полезные комментарии. Для того, чтобы узнать многое из описанного, потребовалось бы кипу всего перечитать. Например, сам никогда бы не задался вопросом, есть ли специальный модуль для записи CSV-файлов!

С кодировками вышла самая большая маета, осмыслить проблему логически не получилось и пришлось подбирать методом тыка. Наверное как раз из-за того, что в Python юникод != utf8.

С выносом XPath в конфиг все просто (кстати, да SQL я бы тоже вынес). Говорят, что человек, начинающий изучать два иностранных языка, путает слова и конструкции и только с опытом происходит надежное отделение двух языковых полей. Так и здесь: ХPath запросы, помещенные прямо в текст, отвлекали от кода. Кроме того, оказалось удобнее отделить написание python-кода, и отладку XPath. Охотно признаю, что опыт в том и другом сделает такое разделение избыточным.

По хранению в памяти согласен. Но в данной задаче памяти требовалось немного, а отлаживать отдельно парсинг и запись в файл показалось удобнее. На других объемах, разумеется, пришлось бы память экономить.
С кодировками проблемы у всех начинающих и многих продвинутых программистов. А юникод != utf8 практически везде, где есть юникод на уровне языка/фреймворка, просто далеко не все об этом задумываются и/или знают разницу.
>> Notepad++ — текстовый редактор с подсветкой синтаксиса:

SciTE(http://code.google.com/p/scite-ru/) лучше)
vim.
Еще раз спасибо всем за обсуждение, советы и замечания!

Узнал много нового и полезного, как из комментариев, так и благодаря им. Жаль, что не могу проголосовать, не ожидал, что время голосования истекает.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации