Scrapy- Как извлечь все сообщения блога из категории?

Я использую scrapy для извлечения всех сообщений из моего блога. Проблема в том, что я не могу понять, как создать правило, которое читает все сообщения в любой заданной категории блога?

пример: в моем блоге в категории "Настройка среды" 17 сообщений. Таким образом, в коде scrapy я могу жестко закодировать его как данность, но это не очень практичный подход.

start_urls=["https://edumine.wordpress.com/category/ide- configuration/environment-setup/","https://edumine.wordpress.com/category/ide-configuration/environment-setup/page/2/","https://edumine.wordpress.com/category/ide-configuration/environment-setup/page/3/"] 

Я читал похожие сообщения, связанные с этим вопросом, размещенные здесь на SO, например 1, 2, 3, 4, 5, 6, 7, но я не могу найти ответ ни в одном из них. Как видите, единственная разница заключается в количестве страниц в приведенных выше URL-адресах. Как я могу написать правило в scrapy, которое может читать все сообщения в блоге в категории. И еще один тривиальный вопрос: как мне настроить паука для сканирования моего блога, чтобы, когда я публикую новую запись в блоге, краулер мог немедленно обнаружить ее и записать в файл.

Это то, что у меня есть для класса пауков

from BlogScraper.items import BlogscraperItem
from scrapy.spiders import CrawlSpider,Rule
from scrapy.selector import Selector
from scrapy.linkextractors import LinkExtractor
from scrapy.http import Request


class MySpider(CrawlSpider):
    name = "nextpage" # give your spider a unique name because it will be used for crawling the webpages

    #allowed domain restricts the spider crawling
    allowed_domains=["https://edumine.wordpress.com/"]
    # in start_urls you have to specify the urls to crawl from
    start_urls=["https://edumine.wordpress.com/category/ide-configuration/environment-setup/"]

    '''
    start_urls=["https://edumine.wordpress.com/category/ide-configuration/environment-setup/",
                "https://edumine.wordpress.com/category/ide-configuration/environment-setup/page/2/",
                "https://edumine.wordpress.com/category/ide-configuration/environment-setup/page/3/"]


    rules = [
                Rule(SgmlLinkExtractor
                    (allow=("https://edumine.wordpress.com/category/ide-configuration/environment-setup/\d"),unique=False,follow=True))
            ]
'''
    rules= Rule(LinkExtractor(allow='https://edumine.wordpress.com/category/ide-configuration/environment-setup/page/'),follow=True,callback='parse_page')

    def parse_page(self, response):

        hxs=Selector(response)
        titles = hxs.xpath("//h1[@class='entry-title']")
        items = []
        with open("itemLog.csv","w") as f:
             for title in titles:
                item = BlogscraperItem()
                item["post_title"] = title.xpath("//h1[@class='entry-title']//text()").extract()
                item["post_time"] = title.xpath("//time[@class='entry-date']//text()").extract()
                item["text"]=title.xpath("//p//text()").extract()
                item["link"] = title.select("a/@href").extract()

                items.append(item)

                f.write('post title: {0}\n, post_time: {1}\n, post_text: {2}\n'.format(item['post_title'], item['post_time'],item['text']))
                print "#### \tTotal number of posts= ",len(items), " in category####"


        f.close()

Любая помощь или предложения по ее решению?


person mnm    schedule 28.09.2015    source источник
comment
Поскольку WordPress хранит сообщения в базе данных, почему бы вам не использовать базу данных вместо скрапа?   -  person Casimir et Hippolyte    schedule 28.09.2015
comment
Потому что я хотел бы, чтобы паук сканировал не только мой блог, но и другие блоги, и я думаю, что только по этой причине лучше всего подходит scrapy.   -  person mnm    schedule 28.09.2015


Ответы (1)


У вас есть некоторые вещи, которые вы можете улучшить в своем коде, и две проблемы, которые вы хотите решить: чтение сообщений, автоматическое сканирование.

Если вы хотите получить содержимое нового поста в блоге, вам нужно перезапустить паука. В противном случае у вас будет бесконечный цикл. Естественно, в этом случае вы должны убедиться, что вы не очищаете уже очищенные записи (база данных, чтение доступных файлов при запуске паука и т. д.). Но у вас не может быть паука, который работает вечно и ждет новых записей. Это не цель.

Ваш подход к хранению сообщений в файле неверен. Это означает, почему вы очищаете список элементов, а затем ничего не делаете с ними? И почему вы сохраняете элементы в функции parse_page? Для этого существуют конвейеры элементов, вы должны написать один и сделать там экспорт. И f.close() не нужен, потому что вы используете оператор with, который делает это за вас в конце.

Ваша переменная rules должна вызывать ошибку, потому что она не является итерируемой. Интересно, вы даже тестировали свой код. И Правило слишком сложное. Вы можете упростить это до этого:

rules = [Rule(LinkExtractor(allow='page/*'), follow=True, callback='parse_page'),]

И он следует за каждым URL-адресом, в котором есть /page.

Если вы запустите свой парсер, вы увидите, что результаты отфильтрованы из-за ваших разрешенных доменов:

Filtered offsite request to 'edumine.wordpress.com': <GET https://edumine.wordpress.com/category/ide-configuration/environment-setup/page/2/>

Чтобы решить эту проблему, измените свой домен на:

allowed_domains = ["edumine.wordpress.com"]

Если вы хотите получить другие сайты WordPress, просто измените его на

allowed_domains = ["wordpress.com"]
person GHajba    schedule 28.09.2015
comment
Квинтал спасибо вам @GHajba за такой подробный ответ. Спасибо за указание на ошибки и возможные пути их решения. Это очень обогащает. Я только начал с scrapy, поэтому архитектура еще не ясна. Будем признательны за любую хорошую ссылку, которая легко понять о конвейерах элементов. Официальная документация пока слишком сложна для понимания. Да, переменная rules выдавала ошибку, но я понятия не имел, как ее исправить. - person mnm; 28.09.2015
comment
Другой связанный с этим вопрос заключается в том, что иногда, если сообщение в блоге слишком длинное, мы видим URL-ссылку, например «Продолжить чтение», щелкнув по ней, можно перейти к полному сообщению. Как мне закодировать его в xpath? - person mnm; 30.09.2015
comment
Есть несколько подходов. Я не буду кодировать его в XPath, но в parse_page, чтобы увидеть, содержит ли контент ссылку. Если да, я бы yield добавил новую Request к подробной статье с другой функцией парсера, которая очищает подробный пост. В этом случае я не буду yield найденным item. Это один подход. - person GHajba; 30.09.2015
comment
Спасибо за быстрый ответ. Позвольте мне попробовать это. Я мог бы вернуться сюда снова, если я не могу заставить его работать. пальцы скрещены, я надеюсь, что смогу заставить это работать. - person mnm; 30.09.2015
comment
Мне интересно, как мне проверить наличие нового опубликованного сообщения, чтобы скребок записывал новое сообщение только в уже существующий файл старых сообщений? Любое предложение о том, как совершить этот подвиг? - person mnm; 01.10.2015