Pull to refresh

Comments 41

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

Как по мне — одна из наиболее функциональных и удобных библиотек для работы с 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 чуть геморойна.
UFO just landed and posted this here
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')


ну и т.д.
UFO just landed and posted this here
Хоть и не хочется обидеть, но… Похвально конечно, что боле менее разобрались и задачу решили, но статью такую лучше не показывать публично. И код тоже.
Вообще, как уже сказали, по стилю написания очень похоже на курсовую или какую-то именно студенческую работу. Типа 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/) лучше)
Еще раз спасибо всем за обсуждение, советы и замечания!

Узнал много нового и полезного, как из комментариев, так и благодаря им. Жаль, что не могу проголосовать, не ожидал, что время голосования истекает.
Sign up to leave a comment.

Articles