TL;DR:见Self-contained minimum example script to run scrapy。
首先,建议使用带有单独的.cfg、settings.py、pipelines.py、items.py、spiders 包等的普通 Scrapy 项目来保留和处理 Web 抓取逻辑。它提供了模块化、关注点分离,使事物保持有序、清晰和可测试。
如果您按照official Scrapy tutorial 创建项目,则您正在通过特殊的scrapy 命令行工具运行网络抓取:
scrapy crawl myspider
但是,Scrapy 也 提供了一个 API 到 run crawling from a script。
有几个关键概念需要提一下:
反应器是 Twisted 中事件循环的核心——该循环使用 Twisted 驱动应用程序。事件循环是一种编程结构,它等待和
在程序中调度事件或消息。它通过调用一些
内部或外部“事件提供者”,通常会阻塞,直到
事件已经到达,然后调用相关的事件处理程序
(“发送事件”)。反应堆提供基本接口
服务的数量,包括网络通信、线程和
事件调度。
这是从脚本运行 Scrapy 的一个基本且简化的过程:
-
创建一个Settings 实例(或使用get_project_settings() 来使用现有设置):
settings = Settings() # or settings = get_project_settings()
-
用传入的settings实例实例化Crawler:
crawler = Crawler(settings)
-
实例化一个蜘蛛(这就是最终的意义,对吧?):
spider = MySpider()
配置信号。如果您想拥有一个后处理逻辑collect stats,或者至少要完成爬网,这是一个重要的步骤,因为需要手动停止扭曲的reactor。 Scrapy 文档建议在 spider_closed signal 处理程序中停止 reactor:
请注意,您还必须自己关闭 Twisted reactor
蜘蛛完成后。这可以通过连接一个
signal.spider_close 信号的处理程序。
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)
这是一个使用 DmozSpider spider 并涉及 item loaders 与 input and output processors 和 item 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 设置。但是,例如,如果您想配置现有管道,或配置 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()
关于该主题的其他有用链接: