Scrapy爬取豆瓣電影Top250

這兩天摸索了下scrapy,剛看文檔的時(shí)候覺得有點(diǎn)生無可戀,scrapy框架個(gè)人還是覺得比較難懂的,需要學(xué)習(xí)的地方非常多,之前用beautifulsoup4爬過top250,比scrapy簡(jiǎn)單更容易理解??!

Scrapy簡(jiǎn)介

Scrapy,Python開發(fā)的一個(gè)快速、高層次的屏幕抓取和web抓取框架,用于抓取web站點(diǎn)并從頁(yè)面中提取結(jié)構(gòu)化的數(shù)據(jù)。Scrapy用途廣泛,可以用于數(shù)據(jù)挖掘、監(jiān)測(cè)和自動(dòng)化測(cè)試。 下面對(duì)每個(gè)組件都做了簡(jiǎn)單介紹,數(shù)據(jù)流如下所描述。


image
  • Scrapy Engine
    引擎負(fù)責(zé)控制數(shù)據(jù)流在系統(tǒng)中所有組件中流動(dòng),并在相應(yīng)動(dòng)作發(fā)生時(shí)觸發(fā)事件。 詳細(xì)內(nèi)容查看下面的數(shù)據(jù)流(Data Flow)部分
  • 調(diào)度器(Scheduler)
    調(diào)度器從引擎接受request并將他們?nèi)腙?duì),以便之后引擎請(qǐng)求他們時(shí)提供給引擎
  • 下載器(Downloader)
    下載器負(fù)責(zé)獲取頁(yè)面數(shù)據(jù)并提供給引擎,而后提供給spider
  • Spiders
    Spider是Scrapy用戶編寫用于分析response并提取item(即獲取到的item)或額外跟進(jìn)的URL的類。 每 個(gè)spider負(fù)責(zé)處理一個(gè)特定(或一些)網(wǎng)站
  • Item Pipeline
    Item Pipeline負(fù)責(zé)處理被spider提取出來的item。典型的處理有清理、 驗(yàn)證及持久化(例如存取到數(shù) 據(jù)庫(kù)中)
  • 下載器中間件(Downloader middlewares)
    下載器中間件是在引擎及下載器之間的特定鉤子(specific hook),處理Downloader傳遞給引擎的 response。 其提供了一個(gè)簡(jiǎn)便的機(jī)制,通過插入自定義代碼來擴(kuò)展Scrapy功能
  • Spider中間件(Spider middlewares)
    Spider中間件是在引擎及Spider之間的特定鉤子(specific hook),處理spider的輸入(response)和輸出 (items及requests)。 其提供了一個(gè)簡(jiǎn)便的機(jī)制,通過插入自定義代碼來擴(kuò)展Scrapy功能
  • 數(shù)據(jù)流(Data flow)
    Scrapy中的數(shù)據(jù)流由執(zhí)行引擎控制,其過程如下:

引擎打開一個(gè)網(wǎng)站(open a domain),找到處理該網(wǎng)站的Spider并向該spider請(qǐng)求第一個(gè)要爬取的 URL(s)。
引擎從Spider中獲取到第一個(gè)要爬取的URL并在調(diào)度器(Scheduler)以Request調(diào)度。
引擎向調(diào)度器請(qǐng)求下一個(gè)要爬取的URL。
調(diào)度器返回下一個(gè)要爬取的URL給引擎,引擎將URL通過下載中間件(請(qǐng)求(request)方向)轉(zhuǎn)發(fā)給下載 器(Downloader)。
一旦頁(yè)面下載完畢,下載器生成一個(gè)該頁(yè)面的Response,并將其通過下載中間件(返回(response)方 向)發(fā)送給引擎。
引擎從下載器中接收到Response并通過Spider中間件(輸入方向)發(fā)送給Spider處理。
Spider處理Response并返回爬取到的Item及(跟進(jìn)的)新的Request給引擎。
引擎將(Spider返回的)爬取到的Item給Item Pipeline,將(Spider返回的)Request給調(diào)度器。
(從第二步)重復(fù)直到調(diào)度器中沒有更多地request,引擎關(guān)閉該網(wǎng)站

