Python爬蟲—Scrapy框架

初學愛好者發表於2020-10-04

一、為什麼要使用Scrapy?

  • 它更容易構建和大規模的抓取專案
  • 它內建的機制被稱為選擇器,用於從網站(網頁)上提取資料
  • 它非同步處理請求,速度十分快
  • 它可以使用自動調節機制自動調整爬行速度
  • 確保開發人員可訪問性

二、Scrapy的特點

  • Scrapy是一個開源和免費使用的網路爬蟲框架
  • Scrapy生成格式匯出如:JSON,CSV和XML
  • Scrapy內建支援從原始碼,使用XPath或CSS表示式的選擇器來提取資料
  • Scrapy基於爬蟲,允許以自動方式從網頁中提取資料

三、Scrapy的優點

  • Scrapy很容易擴充套件,快速和功能強大;
  • 這是一個跨平臺應用程式框架(在Windows,Linux,Mac OS和BSD)。
  • Scrapy請求排程和非同步處理;
  • Scrapy附帶了一個名為Scrapyd的內建服務,它允許使用JSON Web服務上傳專案和控制蜘蛛。
  • 也能夠刮削任何網站,即使該網站不具有原始資料訪問API;

四、Scrapy整體架構是什麼樣?

image.png

最簡單的單個網頁爬取流程是spiders > scheduler > downloader > spiders > item pipeline

五、元件介紹

  • **ScrapyEngine (引擎)**負責 Scheduler、Downloader、Spiders、Item Pipeline中間的通訊訊號和資料的傳遞,相當於一個交通站。
  • **Scheduler(排程器)**簡單地說就是一個佇列,負責接收引擎傳送過來的 request請求,然後將請求排隊,當引擎需要請求資料的時候,就將請求佇列中的資料交給引擎。
  • **Downloader(下載器)**負責傳送請求並下載資料,負責下載引擎傳送過來的所有 request請求,並將獲得的 response交還給引擎,再由引擎將 response交管給 Spiders來進行解析。
  • **Spiders(爬蟲)**就是我們平時寫 xpath、正規表示式的元件,我們會在Spider中寫很多的解析策略,用於分析和提取資料。Spiders負責處理所有的 response,當然,如果 response中包含有其它的請求,比如說下一頁等等,那麼這個時候 Spiders會讓 url提交給引擎,再由引擎再次扔到 Scheduler排程器裡面。
  • **Item Pipeline(專案管道)**就是我們封裝去重類、儲存類的地方,負責處理 Spiders中獲取到的資料並且進行後期的處理,過濾或者儲存等等。
  • **Downloader Middlewares(下載中介軟體)**是一個自定義擴充套件元件,就是我們封裝代理或者Http頭用於隱藏我們的地方。
  • **Spider Middlewares(爬蟲中介軟體)**也就是自定義擴充套件、引擎和Spider之間通訊功能的元件,比如說進入Spider的 response和從 Spider出去的 request,它可以在中間做一些修改。

六、整個 Scrapy元件裡面是如何進行流動的呢?

首先我們會在Spider裡面寫一個入口url,然後引擎會根據我們需要處理網站的url。

引擎會向排程器打招呼,

​ ScrapyEngine[引擎] 說:我這有個 request請求,你幫我 排序入隊一下。

​ Scheduler[排程器] 說:好,我現在就給你排隊。

​ ScrapyEngine 問 Scheduler :你排好了沒有,你排好呢就把 request請求給我。

​ Scheduler[排程器] 說:好,給你,拿去下載吧,我已經排好隊了。

排程器把佇列裡面的請求給引擎 [引擎這麼高大上的元件能幹這種活嗎],然後引擎會把下載的活扔給下載器,不一會呢,下載器就下載好了。當然了,下載器也不是說總能把事辦好,然後會把反饋交還給引擎,接著引擎會將沒下載好的請求再扔給排程器,再次進行排隊排程。

如果說下載好了,這時會將 response交給 Spider元件,Spider會進行資料的解剖,看看裡面都有什麼資料,有沒有什麼新的請求連結,然後Spider一頓操作猛如虎,拿出兩部分資料,一部分資料就是我們要的資料,它呢會扔給管道進行資料儲存或者清洗,另一部分是一些新的請求,將新的請求扔給引擎,然後再到排程器進行排隊,再從排隊排程到Spider解析進行迴圈,直到獲取到全部的資訊。

那麼Scrapy各個元件之間相互協作,不同的元件完成不同的工作。由於 Scrapy是基於非同步進行開發的,因此會很大限度的使用網路頻寬,大大提高了抓取的效率。

七、Scrapy專案實戰

抓取豆瓣電影top250資料,並將資料儲存為 csv 和 json 儲存到 mongo資料庫中

目標站點:https://movie.douban.com/top250

1、建立專案

  1. 1 在我們當前專案下Terminal控制檯中,輸入 scrapy startproject douban 即可建立 scrapy專案

    M_Z_ZO8T2WEJ_8XYPT3P`2I.png

  2. 2 然後open開啟剛剛建立的 scrapy專案

    W_T@G_@_Q_6_`OH_QER5LU9.png

