scrapy通用项目和爬虫代码模板

日常在使用scrapy爬点自己感兴趣的东西时,总会频繁的进行startproject和genspider,然后重复性的将一些常见功能代码在scrapy库默认的模板上进行人工添加和完善(有时候更尴尬的是,可能长时间没用scrapy,导致一些写法已经忘记),这也不能责怪scrapy,毕竟通过其命令创建的项目和爬虫模板,应该是最简版,对于想深入研究scrapy或者想深度使用scrapy的人来说,就有点过于捡漏,当然,还会有人说,可以通过复制粘贴的方式,从其他已经编写好的项目中拿过来,这也可以走通,不过,如果能让scrapy在使用命令创建项目和爬虫的时候,自动添加进去我们可能常用的代码和功能,应该是最好的。

如果想达到上面的偷懒目的,就需要修改甚至添加scrapy的默认项目和爬虫模板,下面会详细介绍,并贴上笔者整理好的模板,抛砖引玉,同时希望可以帮到读者,甚至举一反三,读者可以自行定义自己想要的项目和爬虫模板。

一、修改默认模板思路

一般创建项目和爬虫时,使用scrapy startproject 和scrapy genspider命令,那么肯定scrapy命令是已经加入path环境变量且可接受后面两个参数,并完成相关创建工作,我们可以找到scrapy库,进入commands文件夹,发现这里就是scrapy终端命令文件,通过查看startproject.py和genspider.py内代码,基本可以确定,创建项目和爬虫的模板是在scrapy库文件夹内的templates文件夹内,我们打开,可以发现里面有project和spiders两个文件夹

1.1 project文件夹

进入后,会感觉非常梳理,里面有scrapy.cfg文件(即项目配置文件),点击进入module文件夹,里面就是items、settings、pipelines等我们看到的项目文件,只不过这些文件的后缀是tmpl

其实scrapy在创建项目的时候,做的主要工作如下:

  1. 将project文件夹复制到scrapy startproject 所在或所指定的文件夹内
  2. 将module文件夹名称修改为指定的项目名称
  3. 将module文件夹内的tmpl文件,变为py文件,即去除tmpl文件后缀

所以,我们只需要修改该文件夹内的对应文件,即可完成对创建项目的默认模板的修改

1.2 spiders文件夹

点击进去,里面就是basic、crawler等我们通过命令 scrapy genspider -l命令看到的可用spider模板列表,所以,我们只需要修改甚至在该文件夹内新增我们的spider模板(本质就是一个py文件),以后就可以通过scrapy genspider命令直接创建了。

1.3 指定模板路径

当然,我们直接修改scrapy库内的模板,影响太大,万一是多人或者多个项目共用一个scrapy库,肯定就直接对其他项目或使用者造成了影响,不过scrapy允许我们可以指定模板路径,这样就可以解决以上问题了

我们查看scrapy库里面的commands文件夹,里面有startproject.py文件,打开,可以看到最后有如下代码(同理,genspider.py内,也有类似下面的代码):

    @property
    def templates_dir(self):
        return join(
            self.settings['TEMPLATES_DIR'] or join(scrapy.__path__[0], 'templates'),
            'project'
        )

该函数是用于获取模板路径的,可以看到可以通过命令行settings内的TEMPLATES_DIR参数获取,或者直接使用scrapy库里的templates,既然如此,我们可以

  1. 将自己使用的模板(一定要包括项目和spiders模板)放置到某一指定文件路径下
  2. 然后在终端使用scrapy startproject或者scrapy genspider时,后面多传入一个settings参数,如下:
scrapy startproject -s TEMPLATES_DIR='your templates_path' <projectname> 
scrapy genspider -s TEMPLATES_DIR='your templates_path'  <spidername> <domain>

二、优化默认项目模板

笔者主要优化的是幕刃项目模板里面的settings和pipelines文件,

  1. settings文件:因为scrapy默认的settings文件内只是包含一些基本设置,并且UserAgent不太友好,一般都需要自行设置随机UA,还有其他一些常用设置也需要加进去
  2. pipelines文件:因为在pipelines文件内,笔者一般需要监听spider_opened和spider_closed事件,然后对应的处理一些事务,比如在爬虫关闭时,关闭文件或断开数据库连接等,所以也经常性的需要对scrapy默认pipelines进行修改,此处也要统一优化
  3. 增加itemloaders.py.tmpl文件,主要默认在项目内添加itemloaders,并在里面写好常规代码结构和参考,便于快速构建自己的itemloader,并用来自动完成较为复杂或常用的清洗item动作