scrapy的流程如圖,并且可歸納如下

  • 首先下載器下載request回執(zhí)的html等的response
  • 然后下載器傳給爬蟲解析
  • 接著爬蟲解析后交給調(diào)度器過濾,查重等等
  • 最后交給管道,進(jìn)行爬取數(shù)據(jù)的處理

建議大家參考下中文版的Scrapy文檔,看文檔還是比較枯燥的,Scrapy又比較難懂(大神忽略),務(wù)必要有耐心!?。。。?!

實(shí)戰(zhàn)應(yīng)用

首先下載Scrapy包

pip install scrapy

這樣安裝,windows平臺(tái)應(yīng)該是會(huì)報(bào)錯(cuò)的,我當(dāng)時(shí)裝Scrapy時(shí)廢了很大勁才弄完。安裝過程中Pycharm或者官網(wǎng)上找不到的模塊可以上這個(gè)網(wǎng)址找Unofficial Windows Binaries for Python Extension Packages
Pywin32

接著,我們打開CMD,新建一個(gè)爬蟲文件

scrapy startproject douban

image

C:\Users\ssaw\douban>tree /f
C:.
│ scrapy.cfg

└─douban
│ items.py
│ middlewares.py
│ pipelines.py
│ settings.py
init.py

└─spiders
init.py

簡(jiǎn)單介紹下這些文件

  • scrapy.cfg: 項(xiàng)目的配置文件
  • douban/: 該項(xiàng)目的python模塊。之后您將在此加入代碼
  • douban/items.py: 項(xiàng)目中的item文件
  • douban/pipelines.py: 項(xiàng)目中的pipelines文件
  • douban/settings.py: 項(xiàng)目的設(shè)置文件
  • douban/spiders/:放置spider代碼的目錄

編輯items.py文件

# -*- coding: utf-8 -*-

# Define here the models for your scraped items
#
# See documentation in:
# http://doc.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_name = scrapy.Field()
    movie_star = scrapy.Field()
    movie_quote = scrapy.Field()
  • 首先,引入Scrapy
  • 接著,創(chuàng)建一個(gè)類,繼承自scrapy.item,這個(gè)是用來儲(chǔ)存要爬下來的數(shù)據(jù)的存放容器,類似orm的寫法
  • 我們要記錄的是:電影的名字、電影的評(píng)分、電影的引述(quote)

現(xiàn)在,我們?cè)趕piders文件夾下創(chuàng)建douban_spider.py
在我們編寫爬蟲之前,先了解一下scrapy的爬取機(jī)制,scrapy提取數(shù)據(jù)有自己的一套機(jī)制。它們被稱作選擇器(seletors),因?yàn)樗麄兺ㄟ^特定的 XPath 或者 CSS 表達(dá)式來“選擇” HTML文件中的某個(gè)部分。
之前我在博客上也總結(jié)過一篇使用Xpath模擬登陸GitHub有興趣可以看一下
附上Xpath學(xué)習(xí)教程Xpath

獲取網(wǎng)頁(yè)數(shù)據(jù)

打開Chrome(F12),查找元素
豆瓣電影TOP250

image

紅框圈出來的分別代表

movie_name = div[@class="hd"]/a/span/
movie_star = div[@class="bd"]/div[@class="star"]/span[@class="rating_num"]
movie_quote = div[@class="bd"]/p[@class="quote"]/span[@class="inq"]

# _*_ coding=utf-8 _*_

