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

  日常在使用scrapy爬点自己感兴趣的东西时,总会频繁的进行startproject和genspider,然后重复性的将一些常见功能代码在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在创建项目的时候,做的主要工作如下:

  将project文件夹复制到scrapy startproject 所在或所指定的文件夹内

  将module文件夹名称修改为指定的项目名称

  将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,既然如此,我们可以

  将自己使用的模板(一定要包括项目和spiders模板)放置到某一指定文件路径下

  然后在终端使用scrapy startproject或者scrapy genspider时,后面多传入一个settings参数,如下:

  scrapy startproject -s TEMPLATES_DIR='your templates_path'

  scrapy genspider -s TEMPLATES_DIR='your templates_path'

  二、优化默认项目模板

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

  settings文件:因为scrapy默认的settings文件内只是包含一些基本设置,并且UserAgent不太友好,一般都需要自行设置随机UA,还有其他一些常用设置也需要加进去

  pipelines文件:因为在pipelines文件内,笔者一般需要监听spider_opened和spider_closed事件,然后对应的处理一些事务,比如在爬虫关闭时,关闭文件或断开数据库连接等,所以也经常性的需要对scrapy默认pipelines进行修改,此处也要统一优化

  增加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

  其中:

  from_crawler类方法,主要是注册监听spider_opened和spider_closed信号,然后和对应方法进行绑定,如果不注册,则无法监听这两个信号并做相应处理,当然,你也可以注册监听其他信号,具体不再展开,可以点击https://docs.scrapy.org/en/latest/topics/signals.html 查看了解更多其他信号类型

  增加常用的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()

  主要是添加了随机UA功能

  另外增加了经常用来在调试时需设置的爬取指定数量网页、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()

  以上主要写上itemloader用法,避免时间过长遗忘,还需要查询

  增加定义自己itemloader的代码结构,提升撸码效率

  最后,别忘了修改下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 大连做人流哪家好 mobile.dlrlyy.com/

  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

  增加了定义spider级别的settings方法,可以针对该spider自定义一些设置项

  增加了from_crawler类方法,注册了spider_opened和spider_closed信号

  增加了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

  新增了from_crawler类方法,注册了spider_opened和spider_closed信号

  增加了Rules常用的语法结构,避免自行撸代码或忘记语法

  3.3 新增自定义spider模板

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

  四、写在后面

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

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

请使用浏览器的分享功能分享到微信等