2.1 pipelines优化如下:

# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://docs.scrapy.org/en/latest/topics/item-pipeline.html

# useful for handling different item types with a single interface
from scrapy.exceptions import DropItem

class ${ProjectName}Pipeline:
	#init the pipe instance
	def __init__(self,crawler):
		#refer settings args like self.args=crawler.settings.args
		pass

	@classmethod
	def from_crawler(cls,crawler):
		#called when project start
		p=cls(crawler)
		#register signals to specific pipe methods
		crawler.signals.connect(p.spider_opened, signal=signals.spider_opened)
		crawler.signals.connect(p.spider_closed, signal=signals.spider_closed)
		return p

	def spider_opened(self,spider):
		#called when spider is opened
		pass

	def process_item(self, item, spider):
		#called for each item that yield by spider
		#must either return item itself or raise DropItem error
		if :
			return item
		else:
			raise DropItem()

    def spider_closed(self,spider,reason):
		#called when spider is closed
		pass

其中:

  1. from_crawler类方法,主要是注册监听spider_opened和spider_closed信号,然后和对应方法进行绑定,如果不注册,则无法监听这两个信号并做相应处理,当然,你也可以注册监听其他信号,具体不再展开,可以点击https://docs.scrapy.org/en/latest/topics/signals.html 查看了解更多其他信号类型
  2. 增加常用的DropItem结构,因为在pipelines内,一般需要过滤掉无效的item

读者可以直接复制到自己的pipelines.py.tmpl文件内,并按照自己需要再添加常用功能和代码模板,可以大大提升撸码效率

2.2 settings优化如下:

from faker import Faker
ua=Faker()

BOT_NAME = '$project_name'

SPIDER_MODULES = ['$project_name.spiders']
NEWSPIDER_MODULE = '$project_name.spiders'

#auto close spider when countdown default 0
CLOSESPIDER_TIMEOUT = 0
#auto close spider when scrape pagecount
CLOSESPIDER_PAGECOUNT = 0
#auto close spider when scrape itemcount
CLOSESPIDER_ITEMCOUNT = 0
#auto close spider when occur errorcount
CLOSESPIDER_ERRORCOUNT = 0

# Crawl responsibly by identifying yourself (and your website) on the user-agent
USER_AGENT = ua.user_agent()
  1. 主要是添加了随机UA功能
  2. 另外增加了经常用来在调试时需设置的爬取指定数量网页、items等设置项,这样就不用手动复制粘贴设置等

2.3 增加itemloaders.py.tmpl模板

在project文件夹内,新增以上文件,并在文件内贴上如下代码:

# Define here the itemloaders used to process the item
#
# See documentation in:
# https://docs.scrapy.org/en/latest/topics/loaders.html
# demo codes here, imported into spider :
# from myproject.items import Product
# def parse(self, response):
#     l = ItemLoader(item=Product(), response=response)
#     l.add_xpath('name', '//div[@class="product_name"]')
#     l.add_xpath('name', '//div[@class="product_title"]')
#     l.add_xpath('price', '//p[@id="price"]')
#     l.add_css('stock', 'p#stock]')
#     l.add_value('last_updated', 'today') # you can also use literal values
#     return l.load_item()

import scrapy
from scrapy.loader import ItemLoader
from itemloaders.processors import TakeFirst,Join,MapCompose


class yourItemLoader(ItemLoader):
	# define the itemloader that process the item
	# define the default processor
	default_input_processor=lambda x:x
	default_output_processor=lambda y:y

	# define the input and output processor fror specific field
	fieldname_in=MapCompose(func,str)
	fieldname_in=TakeFirst()
  1. 以上主要写上itemloader用法,避免时间过长遗忘,还需要查询
  2. 增加定义自己itemloader的代码结构,提升撸码效率
  3. 最后,别忘了修改下scrapy下commads文件夹内的startproject.py文件内如下代码:

TEMPLATES_TO_RENDER = (
    ('scrapy.cfg',),
    ('${project_name}', 'settings.py.tmpl'),
    ('${project_name}', 'items.py.tmpl'),
    ('${project_name}', 'pipelines.py.tmpl'),
    ('${project_name}', 'middlewares.py.tmpl'),
    ('${project_name}', 'itemloaders.py.tmpl'),   #此处注册下自己新增的模板文件
)

三、优化默认爬虫模板

笔者经常使用的就是basic和crawler爬虫模板,所以,只演示对这两个模板的修改优化

3.1 basic

优化代码如下:

import scrapy,requests
from scrapy import signals

class $classname(scrapy.Spider):
	name = '$name'
	allowed_domains = ['$domain']
	start_urls = [
		'http://$domain/',
	]

	#spider level settings,highest priority
	custom_settings=dict(
		CLOSESPIDER_ITEMCOUNT=10,
	)


	@classmethod
	def from_crawler(cls, crawler):
		#called when crawl started
		#register signals with spider methods,such as opened and closed,when you want to do somethings following specific signals
		s=cls()
		crawler.signals.connect(s.spider_opened, signal=signals.spider_opened)
		crawler.signals.connect(s.spider_closed, signal=signals.spider_closed)
		return s


	def spider_opend(self,spider):
		#called when spider open,unnecessory
		pass


	def start_requests(self):
		#called automatically when spider start, only called just once
		#unnecessory,if you want to reset reqeust header ,you can reload this method
		#otherwise,scrapy will generate requests from list start_urls,and call the callback method parse fallback
		#must yield request
		pass
		

	def parse(self, response):
		#must either yield requests or items
		pass


    def spider_closed(self,spider,reason):
		##called when spider close,unnecessory
		pass
  1. 增加了定义spider级别的settings方法,可以针对该spider自定义一些设置项
  2. 增加了from_crawler类方法,注册了spider_opened和spider_closed信号
  3. 增加了start_requests方法,如果不需要,可以删除,否则,就可以不用再自行撸代码

3.2 crawler

from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from scrapy import signals

class $classname(CrawlSpider):
    name = '$name'
    allowed_domains = ['$domain']
    start_urls = ['http://$domain/']

    rules = (
        #use re to extract urls from start_urls , and then parse by callback methods
        #:allow:str or tuple ,specify urls that extract with re
        #:allow:str or tuple ,specify urls that won't extract with re
        #:restrict_xpaths: str or tuple ,specify area that extract urls with xpath
        Rule(LinkExtractor(allow=r'Items/',deny='',restrict_xpaths='',), follow=True),
        Rule(LinkExtractor(allow=r'tags/'), callback='parse_item'),
    )


    @classmethod
    def from_crawler(cls, crawler):
        #called when crawl started
        #register signals with spider methods,such as opened and closed,when you want to do somethings following specific signals
        s=cls()
        crawler.signals.connect(s.spider_opened, signal=signals.spider_opened)
        crawler.signals.connect(s.spider_closed, signal=signals.spider_closed)
        return s

    def spider_opend(self,spider):
        #called when spider open,unnecessory
        pass


    def parse_item(self, response):
        item = {}
        #item['domain_id'] = response.xpath('//input[@id="sid"]/@value').get()
        #item['name'] = response.xpath('//div[@id="name"]').get()
        #item['description'] = response.xpath('//div[@id="description"]').get()
        return item


    def spider_closed(self,spider,reason):
        ##called when spider close,unnecessory
        pass
  1. 新增了from_crawler类方法,注册了spider_opened和spider_closed信号
  2. 增加了Rules常用的语法结构,避免自行撸代码或忘记语法

3.3 新增自定义spider模板

可以在spiders文件夹内,自行创建.tmpl文件,写好自己的爬虫蜘蛛模板,以后就可以在命令行内,通过scrapy genspider -t [templatename] <spidername> <domain>直接使用

四、写在最后

其实scrapy允许自己对该库进行更深程度的定制,包括对middlewares文件,甚至在模板内自行添加命令行命令等,或者对scrapy库源代码进行直接修改

或者,如果对scrapy的selector用起来比较爽(笔者觉得的确比lxml和beatifulsoup好用),因为其整合了xpath、css和re,并且支持链式操作,也可以将selector引入自己的模块内直接使用,包括LinkExtracto等等

后续笔者会分享更多scrapy比较好玩的功能。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值