from scrapy.spiders import Spider
from scrapy.selector import Selector

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

    def parse(self, response):
        # print(response.body)
        selector = Selector(response)

        # print(selector)
        movies = selector.xpath('//div[@class="info"]')
        for movie in movies:
            movie_name = movie.xpath('div[@class="hd"]/a/span/text()').extract()
            movie_star = movie.xpath('div[@class="bd"]/div[@class="star"]/span[@class="rating_num"]/text()').extract()
            movie_quote = movie.xpath('div[@class="bd"]/p[@class="quote"]/span[@class="inq"]/text()').extract()


            print(movie_name)
            print(movie_star)
            print(movie_quote)

我們打開setting.py,加上U-A

USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36'

在CMD中輸入scrapy crawl db,運(yùn)行如下:


image

我們還可以在douban文件根目錄創(chuàng)建一個(gè)main.py,這樣就可以在Pycharm中運(yùn)行了

from scrapy import cmdline
cmdline.execute("scrapy crawl db".split())

使用Item

Item對(duì)象是自定義的python字典。 您可以使用標(biāo)準(zhǔn)的字典語(yǔ)法來獲取到其每個(gè)字段的值。(字段即是我們之前用Field賦值的屬性),Spider將會(huì)將爬取到的數(shù)據(jù)以 Item 對(duì)象返回。

item = DoubanItem()

item['movie_name'] = movie_name
item['movie_star'] = movie_star
item['movie_quote'] = movie_quote

好了,現(xiàn)在我們先試著爬取單頁(yè)面,查看下結(jié)果后,再去爬取多頁(yè)面

from scrapy.spiders import Spider
from scrapy.selector import Selector
from douban.items import DoubanItem



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

    def parse(self, response):
        # print(response.body)
        selector = Selector(response)

        # print(selector)
        movies = selector.xpath('//div[@class="info"]')
        for movie in movies:
            movie_name = movie.xpath('div[@class="hd"]/a/span/text()').extract()
            movie_star = movie.xpath('div[@class="bd"]/div[@class="star"]/span[@class="rating_num"]/text()').extract()
            movie_quote = movie.xpath('div[@class="bd"]/p[@class="quote"]/span[@class="inq"]/text()').extract()

            #print(movie_name)
            #print(movie_star)
            #print(movie_quote)

            item = DoubanItem()

            item['movie_name'] = movie_name
            item['movie_star'] = movie_star
            item['movie_quote'] = movie_quote
            yield item
            print(movie_name)
            print(movie_star)
            print(movie_quote)
  • 首先,我們先從scrapy中獲得所需要的通用的 spider和 selector
  • 接著,我們使用Item將爬取的數(shù)據(jù)返回
  • 創(chuàng)建了一個(gè)DouBanSpider,繼承了 scrapy.Spider 類, 且定義以下三個(gè)屬性:
  1. name: 用于區(qū)別Spider。 該名字必須是唯一的,您不可以為不同的Spider設(shè)定相同的名字
  2. start_urls: 包含了Spider在啟動(dòng)時(shí)進(jìn)行爬取的url列表。 因此,第一個(gè)被獲取到的頁(yè)面將是其中之一, 后續(xù)的URL則從初始的URL獲取到的數(shù)據(jù)中提取。
  3. parse() 是spider的一個(gè)方法。 被調(diào)用時(shí),每個(gè)初始URL完成下載后生成的 Response 對(duì)象將會(huì)作為唯一的參數(shù)傳遞給該函數(shù)。 該方法負(fù)責(zé)解析返回的數(shù)據(jù)(response data),提取數(shù)據(jù)(生成item)以及生成需要進(jìn)一步處理的URL的 Request 對(duì)象
  • seletor的方法返回后一定要用它的 extract()方法,來返回一個(gè)列表 ;extract()文檔的定義:串行化并將匹配到的節(jié)點(diǎn)返回一個(gè)unicode字符串列表。 結(jié)尾是編碼內(nèi)容的百分比
  • 接著,我們把得到的數(shù)據(jù)保存在Item中
  • 最后,我們使用Feed exports來保存數(shù)據(jù)
  • 這里使用了yield生成器函數(shù),生成器函數(shù)和迭代器有密切關(guān)系,也并不是很容易理解,這一點(diǎn)需要多多學(xué)習(xí)
