Scrapy基礎

Scrapy框架架構

什麼是Scrapy框架

scrapy 是一個爲了爬取網站數據,提取結構性數據而編寫的應用框架,我們只需要實現少量代碼,就能夠快速的抓取到數據內容。Scrapy 使用了 Twisted(其主要對手是Tornado)異步網絡框架來處理網絡通訊,可以加快我們的下載速度,不用自己去實現異步框架,並且包含了各種中間件接口,可以靈活的完成各種需求。

Scrapy架構圖

在這裏插入圖片描述各模塊的功能:

  1. Scrapy Engine(引擎):Scrapy框架的核心部分。負責在Spider和ItemPipeline、Downloader、Scheduler中間通信、傳遞數據等。
  2. Spider(爬蟲):發送需要爬取的鏈接給引擎,最後引擎把其他模塊請求回來的數據再發送給爬蟲,爬蟲就去解析想要的數據。這個部分是我們開發者自己寫的,因爲要爬取哪些鏈接,頁面中的哪些數據是我們需要的,都是由程序員自己決定。
  3. Scheduler(調度器):負責接收引擎發送過來的請求,並按照一定的方式進行排列和整理,負責調度請求的順序等。
  4. Downloader(下載器):負責接收引擎傳過來的下載請求,然後去網絡上下載對應的數據再交還給引擎。
  5. Item Pipeline(管道):負責將Spider(爬蟲)傳遞過來的數據進行保存。具體保存在哪裏,應該看開發者自己的需求。
  6. Downloader Middlewares(下載中間件):可以擴展下載器和引擎之間通信功能的中間件。
  7. Spider Middlewares(Spider中間件):可以擴展引擎和爬蟲之間通信功能的中間件。

在這裏插入圖片描述scrapy框架的工作流程:

1.首先Spiders(爬蟲)將需要發送請求的url(requests)經ScrapyEngine(引擎)交給Scheduler(調度器)。

2.Scheduler(排序,入隊)處理後,經ScrapyEngine,DownloaderMiddlewares(可選,主要有User_Agent, Proxy代理)交給Downloader。

3.Downloader向互聯網發送請求,並接收下載響應(response)。將響應(response)經ScrapyEngine,SpiderMiddlewares(可選)交給Spiders。

4.Spiders處理response,提取數據並將數據經ScrapyEngine交給ItemPipeline保存(可以是本地,可以是數據庫)。
提取url重新經ScrapyEngine交給Scheduler進行下一個循環。直到無Url請求程序停止結束。

Scrapy的安裝

1.安裝:通過pip install scrapy即可安裝。
2. Scrapy官方文檔:http://doc.scrapy.org/en/latest
3.Scrapy中文文檔:http://scrapy-chs.readthedocs.io/zh_CN/latest/index.html

注意:
    在ubuntu上安裝scrapy之前,需要先安裝以下依賴:
    sudo apt-get install python3-dev build-essential python3-pip libxml2-dev libxslt1-dev zlib1g-dev libffi-dev libssl-dev,然後再通過pip install scrapy安裝。
    如果在windows系統下,提示這個錯誤ModuleNotFoundError: No module named 'win32api',那麼使用以下命令可以解決:pip install pypiwin32。

創建項目

要使用Scrapy框架創建項目,需要通過命令來創建。首先進入到你想把這個項目存放的目錄。然後使用以下命令創建:

scrapy startproject [項目名稱]

目錄結構:
在這裏插入圖片描述

  1. items.py:用來存放爬蟲爬取下來數據的模型。
  2. middlewares.py:用來存放各種中間件的文件。
  3. pipelines.py:用來將items的模型存儲到本地磁盤中。
  4. settings.py:本爬蟲的一些配置信息(比如請求頭、多久發送一次請求、ip代理池等)。
  5. scrapy.cfg:項目的配置文件。
  6. spiders包:以後所有的爬蟲,都是存放到這個裏面。

爬取溴事百科

1.使用命令創建一個爬蟲:

scrapy genspider choushibaikespider "qiushibaike.com"

創建了一個名字叫做choushibaikespider的爬蟲,並且能爬取的網頁只會限制在qiushibaike.com這個域名下。

choushibaikespider.py代碼解析:

import scrapy


class ChoushibaikespiderSpider(scrapy.Spider):
    name = 'choushibaikespider'
    allowed_domains = ['qiushibaike.com']
    start_urls = ['http://qiushibaike.com/']

    def parse(self, response):
        pass

其實這些代碼我們完全可以自己手動去寫,而不用命令。只不過是不用命令,自己寫這些代碼比較麻煩。
要創建一個Spider,那麼必須自定義一個類,繼承自scrapy.Spider,然後在這個類中定義三個屬性和一個方法。

(1) name:這個爬蟲的名字,名字必須是唯一的。
(2) allow_domains:允許的域名。爬蟲只會爬取這個域名下的網頁,其他不是這個域名下的網頁會被自動忽略。
(3). start_urls:爬蟲從這個變量中的url開始。
(4). parse:引擎會把下載器下載回來的數據扔給爬蟲解析,爬蟲再把數據傳給這個parse方法。這個是個固定的寫法。這個方法的作用有兩個,第一個是提取想要的數據。第二個是生成下一個請求的url。