2、檔案介紹

  • scrapy.cfg 是專案的配置檔案,定義了專案配置檔案路徑、部署資訊等內容。

  • items.py 是定義item資料結構的地方,所有的item資料定義都可以在這裡面進行編寫。

  • settings.py 是專案的設定檔案,可以定義專案的全域性設定

    • 比如說http的user-agent:在17行進行設定,例如谷歌瀏覽器的 (Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4238.2 Safari/537.36);

    • 還有ROBOTSTXT_OBEY協議:在20行,也可以進行更改,一般為False;

    • 下載延遲:下載延遲,改為0.5秒等等。

還有一個更重要的檔案,spiders檔案,這是我們編寫xpath和正規表示式的地方,但是這個檔案需要我們自己生成。

進入到douban專案裡的spiders檔案目錄下,輸入scrapy genspider douban_spider movie.douban.com在輸入建立spider檔案命令之前,我們還需要安裝 Scrapy,直接命令 pip install Scrapy進行安裝

4__L6LO94DX_M_9_DE_3PWF.png

image.png

3、明確我們需要抓取的目標

開啟目標地址 https://movie.douban.com/top250

image.png

  • 3.1 在items.py中定義我們的資料結構

    # Define here the models for your scraped items
    #
    # See documentation in:
    # https://docs.scrapy.org/en/latest/topics/items.html
    
    import scrapy
    
    
    class DoubanItem(scrapy.Item):
        # define the fields for your item here like:
        # name = scrapy.Field()
        # 序號
        serial_number = scrapy.Field()
        # 電影名稱
        movie_name = scrapy.Field()
        # 電影介紹
        introduce = scrapy.Field()
        # 電影星級
        star = scrapy.Field()
        # 電影評論數
        evaluate = scrapy.Field()
        # 電影描述
        describe = scrapy.Field()
    
  • 3.2 spider檔案的編寫

    import scrapy
    
    
    class DoubanSpiderSpider(scrapy.Spider):
        # 爬蟲名
        name = 'douban_spider'
        # 允許域名,如果不在這個域名裡邊的 url不會進行抓取
        allowed_domains = ['movie.douban.com']
        # 入口 url,引擎會將入口 url扔到排程器裡面
        start_urls = ['https://movie.douban.com/top250']
    
        def parse(self, response):
            """ 在這裡進行資料的解析 """
            print(response.text)
    
  • 3.3 如何執行我們的 scrapy專案?

    • 1、在終端控制檯中以命令方式執行:scrapy crawl douban_spider

    • 2、在douban模組下建立一個 main.py檔案,並編寫程式碼,然後右鍵Run ‘main’

      image.png

4、解析我們所需要爬取的資料

  • 4.1 使用xpath工具定位到我們所需爬取內容的節點

    image.png

  • 4.2 在程式碼中進行資料解析

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-UHloOE5r-1601819571950)(F:\Android\android案例開發筆記\直播案例開發圖片\image-20201004133914018.png)]

    這裡可以看到,我們獲取出來的item對應的就是頁面中每一個li標籤元素,通過遍歷轉成 Selector物件,

    然後再從每個Selector物件中解析出我們所要獲取的資料。

  • 4.3 匯入我們之前定義好的 items模組,在 spider中解析出我們所要獲取的資料

    這裡以 “serial_number” 為例,其它的寫法也一樣,注意xpath中的規則就行了:

    from douban.items import DoubanItem
    

    image.png

    extract_first():https://blog.csdn.net/ebzxw/article/details/102163887

import scrapy
from douban.items import DoubanItem


class DoubanSpiderSpider(scrapy.Spider):
    # 爬蟲名
    name = 'douban_spider'
    # 允許域名,如果不在這個域名裡邊的 url不會進行抓取
    allowed_domains = ['movie.douban.com']
    # 入口 url,引擎會將入口 url扔到排程器裡面
    start_urls = ['https://movie.douban.com/top250']

    def parse(self, response):
        """ 在這裡進行資料的解析 """
        # print(response.text)
        movie_list = response.xpath('//div[@class="article"]/ol[@class="grid_view"]/li')
        for item in movie_list:
            # print(item)
            douban_item = DoubanItem()
            # 寫詳細的 xpath,進行資料的解析
            douban_item['serial_number'] = item.xpath('.//div[@class="item"]/div[@class="pic"]/em/text()').extract_first()
            douban_item['movie_name'] = item.xpath('.//div[@class="info"]/div[@class="hd"]/a/span[1]/text()').extract_first()
            content = item.xpath('.//div[@class="info"]//div[@class="bd"]/p[1]/text()').extract()
            for con in content:
                # 空格字元處理
                content_str = "".join(con.split())
                douban_item['introduce'] = content_str
            douban_item['star'] = item.xpath('.//div[@class="star"]/span[2]/text()').extract_first()
            douban_item['evaluate'] = item.xpath('.//div[@class="star"]/span[4]/text()').extract_first()
            douban_item['describe'] = item.xpath('.//p[@class="quote"]/span/text()').extract_first()

            # 將資料 yield到 pipelines裡面
            yield douban_item

        # 獲取下一頁[解析下一頁],取後頁的 xpath
        next_link = response.xpath('//div[@class="paginator"]/span[@class="next"]/link/@href').extract()
        # 如果有下一頁就進行提取
        if next_link:
            next_link = next_link[0]
            # 將新的 url提交到排程器,通過 callback回撥函式再進行資料的解析
            yield scrapy.Request('https://movie.douban.com/top250?' + next_link, callback=self.parse)