#看一個(gè)yield函數(shù)的示例
#函數(shù)在每次循環(huán)時(shí)都會(huì)產(chǎn)生一個(gè)值,之后將其返回給它的調(diào)用者
#函數(shù)不斷的生成數(shù)字的平方

def gensquares(N):
    for i in range(N):
        yield i ** 2
        
for i in gensquares(5):
    print(i, end=' ')

0 1 4 9 16 

好了,spider暫時(shí)寫完了,我們?cè)囍\(yùn)行下

scrapy crawl db -o douban.json -t json

-o 后面是導(dǎo)出文件名,-t 后面是導(dǎo)出類型。
然后來看一下導(dǎo)出的結(jié)果,Pycharm打開json文件即可


image

打印出來的內(nèi)容需要編碼
我們換種方式,把文件格式保存為CSV,使用EXCEL打開

scrapy crawl db -o douban.csv -t csv

image

用excel打開后假如是一堆亂碼,就使用記事本打開,把它“另存為”時(shí),編碼選擇ANSI


image

好了,現(xiàn)在我們添加多頁(yè)面鏈接,完整地把TOP250爬取下來
我們從Elements中找到翻頁(yè)lianjie


image
next_page =response.selector.xpath('//span[@class="next"]/link/@href').extract()
if next_page:
    next_page = next_page[0]
    print(next_page)
    yield Request(self.url + next_page, callback=self.parse)

CMD輸入scrapy crawl db -o douban.csv -t csv ,開始運(yùn)行


image

學(xué)習(xí)Scrapy需要反復(fù)查看文檔、資料,這是個(gè)簡(jiǎn)單的學(xué)習(xí)總結(jié),這兩天準(zhǔn)備再去學(xué)習(xí)MongoDB數(shù)據(jù)庫(kù),大家一起加油??!

參考鏈接
參考鏈接
Scrapy文檔
GitHub
簡(jiǎn)書
最后,歡迎大家訪問我的博客Treehl的博客

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • scrapy學(xué)習(xí)筆記(有示例版) 我的博客 scrapy學(xué)習(xí)筆記1.使用scrapy1.1創(chuàng)建工程1.2創(chuàng)建爬蟲模...
    陳思煜閱讀 13,044評(píng)論 4 46
  • Scrapy介紹 Scrapy是一個(gè)為了爬取網(wǎng)站數(shù)據(jù),提取結(jié)構(gòu)性數(shù)據(jù)而編寫的應(yīng)用框架。 可以應(yīng)用在包括數(shù)據(jù)挖掘,信...
    JasonDing閱讀 122,776評(píng)論 15 126
  • 天的那邊,雛陽(yáng)高照 海的遠(yuǎn)邊,酒雨紛紛 綿綿絲雨,悠悠我心 徐徐清風(fēng),柔柔撫心 半載未歸,思之如狂 長(zhǎng)相思情,轉(zhuǎn)難入夢(mèng)
    南國(guó)梓桐君閱讀 336評(píng)論 0 1
  • 成功的時(shí)候,誰都是朋友。但只有母親——她是失敗時(shí)的伴侶。 感謝媽媽: 自己活了二十多年,最需要感謝的就是母親。我很...
    宋東珂_閱讀 520評(píng)論 0 2
  • 一、釋運(yùn)氣 運(yùn)氣,是五運(yùn)六氣的簡(jiǎn)稱。 五運(yùn):金、木、水、火、土。(行的東西代表)十天干?陰陽(yáng)干 六氣:太陽(yáng)寒水、厥...
    王胖胖搖啊搖閱讀 1,721評(píng)論 1 3

友情鏈接更多精彩內(nèi)容