Python爬蟲框架Scrapy的入門和實踐

Github項目地址:https://github.com/xylon666/Scrapy

Scrapy框架,簡單來說就是把爬蟲各功能模塊分割開來,分別負責相應的功能,讓我們通過簡單的學習和實踐來使用他

框架示意圖:

                   Scrapy架構圖.png

架構分析

  • Scrapy Engine:Scrapy引擎。負責控制數據流在系統中所有組件中流動,並在相應動作發生時觸發事件。
  • Scheduler:調度器。從Scrapy Engine接受請求(requests)並排序列入隊列,並在引擎再次請求時返回。用它來決定下一個抓取的網址是什麼,同時去除重複的網址。
  • Downloader:下載器。抓取網頁並將網頁內容返還給Spiders。建立在twisted異步模型。
  • Spiders:爬蟲。用戶自定義的類,主要用來解析網頁,提取Items,發送url跟進等新請求等。
  • Item Pipelines:管道。主要用來處理Spider解析出來的Items,進行按規則過濾,驗證,持久化存儲(如數據庫存儲)等
  • Downloader Middlewares:下載中間件。位於Scrapy Engine和Downloader之間,主要是處理Scrapy引擎與下載器之間的請求及響應。
  • Spider Middlewares:爬蟲中間件。位於Scrapy Engine和Spiders之間,主要工作是處理Spiders的響應輸入和請求輸出。
  • Scheduler Middlewares:調度中間件。位於Scrapy Engine和Scheduler之間。主要工作是處理從Scrapy Engine發送到Scheduler的請求和響應。

所需環境:

編譯器:Pycharm

第三方庫:scrapy

Scrapy相關依賴庫:

lxml
parsel
w3lib
twisted
cryptography
pyOpenSSL

均可通過pip install 安裝

 

實踐目標:

使用Scrapy框架爬取豆瓣電影排行版Top250

 

創建項目:

選擇創建項目的文件路徑,如在D盤創建一個文件夾"Douban_Scrapy"

然後運行cmd,cd到該目錄

d:
cd D:\Douban_Scrapy

創建項目:

scrpay startproject douban

運行後我們會發現在該目錄下多了幾個文件,在Pycharm中打開:

對比文章開頭的框架示意圖,簡單介紹下他們的功能

spiders目錄:編寫爬蟲代碼的主體

items:存放獲取數據的相關元素

middlewares:定義爬蟲過程中的操作

pipelines:定義存儲信息時的操作,例如將數據傳入ManggoDB或MySQL

setting:顧名思義,用來定義我們的各種配置,比如請求頭信息等


初始化爬蟲:

運行cmd,cd到爬蟲project的spiders目錄,執行:

scrapy genspider douban_spider movie.douban.com

這樣一個爬蟲模板就自動建好了

由於需要多次運行cmd來執行scrapy命令,我們可以通過Pycharm直接在編譯器內來實現這一過程

在spiders目錄新建main.py:

from scrapy import cmdline
cmdline.execute('scrapy genspider douban_spider movie.douban.com'.split())

運行後無需通過cmd就能執行命令了 

再修改一下setting配置:

USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36'
#僞裝頭
ROBOTSTXT_OBEY = False
#忽略網頁的爬蟲規則
DOWNLOAD_DELAY = 0.5
#下載延時

再來看一下要爬的內容:

我們通過該頁面可以獲取到的信息有:排名,電影名,星級,評價人數,描述

 根據爬取對象編輯items.py文件

# -*- 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()
    # 排名
    movie_num = scrapy.Field()
    # 電影名稱
    movie_name = scrapy.Field()
    # 星級
    star = scrapy.Field()
    # 評價人數
    value = scrapy.Field()
    # 描述
    describle = scrapy.Field()

 編輯爬蟲代碼douban_spider.py:

# -*- coding: utf-8 -*-
import scrapy


class DoubanSpiderSpider(scrapy.Spider):
    #爬蟲名稱
    name = 'douban_spider'
    #爬蟲允許抓取的域名
    allowed_domains = ['movie.douban.com']
    #獲取數據傳給調度器的地址
    start_urls = ['http://movie.douban.com/top250']

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

執行命令:

在cmd中對應目錄下

scrapy crawl douban_spider

 或在Pycharm中spiders目錄下新建main.py

from scrapy import cmdline
cmdline.execute('scrapy crawl douban_spider'.split())

 執行結果,可以發現成功獲取到了豆瓣網頁源代碼

 

