Scrapy實戰之豆瓣top250電影資訊的爬取

語言: CN / TW / HK

持續創作,加速成長!這是我參與「掘金日新計劃 · 6 月更文挑戰」的第25天,點選檢視活動詳情

簡單使用

1.基操(簡單的專案命令)!

(1)建立專案:

(小知識點:<>為必填項;[]為選填項!小技巧1:pycharm終端輸入scrapy可以檢視一些幫助,有助於我們寫那些難記的命令!小技巧2:scrapy+命令關鍵字,可以檢視有關於此命令的詳細用法!)

1.首先: cd+要放scrapy專案的資料夾路徑

2.第二步: 通過scrapy命令可以很方便的新建scrapy專案。

語法格式:scrapy startproject [project_dir]

該命令會在project_dir檔案加下建立一個名為project_name的Scrapy新專案。如果project_dir沒有指定,project_dir與project_name相同。執行命令:scrapy startproject baidu之後會在指定資料夾建立如下檔案:

(2)建立爬蟲檔案

{建立一個bdSpider的類,它必須繼承scrapy.Spider類,需要定義以下三個屬性:name: spider的名字,必須且唯一start_urls: 初始的url列表parse(self, response) 方法:每個初始url完成之後被呼叫。這個函式要完成一下兩個功能:解析響應,封裝成item物件並返回這個物件提取新的需要下載的url,建立新的request,並返回它

我們也可以通過命令建立爬蟲

語法格式:scrapy genspider [-t template] 執行命令:scrapy genspider bd www.baidu.com會在spiders檔案下生成bd.py檔案}1.首先: cd 到專案下2.第二步: scrapy genspider [options] scrapy genspider bd www.baidu.com會建立在專案/spider下 ;其中bd 是爬蟲檔名, www.baidu.com 是 url(域名)執行命令:scrapy genspider bd www.baidu.com之後再專案/spider下建立的檔案為:

```

-- coding: utf-8 --

import scrapy

class BdSpider(scrapy.Spider): #繼承了scrapy.Spider類 name = 'bd' #名字是唯一的(不重複) 因為我們在啟動專案的時候,是根據這個名字來找爬蟲檔案的 allowed_domains = ['www.baidu.com'] #允許的域名 (限制) 可以沒有這個限制! start_urls = ['http://www.baidu.com/'] #首個請求(必須要有) 不然開始都開始不了,怎麼讓整個框架執行下去呢!

def parse(self, response):           #必須是parse函式  不可以亂改名  接收下載器下載的資料
    print("*******")    #用於更直觀的觀察框架能否正常執行!
    print("*******")
    print("*******")
    print("*******")
    print("*******")
    print("*******")
    print(response)         #response物件
    #獲取資料   兩種方法:
    print(response.body.decode())   #獲取到的是位元組碼形式
    # print(response.text)

```

注意:最後引擎給spider模組的資料就給到了函式parse裡的形參response:

(3)執行爬蟲檔案

一步即可: scrapy crawl [options] 其中spider是爬蟲檔名

執行命令:scrapy crawl bd

但是!我們執行爬蟲檔案之後,發現用於測試的print函式沒有顯示,經過檢查終端輸出的資料可知Scrapy框架是預設遵循robots協議的,所以咱們肯定獲取不到資料了!!!

如何解決這個問題呢?

開啟設定檔案settings.py,將其中的以下程式碼更改為False即可!

```

Obey robots.txt rules

ROBOTSTXT_OBEY = True ```


拓展:第二種執行scrapy的方法!

cd 到爬蟲模組spiders資料夾下,執行命令: scrapy runspider 爬蟲py檔名 注意:爬蟲py檔名要帶.py字尾!

高階拓展:(注意:以上兩種執行scrapy框架的方法都無法進行debug,非常不方便!萬一出問題了,豈不是很難找!!!所以:推出第三種啟動scrapy框架的方法-----django在建立專案的時候自動生成一個啟動專案的py檔案【manage.py或者main.py】,而scrapy框架沒有,但是我們可以自己定義呀!!!!!)

