1. 程式人生 > 其它 >scrapy框架的簡介與使用

scrapy框架的簡介與使用

Scrapy框架

    • crapy Engine(引擎): 負責Spider、ItemPipeline、Downloader、Scheduler中間的通訊,訊號、資料傳遞等。

    • Scheduler(排程器): 它負責接受引擎傳送過來的Request請求,並按照一定的方式進行整理排列,入隊,當引擎需要時,交還給引擎。

    • Downloader(下載器):負責下載Scrapy Engine(引擎)傳送的所有Requests請求,並將其獲取到的Responses交還給Scrapy Engine(引擎),由引擎交給Spider來處理,

    • Spider(爬蟲):它負責處理所有Responses,從中分析提取資料,獲取Item欄位需要的資料,並將需要跟進的URL提交給引擎,再次進入Scheduler(排程器),

    • Item Pipeline(管道):它負責處理Spider中獲取到的Item,並進行進行後期處理(詳細分析、過濾、儲存等)的地方.

    • Downloader Middlewares(下載中介軟體):你可以當作是一個可以自定義擴充套件下載功能的元件。

    • Spider Middlewares(Spider中介軟體):你可以理解為是一個可以自定擴充套件和操作引擎和Spider中間通訊的功能元件(比如進入Spider的Responses;和從Spider出去的Requests)


          •  

 