5、儲存資料

1)儲存在檔案中

在終端控制檯中輸入:scrapy crawl douban_spider -o douban.json

image.png

如果要儲存為 csv檔案:scrapy crawl douban_spider -o douban.csv

image.png

關係 csv檔案開啟亂碼問題 :

原因:CSV是用UTF-8編碼的,而EXCEL是ANSI編碼,由於編碼方式不一致導致出現亂碼。

解決,用記事本開啟,另存為為ANSI編碼即可。

2)儲存到MongoDB資料庫裡面
  • 1、在 settings.py檔案中填寫主機地址、埠、資料庫名、資料庫表並開啟ITEM_PIPELINES

    image.png

    image.png

  • 2、在 pipelines.py檔案中進行編寫

    在編寫之前需要下載 pymongo模組pip install pymongo

    # useful for handling different item types with a single interface
    from itemadapter import ItemAdapter
    import pymongo
    from douban.settings import mongo_host, mongo_port, mongo_db_name, mongo_db_collection
    
    
    class DoubanPipeline:
        def __init__(self):
            host = mongo_host
            port = mongo_port
            dbname = mongo_db_name
            sheetname = mongo_db_collection
            # 獲取 MongoDB的連線
            client = pymongo.MongoClient(host=host, port=port)
            # 指定資料庫
            mydb = client[dbname]
            # 指定資料庫表
            self.post = mydb[sheetname]
    
        def process_item(self, item, spider):
            """ 進行資料的插入 """
            data = dict(item)
            self.post.insert(data)
    
            return item
    

    然後在 main.py中右鍵執行即可。

  • 3、在MongoDB中檢視我們儲存的資料

    MongoDB視覺化工具下載地址:https://robomongo.org/

    image.png

八、IP代理中介軟體的編寫

1、在middlewares.py檔案中編寫

class MyProxy(object):
    def process_request(self, request, spider):
        request.meta['proxy'] = '代理伺服器地址:埠號'
        proxy_name_pass = b'使用者名稱:密碼'
        # 對使用者名稱和密碼進行加密
        encode_pass_name = base64.b64decode(proxy_name_pass)
        # 設定 http頭
        request.headers['Proxy-Authorization'] = 'Basic ' + proxy_name_pass.decode()

2、在settings.py檔案中開啟DOWNLOADER_MIDDLEWARES

DOWNLOADER_MIDDLEWARES = {
   #'douban.middlewares.DoubanDownloaderMiddleware': 543,
   'douban.middlewares.MyProxy': 300,
   # 300為設定的優先順序,數字越小,優先順序越高
}

image.png

九、User-Agent中介軟體的編寫

1、在middlewares.py檔案中進行編寫

class MyUserAgent(object):
    def process_request(self, request, spider):
        USER_AGENT_LIST = [
            "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1",
            "Mozilla/5.0 (X11; CrOS i686 2268.111.0) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11",
            "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1092.0 Safari/536.6",
            "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1090.0 Safari/536.6",
            "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/19.77.34.5 Safari/537.1",
            "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.9 Safari/536.5",
            "Mozilla/5.0 (Windows NT 6.0) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.36 Safari/536.5",
            "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",
            "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",
            "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; SE 2.X MetaSr 1.0; SE 2.X MetaSr 1.0; .NET CLR 2.0.50727; SE 2.X MetaSr 1.0)",
            "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3",
            "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3",
            "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; 360SE)",
            "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
            "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
            "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.0 Safari/536.3",
            "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.24 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24",
            "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/535.24 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24"
        ]
        agent = random.choice(USER_AGENT_LIST)
        request.headers['User-Agent'] = agent

2、在settings.py檔案中引入

DOWNLOADER_MIDDLEWARES = {
   # 'douban.middlewares.DoubanDownloaderMiddleware': 543,
   'douban.middlewares.MyProxy': 543,
   'douban.middlewares.MyUserAgent': 544
}

十、注意事項

  • 中介軟體定義完要在settings檔案內啟用
  • 爬蟲檔名和爬蟲名稱不能相同,spiders目錄內不能存在相同爬蟲名稱的專案檔案
  • 做一個文明守法的好網民,不要爬取公民的隱私資料,不要給對方的系統帶來不必要的麻煩

補充、解決content切割只有最後一組(年份/地區/型別)字串的問題

  • 解決前

image.png

  • 改寫程式碼

image.png

  • 解決後

image.png

相關文章