1.在專案資料夾下建立名為main.py或者manage.py的py檔案:

``` 2.在此py檔案下編寫程式碼如下:

from scrapy.cmdline import execute import sys import os

保證終端執行 "scrapy", "crawl", "bd" 這個命令執行不出現路徑問題!(可以不寫!)

sys.path.append(os.path.dirname(os.path.abspath(file))) execute(["scrapy", "crawl", "bd"]) ```

3.現在,我們可以直接執行這個py檔案,會發現會和前兩種方法一樣執行scrapy框架;而且,強大的是:我們還可以通過debug此py檔案達到除錯此scrapy框架的作用!!!


(2)實操(豆瓣電影top250首頁電影資訊的獲取!)

1.建立專案:

scrapy startproject douban

2.建立爬蟲檔案:

scrapy genspider db www.summer.com (注意:這個域名是可以隨便寫的【但是必須要寫哦!】,等爬蟲檔案生成之後再進相應的爬蟲檔案改為我們所需的即可!)

```

-- coding: utf-8 --

import scrapy

class DbSpider(scrapy.Spider): name = 'db' allowed_domains = ['movie.douban.com'] start_urls = ['https://movie.douban.com/top250']

def parse(self, response):
    print("*********")
    print("*********")
    print("*********")
    print("*********")
    print("*********")
    print(response.text)

```

3.執行爬蟲檔案:

scrapy crawl db但是,我們執行之後發現又沒有獲取到資料哎!

造成這樣的原因是:回想爬蟲的基礎,我們如果直接這樣向網頁傳送請求進行爬取,那服務端一眼就看到咱是scrapy了,它還會理咱嘛?所以我們要設定請求頭!

4.設定請求頭:

在配置檔案settings.py中找到如下程式碼取消註釋並加入爬取網頁請求頭的User-Agent即可!

5.獲取到電影名字:

{到現在,我們執行爬蟲檔案,Scrapy框架已經可以獲取到網頁的首頁資料。那麼,我們如何篩選出我們想要的電影的名字呢?考慮到我們如果利用xpath匹配,可能要多次嘗試才能正確匹配到,那就需要我們一次又一次的執行咱的專案,多麻煩啊!咱都這樣想了,人家大牛也這樣想啊,所以,在這裡有個賊帥賊帥的牛皮的方法:使用shell互動式平臺:(注意1:它是遵循settings設定的;注意2:一定要到咱的專案資料夾下執行;) 首先:cd到我們專案的檔案路徑下。然後:輸入命令scrapy shell url (start_url) 即可!這樣:它其實就請求到了此url的資料(跟上面執行爬蟲檔案得到的資料一模一樣)!!!}

首先:開啟我們的shell互動式平臺。 再此專案中:輸入命令scrapy shell https://movie.douban.com/top250

第二步:在shell互動式平臺中匹配我們所需的電影資料。 輸入:response.xpath('//div[@class="info"]/div/a/span[1]/text()')

(會發現:這得到的是一個selector物件!而我們得到的資料就是用的response物件自帶的xpath匹配到的(生成了response之後就會自動生成selector物件)!與我們正常用的xpath不同,它獲取到的資料在selector物件裡,如上圖:)

第三步:從selector物件中提取電影名字使用selector物件的方法.extract()。這個方法可以提取到selector物件中data對應的資料。response.xpath('//div[@class="info"]/div/a/span[1]/text()').extract()

6.將獲取到的電影的資訊儲存到text文字中

{注意:如果想要儲存資料,就要用到管道。這就涉及到了items.py檔案(定義結構化資料欄位)和pipelines.py檔案(管道檔案)。}

首先:操作items.py檔案因為我們只需要儲存一個資訊,所以定義一個欄位名即可!{定義公共輸出資料格式,Scrapy提供了Item類。Item物件是用於收集剪貼資料的簡單容器。它們提供了一個類似詞典的API,提供了一種方便的語法來宣告它們的可用欄位。 scray.Item物件是用於收集抓取資料的簡單容器,使用方法和python的字典類似。編輯專案目錄下items.py檔案。

然後我們只需要在爬蟲中匯入我們定義的Item類,例項化後用它進行資料結構化。}

