Scrapy非常基础的例子

26

你好,我在我的Mac电脑上安装了Python Scrapy,并尝试按照他们网站上第一个示例的步骤进行操作。

他们要运行的命令是:

scrapy crawl mininova.org -o scraped_data.json -t json

我不太明白这是什么意思?看起来Scrapy变成了一个单独的程序。我认为他们没有一个叫做crawl的命令。在例子中,他们有一段代码,这是MininovaSpider类和TorrentItem类的定义。我不知道这两个类应该放在哪里,是否应该放在同一个文件中,以及这个Python文件的名称是什么?


1
你想要做什么? - tjvr
我试图按照网站上的示例来爬取Minonova的项目。 - B.Mr.W.
今晚我将一些旧的Scrapy脚本推送到了Github,如果你想使用它们作为示例,请访问:https://github.com/dreamcc/Scrapy-Spiders - davidcondrey
请查看此答案 - Levon
2个回答

60

TL;DR: 请查看自包含最小示例脚本以运行Scrapy

首先,使用单独的.cfgsettings.pypipelines.pyitems.pyspiders包等来管理和处理您的网络爬虫逻辑是推荐的方法。它提供了模块化、关注点分离的功能,使事情有条理、清晰且易于测试。

如果您正在按照官方Scrapy教程创建项目,则可以通过特殊的scrapy命令行工具来运行网络爬虫:

scrapy crawl myspider

但是,Scrapy 也提供了一个API来从脚本运行爬虫

有几个关键概念需要提到:

  • Settings - 基本上是一个键值对的“容器”,它使用默认内置值进行初始化。
  • Crawler - 是主要的类,它像胶水一样连接了所有涉及到Scrapy网络爬虫的不同组件。
  • Twisted反应器 - 由于Scrapy是建立在Twisted异步网络库之上的,因此要启动爬虫,我们需要将其放入Twisted反应器中,简单来说,这是一个事件循环:

反应器是Twisted中事件循环的核心 - 驱动使用Twisted的应用程序的循环。事件循环是一种编程构造,它在程序中等待和分派事件或消息。它通过调用某些内部或外部的“事件提供者”来工作,该提供者通常会阻塞,直到事件到达,然后调用相关的事件处理程序(“分派事件”)。反应器为许多服务提供基本接口,包括网络通信、线程和事件分派。

这里是从脚本运行Scrapy的基本和简化过程:

  • create a Settings instance (or use get_project_settings() to use existing settings):

    settings = Settings()  # or settings = get_project_settings()
    
  • instantiate Crawler with settings instance passed in:

    crawler = Crawler(settings)
    
  • instantiate a spider (this is what it is all about eventually, right?):

    spider = MySpider()
    
  • configure signals. This is an important step if you want to have a post-processing logic, collect stats or, at least, to ever finish crawling since the twisted reactor needs to be stopped manually. Scrapy docs suggest to stop the reactor in the spider_closed signal handler:

请注意,在爬虫完成后,您还需要自行关闭Twisted反应器。这可以通过将处理程序连接到signals.spider_closed信号来实现。
def callback(spider, reason):
    stats = spider.crawler.stats.get_stats()
    # stats here is a dictionary of crawling stats that you usually see on the console        

    # here we need to stop the reactor
    reactor.stop()

crawler.signals.connect(callback, signal=signals.spider_closed)
  • configure and start crawler instance with a spider passed in:

    crawler.configure()
    crawler.crawl(spider)
    crawler.start()
    
  • optionally start logging:

    log.start()
    
  • start the reactor - this would block the script execution:

    reactor.run()
    

这是一个使用DmozSpider spider的自包含脚本示例,涉及item loadersinput and output processorsitem pipelines:

import json

from scrapy.crawler import Crawler
from scrapy.contrib.loader import ItemLoader
from scrapy.contrib.loader.processor import Join, MapCompose, TakeFirst
from scrapy import log, signals, Spider, Item, Field
from scrapy.settings import Settings
from twisted.internet import reactor


# define an item class
class DmozItem(Item):
    title = Field()
    link = Field()
    desc = Field()


# define an item loader with input and output processors
class DmozItemLoader(ItemLoader):
    default_input_processor = MapCompose(unicode.strip)
    default_output_processor = TakeFirst()

    desc_out = Join()


