scrapy通用專案和爬蟲程式碼模板

ckxllf發表於2021-03-22

  日常在使用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:

  # 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訊號,然後和對應方法進行繫結,如果不註冊,則無法監聽這兩個訊號並做相應處理,當然,你也可以註冊監聽其他訊號,具體不再展開,可以點選 檢視了解更多其他訊號型別

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

  #

  # 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 = [

  '

  ]

  #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 = [']

  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等等。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69945560/viewspace-2764264/,如需轉載,請註明出處,否則將追究法律責任。

相關文章