```

-- coding: utf-8 --

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() #需要定義欄位名 就像資料庫那樣,有欄位名,才能插入資料(即儲存資料) # Field代表的是字串型別!!! films_name=scrapy.Field() #定義欄位名 ```

第二步:在爬蟲檔案中操作資料,使其與管道建立橋樑{到目前為止,我們通過scrapy寫出的爬蟲還看不出優越性在哪裡,並且上面的爬蟲還有個很嚴重的問題,就是對檔案的操作。每次呼叫parse方法會開啟檔案關閉檔案,這極大的浪費了資源。parse函式在解析出我們需要的資訊之後,可以將這些資訊打包成一個字典物件或scray.Item物件(一般都是item物件),然後返回。這個物件會被髮送到item管道,該管道會通過順序執行幾個元件處理它。每個item管道元件是一個實現簡單方法的Python類。他們收到一個item並對其執行操作,同時決定該item是否應該繼續通過管道或者被丟棄並且不再處理。item管道的典型用途是:

清理HTML資料驗證已刪除的資料(檢查專案是否包含某些欄位)檢查重複項(並刪除它們)將已爬取的item進行資料持久化}

```

-- coding: utf-8 --

import scrapy

from ..items import DoubanItem #因為我們要使用包含定義欄位名的類,所以需要匯入

class DbSpider(scrapy.Spider): name = 'db' allowed_domains = ['movie.douban.com'] start_urls = ['https://movie.douban.com/top250']

def parse(self, response):
    # 獲取電影資訊資料
    films1_name=response.xpath('//div[@class="info"]/div/a/span[1]/text()').extract()
    # 交給管道儲存
    # 使用DoubanItem
    item=DoubanItem()  #建立物件
    item["films_name"]=films1_name      #值是個列表,因為xpath匹配到的資料都扔到列表裡了!
    # item可以理解為一個安全的字典  用法與字典相同
    print("item裡面是:",dict(item))  #可以轉換為字典
    return item     #交給引擎  引擎要交給管道,需要開啟管道

```

第三步:我們要將資料提交給管道,所以需要開啟管道要啟用這個管道元件,必須將其新增到ITEM_PIPELINES設定中,在settings.py檔案中:

(在此設定中為類分配的整數值決定了它們執行的順序:按照從較低值到較高值的順序進行。注意:這個管道的目的只是介紹如何編寫專案管道,如果要將所有爬取的item儲存到json檔案中,則應使用Feed匯出,在執行爬蟲是加上如下引數:scrapy crawl bd -o films.json)

第四步:現在資料已經可以交給管道,那麼管道就要對資料進行處理就是操作pipelines.py檔案

```

-- coding: utf-8 --

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

import json class DoubanPipeline(object): def process_item(self, item, spider): #為了能寫進text json.dumps將dic資料轉換為str json_str=json.dumps(dict(item),ensure_ascii=False) with open("films.text","w",encoding="utf-8") as f: f.write(json_str) return item ```

實現效果:

🔆In The End!

👑有關於Me

個人簡介:我是一個硬體出身的計算機愛好者,喜歡program,源於熱愛,樂於分享技術與所見所聞所感所得。文章涉及Python,C,微控制器,HTML/CSS/JavaScript及演算法,資料結構等。

| 從現在做起,堅持下去,一天進步一小點,不久的將來,你會感謝曾經努力的你! | | ------------------------------------ |

認真仔細看完本文的小夥伴們,可以點贊收藏並評論出你們的讀後感。並可關注本博主,在今後的日子裡閱讀更多技術文哦~

如有錯誤或者言語不恰當的地方可在評論區指出,謝謝!\ 如轉載此文請聯絡我徵得本人同意,並標註出處及本博主名,謝謝 !