# define a pipeline
class JsonWriterPipeline(object):
    def __init__(self):
        self.file = open('items.jl', 'wb')

    def process_item(self, item, spider):
        line = json.dumps(dict(item)) + "\n"
        self.file.write(line)
        return item


# define a spider
class DmozSpider(Spider):
    name = "dmoz"
    allowed_domains = ["dmoz.org"]
    start_urls = [
        "http://www.dmoz.org/Computers/Programming/Languages/Python/Books/",
        "http://www.dmoz.org/Computers/Programming/Languages/Python/Resources/"
    ]

    def parse(self, response):
        for sel in response.xpath('//ul/li'):
            loader = DmozItemLoader(DmozItem(), selector=sel, response=response)
            loader.add_xpath('title', 'a/text()')
            loader.add_xpath('link', 'a/@href')
            loader.add_xpath('desc', 'text()')
            yield loader.load_item()


# callback fired when the spider is closed
def callback(spider, reason):
    stats = spider.crawler.stats.get_stats()  # collect/log stats?

    # stop the reactor
    reactor.stop()


# instantiate settings and provide a custom configuration
settings = Settings()
settings.set('ITEM_PIPELINES', {
    '__main__.JsonWriterPipeline': 100
})

# instantiate a crawler passing in settings
crawler = Crawler(settings)

# instantiate a spider
spider = DmozSpider()

# configure signals
crawler.signals.connect(callback, signal=signals.spider_closed)

# configure and start the crawler
crawler.configure()
crawler.crawl(spider)
crawler.start()

# start logging
log.start()

# start the reactor (blocks execution)
reactor.run()

以平常的方式运行它:

python runner.py

使用管道功能观察导出到items.jl的项目:

{"desc": "", "link": "/", "title": "Top"}
{"link": "/Computers/", "title": "Computers"}
{"link": "/Computers/Programming/", "title": "Programming"}
{"link": "/Computers/Programming/Languages/", "title": "Languages"}
{"link": "/Computers/Programming/Languages/Python/", "title": "Python"}
...

这里提供了Gist(欢迎改进):


注意:

如果您通过实例化Settings()对象来定义settings - 您将获得所有默认的Scrapy设置。但是,如果您想要例如配置现有的pipeline,或者配置DEPTH_LIMIT或调整任何其他设置,则需要通过settings.set()在脚本中设置它(如示例所示):

pipelines = {
    'mypackage.pipelines.FilterPipeline': 100,
    'mypackage.pipelines.MySQLPipeline': 200
}
settings.set('ITEM_PIPELINES', pipelines, priority='cmdline')

或者,使用已经预先配置了所有自定义设置的现有settings.py

from scrapy.utils.project import get_project_settings

settings = get_project_settings()

关于该主题的其他有用链接:


我们能否手动调用管道以此方式进行后处理项目? - pad
@Basj 我正在考虑制作一个示例 Github 项目,其中包括一个简单的脚本来运行 Scrapy。希望这周有时间。谢谢。 - alecxe
@Basj 好的,完成了 - 请查看更新。有反馈吗? :) - alecxe
@pad 还请查看更新 - 在示例中,我使用的是同一文件中定义的流水线。 - alecxe
@alecxe,这很棒,但如果我想要在并行进程中运行多个爬取,那么每个进程都需要有自己的反应器吗? - yangmillstheory
显示剩余3条评论

26

您可以先查看教程,而不是“Scrapy概览”网页。

教程表明Scrapy实际上是一个独立的程序。

运行命令scrapy startproject tutorial将创建一个名为tutorial的文件夹,并为您设置好几个文件。

例如,在我的情况下,模块/包itemspipelinessettingsspiders已添加到根包tutorial中。

tutorial/
    scrapy.cfg
    tutorial/
        __init__.py
        items.py
        pipelines.py
        settings.py
        spiders/
            __init__.py
            ...
TorrentItem 类应该放在 items.py 中,而 MininovaSpider 类则放在 spiders 文件夹中。
一旦项目设置完成,Scrapy 的命令行参数似乎相当简单。它们采用以下形式:
scrapy crawl <website-name> -o <output-file> -t <output-type>

如果你不想创建一个项目目录,也可以使用runspider命令来运行Scrapy,从而避免额外的开销。

scrapy runspider my_spider.py

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接