運維學python之爬蟲高級篇(五)scrapy爬取豆瓣電影TOP250

對於scrapy我們前面已經介紹了簡單的應用,今天我們用一個完整的例子,爬取豆瓣電影TOP250來做一個小的練習,把scrapy階段做一個總結。

1 環境配置

語言:Python 3.6.1 
IDE: Pycharm
瀏覽器:firefox
爬蟲框架:Scrapy 1.5.0
操作系統:Windows 10 家庭中文版

2 爬取前分析

2.1 需要保存的數據

首先確定我們要獲取的內容,在items中定義字段,來將非結構化數據生成結構化數據,獲取的內容主要包括:排名、電影名稱、得分、評論人數。
如下圖:
運維學python之爬蟲高級篇(五)scrapy爬取豆瓣電影TOP250

在scrapy中需要定義items.py來配置我們的字段:

import scrapy

class SpItem(scrapy.Item):
    """
    定義item字段
    """
    # 排名
    ranking = scrapy.Field()
    # 電影名稱
    movie_name = scrapy.Field()
    # 評分
    score = scrapy.Field()
    # 評論人數
    people_num = scrapy.Field()

2.2 編寫爬蟲spider

基本的框架如下:

import scrapy
from sp.items import SpItem

class DoubanSpider(scrapy.Spider):
    """
    爬取豆瓣電影TOP250類,繼承了scrapy.Spider類
    """
    # 定義spider名稱,必須要有而且是唯一值
    name = 'douban'
    # 初始url,可以使用start_requests(self)也可以直接使用start_urls方式,而且區別是start_requests(self)可以更靈活,添加更多內容,如header等。
    start_urls = ['https://movie.douban.com/top250']

    def parse(self, response):
        """
        解析response中的字段,傳送到items中
        """
                # 實例化item,用來添加獲取的內容
                item = SpItem()
                pass

下面我們就看一看我們需要解析的內容,打開firefox瀏覽器,開發者模式(F12),通過元素選擇箭頭選擇我們要獲取的內容,發現我們要獲取的當前頁面的信息都在一個class爲grid_view的ol標籤中,如下圖:
運維學python之爬蟲高級篇(五)scrapy爬取豆瓣電影TOP250

2.3 使用scrapy shell獲取內容

因爲我們無法一次就能準確獲取我們的內容,所以建議還是先用scrapy shell來獲取內容再執行,執行結果如下:

scrapy shell "https://movie.douban.com/top250"

執行結果如下:
運維學python之爬蟲高級篇(五)scrapy爬取豆瓣電影TOP250
小夥伴們有沒有發現問題,沒錯看到403了,這是什麼原因,難道是因爲沒有添加header,好的那我就加上header試試,scrapy shell 添加header命令運行如下:

scrapy shell -s USER_AGENT="Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:58.0) Gecko/20100101 Firefox/58.0" "https://movie.douban.com/top250"

使用-s參數更多參數可以查看官方文檔(scrapy shell),傳入USER_AGENT頭信息,頭信息我們哪裏獲取呢?見下圖:
運維學python之爬蟲高級篇(五)scrapy爬取豆瓣電影TOP250
讓我們看一下結果:
運維學python之爬蟲高級篇(五)scrapy爬取豆瓣電影TOP250
ok,成功了,那我們就獲取我們想要的內容吧。
通過使用開發者工具和scrapy shell,我們先獲取ol下的所有li標籤,然後循環每個標籤提取我們需要的內容,分析步驟略了,大家多聯繫xpath和css使用方法即可。最終結果如下:

# 所有電影的標籤,每個電影的信息在一個li中,我們先獲取所有的li標籤
 movies = response.css("ol.grid_view li")
 # 循環每一個li標籤,也就是每一個電影的信息
for movie in movies:
     # 排名
     item['ranking'] = movie.css("div.pic em::text").extract_first()
     # 電影名字
     item['movie_name'] = movie.css("div.hd a span:first-child::text").extract_first()
     # 得分
     item['score'] = movie.css("div.star span.rating_num::text").extract_first()
     # 評論人數
     item['people_num'] = movie.css("div.star span:last-child::text").re("\d+")[0]

完善我們的spider代碼(douban_spider.py)如下:

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