分析頁面:

網頁源代碼已獲取,再來看要爬取的內容:

電影信息都在div class='"article"//ol class="grid_view"下的<li>標籤內,通過xpath對其解析獲取:

# -*- coding: utf-8 -*-
import scrapy


class DoubanSpiderSpider(scrapy.Spider):
    name = 'douban_spider'
    allowed_domains = ['movie.douban.com']
    start_urls = ['http://movie.douban.com/top250']

    def parse(self, response):
        movie_list = response.xpath("//div[@class='article']//ol[@class='grid_view']/li")
        for item in movie_list:
            print(item)

如果你不知道xpath,推薦閱讀:xpath語法

獲取該頁面所有電影信息後,從中提取出我們需要的部分

導入模型文件:

from ..items import DoubanItem

 從我們剛剛獲得的電影信息中,根據節點信息獲取電影排名:

        for item in movie_list:
            douban_item = DoubanItem()    
            #模型初始化
            douban_item['movie_num'] = item.xpath(".//div[@class='item']//em/text()").get()
            #從當前標籤起始,訪問目標標籤獲取文本信息,將其寫入movie_num

以此類推,獲取後面的內容

        for item in movie_list:
            douban_item = DoubanItem()
            douban_item['movie_num'] = item.xpath(".//div[@class='item']//em/text()").get()
            douban_item['movie_name'] = item.xpath(".//div[@class='info']/div[@class='hd']/a/span[1]/text()").get()
            douban_item['star'] = item.xpath(".//div[@class='bd']/div[@class='star']/span[2]/text()").get()
            douban_item['value'] = item.xpath(".//div[@class='bd']/div[@class='star']/span[4]/text()").get()
            douban_item['describle'] = item.xpath(".//div[@class='bd']/p[@class='quote']/span/text()").get()
            print(douban_item)
            yield douban_item
            #將返回結果壓入item Pipline進行處理

運行結果(紅色信息是正常情況):

循環獲取當前頁面所有電影信息後,我們需要訪問下一頁繼續獲取數據,右鍵檢查“後頁”

根據標籤信息,拼接前綴獲取完整鏈接並訪問下一頁

next_link = response.xpath("//span[@class='next']/link/@href").get()
if next_link:
    yield scrapy.Request('http://movie.douban.com/top250' + next_link, callback=self.parse)

通過輸出結果可以看到成功訪問到了最後一頁

完整代碼:

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

class DoubanSpiderSpider(scrapy.Spider):
    #爬蟲名稱
    name = 'douban_spider'
    #爬蟲允許抓取的域名
    allowed_domains = ['movie.douban.com']
    #獲取數據傳給調度器的地址
    start_urls = ['http://movie.douban.com/top250']

    def parse(self, response):
        movie_list = response.xpath("//div[@class='article']//ol[@class='grid_view']/li")
        for item in movie_list:
            douban_item = DoubanItem()
            douban_item['movie_num'] = item.xpath(".//div[@class='item']//em/text()").get()
            douban_item['movie_name'] = item.xpath(".//div[@class='info']/div[@class='hd']/a/span[1]/text()").get()
            douban_item['star'] = item.xpath(".//div[@class='bd']/div[@class='star']/span[2]/text()").get()
            douban_item['value'] = item.xpath(".//div[@class='bd']/div[@class='star']/span[4]/text()").get()
            douban_item['describle'] = item.xpath(".//div[@class='bd']/p[@class='quote']/span/text()").get()
            print(douban_item)
            yield douban_item
            #將返回結果壓入item Pipline進行處理
        next_link = response.xpath("//span[@class='next']/link/@href").get()
        if next_link:
            yield scrapy.Request('http://movie.douban.com/top250' + next_link, callback=self.parse)

保存文件:

保存爲csv文件:

scrapy crawl douban_spider -o movielist.csv

保存爲json文件:

scrapy crawl douban_spider -o movielist.json

注意:使用excel打開csv文件時,常常會發生亂碼,這是由於csv數據用逗號分隔,而excel通過ANSI解碼導致的

解決方法:

在爬蟲文件中添加以下代碼,預先設置csv文件的編碼格式爲UTF8-BOM

import codecs
with codecs.open('movielist.csv','wb+') as f:
    f.write(codecs.BOM_UTF8)

結果展示: 

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