Scrapy框架的使用

  • 建立一個scrapy專案
    • scrapy startproject  專案名
    • scrapy genspider  爬蟲名 域名

  • 執行爬蟲專案
    • scrapy crawl  爬蟲名
    • 建立完爬蟲專案後會自動生成以下程式碼
    •  

      import scrapy
      
      
      class TestSpider(scrapy.Spider):
          # 爬蟲名稱
          name = 'test'
          # 設定允許爬取的域(可以指定多個)
          allowed_domains = ['baidu.com']
          # 設定起始url(設定多個)
          start_urls = ['http://baidu.com/']
      
          def parse(self, response):
              '''
              是一個回撥方法,起始url請求成功後,會回撥這個方法
              :param response: 響應結果
              :return:
              '''
              pass

       

  • 在parse中自定義解析方式
    •     def parse(self, response):
              '''
              在parse回撥方法中
              step1;提取目標資料
              step2;獲取新的url
              :param response: 請求的響應結果
              :return:
              '''
              print(response.status)
              #response.xpath(): 使用xpath語法,得到的是selectorlist物件
              # response.css(): 使用css選擇器,得到的是selectorlist物件
              # extract(): 將selector 序列化為unicode字串
              # step1;提取目標資料
              # 獲取分類列表
              tags = response.xpath('//div[@class="Taright"]/a')
              # tags = response.css('.Taright a')
              for tag in tags:
                  # 例項化一個item,用來儲存資料
                  tag_item = ChinazspidertagItem()
                  # 獲取網站分類的名稱
                  # tagname = tag.xpath('./text()')[0].extract()
                  tagname = tag.xpath('./text()').extract_first('')
                  tag_item['tagname'] = tagname
                  # 使用css取值(文字)
                  # tagname = tag.css('::text').extract_first('')
                  # 獲取網站分類的首頁url地址
                  # first_url = tag.xpath('./@href')[0].extract()
                  first_url = tag.xpath('./@href').extract_first('')
                  tag_item['firsturl'] = first_url
                  # css取值(屬性)
                  # first_url = tag.css('::attr(href)').extract_first('')
                  print(tag_item)
                  # print(type(tagname),type(first_url))
                  # print(tagname,first_url)
                  # 將獲取到的資料交給管道處理
                  yield tag_item
                  # http://top.chinaz.com/hangye/index_yule_yinyue.html
                  # http://top.chinaz.com/hangye/index_yule_yinyue_2.html
                  '''
                  url,設定需要發起請求的url地址
                  callback=None,設定請求成功後的回撥方法
                  method='GET',請求方式,預設為get請求
                  headers=None,設定請求頭,字典型別
                  cookies=None,設定cookies資訊,模擬登入使用者,字典型別
                  meta=None,傳遞引數(字典型別)
                  encoding='utf-8',設定編碼
                  dont_filter=False, 是否去重,預設為false,表示去重
                  errback=None, 設定請求失敗後的回撥
                  '''
                  yield scrapy.Request(first_url,callback=self.parse_tags_page)

       

  • 關於yeild函式介紹
    • 簡單地講,yield 的作用就是把一個函式變成一個 generator(生成器),帶有 yield 的函式不再是一個普通函式,Python 直譯器會將其視為一個 generator,帶有yeild的函式遇到yeild的時候就返回一個迭代值,下次迭代時, 程式碼從 yield 的下一條語句繼續執行,而函式的本地變數看起來和上次中斷執行前是完全一樣的,於是函式繼續執行, 直到再次遇到 yield。

    • 通俗的講就是:在一個函式中,程式執行到yield語句的時候,程式暫停,返回yield後面表示式的值,在下一次呼叫的時候,從yield語句暫停的地方繼續執行,如此迴圈,直到函式執行完。

     

    Item pipeline(管道檔案)使用
    • 當Item在Spider中被收集之後,它將會被傳遞到Item Pipeline,這些Item Pipeline元件按定義的順序處理Item。

 

  • 爬蟲資料持久化
    • 將資料存入mysql資料庫
    • ITEM_PIPELINES = {
      'douban.pipelines.DoubanPipeline': 300,
      }

      關於資料庫的相關配置
      MYSQL_HOST = '127.0.0.1'
      MYSQL_PORT = 3306
      MYSQL_USER = ''
      MYSQL_PWD = ''
      MYSQL_DB = ''
      pipelines.py管道檔案

    • 往資料庫裡插資料
      class ChinazspiderPipeline(object):
          def __init__(self):
              '''
              初始化方法
              '''
              # self.file = open('chinaz.json','a')
              # 建立資料庫連結
              self.client = pymysql.Connect(
                  '127.0.0.1', 'root', 'czj1234',
                  'chinaz', 3306, charset='utf8'
              )
              # 建立遊標
              self.cursor = self.client.cursor()
      
          def open_spider(self, spider):
              '''
              爬蟲啟動的時候回撥用一次
              :param spider:
              :return:
              '''
              print('爬蟲開啟')
              pass
      
          def process_item(self, item, spider):
              '''
              這個方法必須實現,爬蟲檔案中所有的item 都會經過這個方法
              :param item: 爬蟲檔案傳遞過來的item物件
              :param spider: 爬蟲檔案例項化的物件
              :return:
              '''
              # 儲存到本地json檔案
              data_dict = dict(item)
              # import json
              # json_data = json.dumps(data_dict,ensure_ascii=False)
              # self.file.write(json_data+'\n')
              # 使用isisinstance判斷item要儲存的表
              # if isinstance(item,ChinazprojectWebInfoItem):
              #     print('網站資訊')
              #     tablename = 'webinfo'
              # elif isinstance(item,ChinazspidertagItem):
              #     print('網站分類資訊')
              #     tablename = 'tags'
              #     #
              # # 往資料庫裡寫
              # sql = """
              #     insert into %s(%s)
              #     values (%s)
              # """ % (tablename,','.join(data_dict.keys()), ','.join(['%s'] * len(data_dict)))
              sql,data = item.get_insert_sql_data(data_dict)
      
              try:
                  self.cursor.execute(sql, list(data_dict.values()))
                  self.client.commit()
              except Exception as err:
                  self.client.rollback()
                  print(err)
              # 如果有多個管道檔案,一定要return item , 否則下一管道無法接收到item
              print('經過了管道')
              return item
      
          def close_spider(self, spider):
              '''
              爬蟲結束的時候呼叫一次
              :param spider:
              :return:
              '''
              # self.file.close()
              self.client.close()
              self.cursor.close()
              print('爬蟲結束')