2.修改settings.py代碼:
在做一個爬蟲之前,一定要記得修改setttings.py中的設置。兩個地方是強烈建議設置的。

 1. ROBOTSTXT_OBEY設置爲False。默認是True。即遵守機器協議,那麼在爬蟲的時候,scrapy首先去找robots.txt文件,如果沒有找到。則直接停止爬取。
 2.DEFAULT_REQUEST_HEADERS添加User-Agent。這個也是告訴服務器,我這個請求是一個正常的請求,不是一個爬蟲。

3.完成代碼:
choushibaikespider.py
(1).response是一個scrapy.http.response.html.HtmlResponse對象。可以執行xpathcss語法來提取數據。
(2). 提取出來的數據,是一個Selector或者是一個SelectorList對象。如果想要獲取其中的字符串。那麼應該執行getall或者get方法。
(3). getall方法:獲取Selector中的所有文本。返回的是一個列表。
(4). get方法:獲取的是Selector中的第一個文本。返回的是一個str類型。
(5). 如果數據解析回來,要傳給pipline處理。那麼可以使用yield來返回。或者是收集所有的item。最後統一使用return返回。

# -*- coding: utf-8 -*-
import scrapy
from choushibaike.items import ChoushibaikeItem



class ChoushibaikespiderSpider(scrapy.Spider):
    name = 'choushibaikespider'
    allowed_domains = ['qiushibaike.com']
    start_urls = ['https://www.qiushibaike.com/text/page/1/']
    base_domain = 'https://www.qiushibaike.com'

    def parse(self, response): 
        # SelectorList
        duanzidivs=response.xpath("//div[@id='content-left']/div")
        for duanzidiv in duanzidivs:
            # Selector
            author = duanzidiv.xpath(".//h2/text()").get().strip()
            content = duanzidiv.xpath(".//div[@class='content']//text()").getall()
            content = "".join(content).strip()

            item = ChoushibaikeItem(author=author,content=content)
            yield  item
        next_url = response.xpath("//ul[@class='pagination']/li[last()]/a/@href").get()
        if not next_url:
            return
        else:
            yield scrapy.Request(self.base_domain+next_url,callback=self.parse)

items.py
(6).item:建議在items.py中定義好模型。以後就不要使用字典。

import scrapy
class ChoushibaikeItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    author = scrapy.Field()
    content = scrapy.Field()

pipelines.py
(7). pipeline:這個是專門用來保存數據的。其中有三個方法是會經常用的。
* open_spider(self,spider):當爬蟲被打開的時候執行。
* process_item(self,item,spider):當爬蟲有item傳過來的時候會被調用。
* close_spider(self,spider):當爬蟲關閉的時候會被調用。
要激活piplilne,應該在settings.py中,設置ITEM_PIPELINES。示例如下:
ITEM_PIPELINES = { 'choushibaike.pipelines.ChoushibaikePipeline': 300, }

import json


class ChoushibaikePipeline(object):
    def __init__(self):
        self.fp = open("duanzhi.js",'w',encoding="utf-8")

    def open_spider(self,spider):
        print("爬蟲開始...")

    def process_item(self, item, spider):
        item_json = json.dumps(dict(item),ensure_ascii=False)
        self.fp.write(item_json)
        return item

    def close_spider(self,spider):
        self.fp.close()
        print("爬蟲結束了.")

4.運行爬蟲
運行scrapy項目。需要在終端,進入項目所在的路徑,然後scrapy crawl [爬蟲名字]即可運行指定的爬蟲。如果不想每次都在命令行中運行,那麼可以把這個命令寫在一個文件中。以後就在pycharm中執行運行這個文件就可以了。比如現在新創建一個文件叫做start.py,然後在這個文件中填入以下代碼:

from  scrapy import cmdline

cmdline.execute("scrapy crawl choushibaikespider".split())
JsonItemExporter和JsonLinesItemExporter

保存json數據的時候,可以使用這兩個類,讓操作變得得更簡單。

  1. JsonItemExporter:這個是每次把數據添加到內存中。最後統一寫入到磁盤中。好處是,存儲的數據是一個滿足json規則的數據。壞處是如果數據量比較大,那麼比較耗內存。
from scrapy.exporters import JsonItemExporter

 class ChoushibaikePipeline(object):
     def __init__(self):
         self.fp = open("duanzi.json",'wb')
         self.exporter = JsonItemExporter(self.fp,ensure_ascii=False,encoding='utf-8')
         self.exporter.start_exporting()

     def open_spider(self,spider):
         print('爬蟲開始了...')

     def process_item(self, item, spider):
         self.exporter.export_item(item)
         return item

     def close_spider(self,spider):
         self.exporter.finish_exporting()
         self.fp.close()
         print('爬蟲結束了...')
  1. JsonLinesItemExporter:這個是每次調用export_item的時候就把這個item存儲到硬盤中。壞處是每一個字典是一行,整個文件不是一個滿足json格式的文件。好處是每次處理數據的時候就直接存儲到了硬盤中,這樣不會耗內存,數據也比較安全。
from scrapy.exporters import JsonLinesItemExporter
    class ChoushibaikePipeline(object):
        def __init__(self):
            self.fp = open("duanzi.json",'wb')
            self.exporter = JsonLinesItemExporter(self.fp,ensure_ascii=False,encoding='utf-8')

        def open_spider(self,spider):
            print('爬蟲開始了...')

        def process_item(self, item, spider):
            self.exporter.export_item(item)
            return item

        def close_spider(self,spider):
            self.fp.close()
            print('爬蟲結束了...')

注:參考網易課堂知了課程。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章