python - 使用 Celery 时 Scrapy 蜘蛛不跟踪链接

标签 python django scrapy twisted celery

我正在用 Python 编写一个爬虫程序,它可以爬取给定域中的所有页面,作为特定域搜索引擎的一部分。我正在使用 Django、Scrapy 和 Celery 来实现这一目标。场景如下:

我从用户那里收到一个域名,并在 View 中调用 crawl 任务,将域名作为参数传递:

crawl.delay(domain)

任务本身只是调用一个启动爬行过程的函数:

from .crawler.crawl import run_spider
from celery import shared_task

@shared_task
def crawl(domain):
    return run_spider(domain) 

run_spider 开始抓取过程,as in this SO answer , 将 MySpider 替换为 WebSpider

WebSpider 继承自 CrawlSpider,我现在使用它只是为了测试功能。定义的唯一规则采用一个 SgmlLinkExtractor 实例和一个回调函数 parse_page,它简单地提取响应 url 和页面标题,填充一个新的 DjangoItem(HTMLPageItem) 并将其保存到数据库中(效率不高,我知道)。

from urlparse import urlparse
from scrapy.contrib.linkextractors.sgml import SgmlLinkExtractor
from ..items import HTMLPageItem
from scrapy.selector import Selector
from scrapy.contrib.spiders import Rule, CrawlSpider

class WebSpider(CrawlSpider):
    name = "web"

    def __init__(self, **kw):
        super(WebSpider, self).__init__(**kw)
        url = kw.get('domain') or kw.get('url')
        if not (url.startswith('http://') or url.startswith('https://')):
            url = "http://%s/" % url
        self.url = url
        self.allowed_domains = [urlparse(url).hostname.lstrip('www.')]
        self.start_urls = [url]
        self.rules = [
            Rule(SgmlLinkExtractor(
                allow_domains=self.allowed_domains,
                unique=True), callback='parse_page', follow=True)
        ]

    def parse_start_url(self, response):
        return self.parse_page(response)

    def parse_page(self, response):
        sel = Selector(response)
        item = HTMLPageItem()
        item['url'] = response.request.url
        item['title'] = sel.xpath('//title/text()').extract()[0]
        item.save()
        return item

问题 是爬虫只抓取 start_urls 并且在遵循这种情况并使用 Celery 时不跟踪链接(或调用回调函数)。然而,通过 python manage.py shell 调用 run_spider 工作得很好!

另一个问题是 Item Pipelines 和日志记录不适用于 Celery。这使调试变得更加困难。我认为这些问题可能是相关的。

最佳答案

所以在检查 Scrapy 的代码并启用 Celery 日志记录之后,通过在 web_spider.py 中插入这两行:

from celery.utils.log import get_task_logger

logger = get_task_logger(__name__)

我能够找到问题所在: 在WebSpider的初始化函数中:

super(WebSpider, self).__init__(**kw)

CrawlSpider__init__ 函数调用_compile_rules简而言之,该函数将规则从 self.rules 复制到 self._rules,同时进行一些更改。 self._rules 是蜘蛛在检查规则时使用的。在定义规则之前调用CrawlSpider 的初始化函数导致一个空的self._rules,因此没有遵循任何链接。

super(WebSpider, self).__init__(**kw) 行移动到 WebSpider__init__ 的最后一行已修复问题。

更新 the previously mentioned SO answer 中的代码有一点错误.它会导致 react 器在第二次调用后挂起。修复很简单,在 WebCrawlerScript__init__ 方法中,只需移动这一行:

self.crawler.signals.connect(reactor.stop, signal=signals.spider_closed)

按照评论中的建议,在 if 语句之外。

更新 2: 我终于可以使用管道了!这不是 celery 问题。我意识到设置模块没有被读取。这只是一个导入问题。要修复它:

在 django 项目的设置模块 myproject/settings.py 中设置环境变量 SCRAPY_SETTINGS_MODULE:

import os
os.environ['SCRAPY_SETTINGS_MODULE'] = 'myapp.crawler.crawler.settings'

在您的 Scrapy 设置模块 crawler/settings.py 中,将您的 Scrapy 项目路径添加到 sys.path 以便设置文件中的相对导入工作:

import sys
sys.path.append('/absolute/path/to/scrapy/project')

根据您的情况更改路径。

关于python - 使用 Celery 时 Scrapy 蜘蛛不跟踪链接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24232744/

相关文章:

用于多个服务器的 python 流处理程序

python - 如何重定向到 flask 上的上一页?

python - 为什么 os.walk() 没有定义目录或文件?

Django 应用程序未连接远程数据库

django - Django 中的简单搜索

python - Scrapy 按条件停止分页?

parsing - Scrapy:将列表项解析到单独的行上

javascript - python scrapy : scraping dynamic information

python - QToolTip 中包含的变量不会自动更新

django - Ndb 型号 : assure uniqueness in datastore using custom key_name