class DoubanSpider(scrapy.Spider):
    """
    爬取豆瓣電影TOP250
    """
    name = 'douban'
    start_urls = ['https://movie.douban.com/top250']

    def parse(self, response):
        """
        解析response中的字段,傳送到items中
        """
        item = SpItem()
        movies = response.css("ol.grid_view li")
        for movie in movies:
            # 排名
            item['ranking'] = movie.css("div.pic em::text").extract_first()
            # 電影名字
            item['movie_name'] = movie.css("div.hd a span:first-child::text").extract_first()
            # 得分
            item['score'] = movie.css("div.star span.rating_num::text").extract_first()
            # 評論人數
            item['people_num'] = movie.css("div.star span:last-child::text").re("\d+")[0]
            yield item

2.4 運行spider

我的spider裏面沒有添加頭,我在settings.py中增加了如下參數:
運維學python之爬蟲高級篇(五)scrapy爬取豆瓣電影TOP250
這裏添加也是可以的 。
運行spider輸出到csv文件命令如下:

scrapy crawl douban -o douban.csv

執行結果如下:
運維學python之爬蟲高級篇(五)scrapy爬取豆瓣電影TOP250
這裏有兩個地方要注意:
1.如果直接用excel打開這個csv文件的話,會出現亂碼,需要用類似notepadd++工具打開後選擇編碼--轉碼爲utf-8格式,然後再用excel打開後就沒有這個問題了。
2.我們看輸出結果是有空行的,這個需要修改scrapy的源碼內容,在pycharm中連續點擊兩下shift鍵,彈出搜索框後搜索exporters.py,如下圖:
運維學python之爬蟲高級篇(五)scrapy爬取豆瓣電影TOP250
找到下面內容,添加一行newline=' ',如下圖:
運維學python之爬蟲高級篇(五)scrapy爬取豆瓣電影TOP250
我們再次執行操作後輸出結果如下:
運維學python之爬蟲高級篇(五)scrapy爬取豆瓣電影TOP250
是不是很神奇!

2.5 爬取所有頁面內容

首先還是分析頁面,找到最下面頁面內容部分,用瀏覽器工具找到後頁所對應的標籤,裏面的href內容就是我們要獲取的內容,如下:
運維學python之爬蟲高級篇(五)scrapy爬取豆瓣電影TOP250
注意這裏獲取的是相對鏈接,不是絕對鏈接,有一下兩種方式調用相對連接:

        # scrapy 1.4版本以前的版本使用此段代碼
        next_page = response.css("span.next a::attr(href)").extract_first()
        if next_page is not None:
            next_page = response.urljoin(next_page)
            yield scrapy.Request(next_page, callback=self.parse)

        # scrapy 1.4版本以後加入了follow方法,可以使用下面代碼
        # next_page = response.css("span.next a::attr(href)").extract_first()
        # if next_page is not None:
        #     yield response.follow(next_page, callback=self.parse)

我們的完整spider代碼如下:

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

class DoubanSpider(scrapy.Spider):
    """
    爬取豆瓣電影TOP250
    """
    name = 'douban'
    start_urls = ['https://movie.douban.com/top250']

    def parse(self, response):
        """
        解析response中的字段,傳送到items中
        """
        item = SpItem()
        movies = response.css("ol.grid_view li")
        for movie in movies:
            # 排名
            item['ranking'] = movie.css("div.pic em::text").extract_first()
            # 電影名字
            item['movie_name'] = movie.css("div.hd a span:first-child::text").extract_first()
            # 得分
            item['score'] = movie.css("div.star span.rating_num::text").extract_first()
            # 評論人數
            item['people_num'] = movie.css("div.star span:last-child::text").re("\d+")[0]
            yield item

        # scrapy 1.4版本以前的版本使用此段代碼
        next_page = response.css("span.next a::attr(href)").extract_first()
        if next_page is not None:
            next_page = response.urljoin(next_page)
            yield scrapy.Request(next_page, callback=self.parse)

        # scrapy 1.4版本以後加入了follow方法,可以使用下面代碼
        # next_page = response.css("span.next a::attr(href)").extract_first()
        # if next_page is not None:
        #     yield response.follow(next_page, callback=self.parse)

輸出結果如下:
運維學python之爬蟲高級篇(五)scrapy爬取豆瓣電影TOP250
除去標題,正好250。

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