1. 程式人生 > 其它 >用scrapy爬蟲抓取慕課網課程資料詳細步驟

用scrapy爬蟲抓取慕課網課程資料詳細步驟

關於如何安裝scrapy框架,可以參考這篇文章

史上最完全Mac安裝Scrapy指南

http://www.jianshu.com/p/a03aab073a35

超簡單Windows安裝Scrapy (僅需一步)

http://www.cnblogs.com/lfoder/p/6565088.html

這裡使用的是Python2.7

例子的目標就是抓取慕課網的課程資訊

流程分析

抓取內容

例子要抓取這個網頁http://www.imooc.com/course/list 要抓取的內容是全部的課程名稱,圖片URL,課程圖片,課程人數,課程簡介,課程URL ,課程評分,課程難度,課程時長

這樣的:

我們要抓取的是這一部分

或者說抓取其中的每一個課程div

#response是爬蟲請求獲取的網頁資源,下面的程式碼可以幫助我們獲得每一個課程div

scrapy 支援使用Xpath網頁元素定位器

想抓取哪個資料,可以用xpath定位它的位置,下面介紹幾個實用的外掛:

使用火狐瀏覽器,安裝兩個擴充套件外掛Firebug和FirePath

安裝好之後,Firebug的作用是方便獲取到目標位置的原始碼,使用方法是:

滑鼠移動到網頁中你要獲取的資料的位置,右鍵單擊,然後選擇“使用Firebug檢視元素”,結果如下:

接下來可以用FirePath 除錯你的xpath表示式,方法是:

開啟目標網頁,在任意位置右鍵,選擇“Inspect in FirePath ”,結果如下:

圖中的紅色框就是xpath表示式,直接右擊網頁生成的xpath表示式在爬蟲裡用不了,需要改改。這裡列舉幾個常用,且夠用的七個符號:

以下面三句為例:

response.xpath('.//div[@class="course-card-container"]')

box.xpath('.//@href').extract()[0]

box.xpath('.//h3/text()').extract()[0]

英文 句號“.” 表示當前物件裡面的內容,比如上面就是指response和box裡面的內容;

雙斜槓 // 表示獲取所有的指定元素,比如上面第一句就是在esponse內容裡取所有的指定class屬性值為"course-card-container"的div標籤

a[@b='c'] 表示指定獲取屬性b的值為c的a標籤,

如果是單斜槓 / 就是取一個,

@ 是指定屬性

box.xpath('.//@href') 這句就是box內容裡面獲取所有的包含href屬性的html標籤,

text()就是取html標籤裡面的文字內容

最後加個.extract() 其實是將提取的內容轉換成python 的list列表結構,在scrapy裡必須加這個,否則報錯。

只要熟悉了上面七個符號的用法,就可以獲取任何你想定位的內容。寫好xpath表示式後,可以放到FirePath裡除錯,比如

response.xpath('.//div[@class="course-card-container"]')

這裡response存放的是爬蟲開啟網頁獲取的內容,用火狐瀏覽器手動開啟該網頁,將這句

.//div[@class="course-card-container"]

xpath表示式copy放到FirePath裡,按回車,結果如下:

如果想在獲取結果裡面繼續獲取下一層的東西,就直接在剛那句後面加xpath表示式,比如,我想獲取所有h3標籤裡面的文字內容

.//div[@class="course-card-container"]//h3/text()

這樣我們就獲取到了頁面裡面課程的標題~,這個xpath表示式就可以放到scprapy爬蟲裡面啦~

其他的網頁資料的定位也是類似操作:通過Firebug檢視目標資料的原始碼,通過FirePath 除錯xpath表示式。

獲取的資訊如下:

#獲取課程URL
item['url'] = 'http://www.imooc.com' + box.xpath('.//@href').extract()[0]
#獲取課程標題
item['title'] = box.xpath('.//h3/text()').extract()[0]
#獲取課程圖片URL
item['image_url'] = box.xpath('.//@src').extract()[0]
# 獲取div中的學生人數
item['student'] = box.xpath('.//div[@class="course-card-info"]/span[2]/text()').extract()[0]
# 獲取div中的課程簡介
item['introduction'] = box.xpath('.//p/text()').extract()[0].strip()

工作流程


工作流程

Scrapy框架抓取的基本流程是這樣(隨便畫了一下,不要糾結)


工程建立

在控制檯模式下(windows系統用cmd進入命令列),用cd 命令進入你要建立工程的資料夾,然後執行如下命令建立工程

scrapy startproject scrapytest

這裡的scrapytest是工程名框架會自動在當前目錄下建立一個同名的資料夾,工程檔案就在裡邊。


目錄分析

目錄結構如下圖。

scrapy.cfg: 專案的配置檔案
scrapytest/: 該專案的python模組。之後您將在此加入程式碼。
scrapytest/items.py: 專案中的item檔案.
scrapytest/pipelines.py: 專案中的pipelines檔案.
scrapytest/settings.py: 專案的設定檔案.
scrapytest/spiders/: 放置spider程式碼的目錄.

建立一個爬蟲

下面按步驟講解如何編寫一個簡單的爬蟲。

我們要編寫爬蟲,首先是建立一個Spider

我們在scrapytest/spiders/目錄下建立一個檔案MySpider.py

檔案包含一個MySpider類,它必須繼承scrapy.Spider類。

同時它必須定義一下三個屬性:

-name: 用於區別Spider。 該名字必須是唯一的,您不可以為不同的Spider設定相同的名字。 -start_urls: 包含了Spider在啟動時進行爬取的url列表。 因此,第一個被獲取到的頁面將是其中之一。 後續的URL則從初始的URL獲取到的資料中提取。 -parse() 是spider的一個方法。 被呼叫時,每個初始URL完成下載後生成的 Response 物件將會作為唯一的引數傳遞給該函式。 該方法負責解析返回的資料(response data),提取資料(生成item)以及生成需要進一步處理的URL的 Request 物件。

建立完成後MySpider.py的程式碼如下

# -*- coding: utf-8 -*-
import scrapy
class MySpider(scrapy.Spider):
    name = "MySpider"

    allowed_domains = ["imooc.com"]

    start_urls = ["http://www.imooc.com/course/list"]

    def parse(self, response):
        pass

定義爬取專案

建立完了Spider檔案,先不急著編寫爬取程式碼 我們先定義一個容器儲存要爬取的資料。

這樣我們就用到了Item 為了定義常用的輸出資料,Scrapy提供了Item類。Item物件是種簡單的容器,儲存了爬取到得資料。 其提供了 類似於詞典(dictionary-like)的API以及用於宣告可用欄位的簡單語法。

我們在工程目錄下可以看到一個items檔案,我們可以更改這個檔案或者建立一個新的檔案來定義我們的item。

這裡,我們在同一層建立一個新的item檔案CourseItems.py

CourseItems.py的程式碼如下

# -*- coding: utf-8 -*-
#引入檔案
import scrapy

class CourseItem(scrapy.Item):
    #課程標題
    title = scrapy.Field()
    #課程url
    url = scrapy.Field()
    #課程標題圖片
    image_url = scrapy.Field()
    #課程描述
    introduction = scrapy.Field()
    #學習人數
    student = scrapy.Field()
    #課程標籤
    catycray = scrapy.Field()
    #課程難度
    degree = scrapy.Field()
    #課程時長
    hour =scrapy.Field()

    #課程評分
    score=scrapy.Field()

根據如上的程式碼,我們建立了一個名為courseItem的容器,用來儲存、抓取的資訊, title->課程標題, url->課程url, image_url->課程標題圖片, introduction->課程描述, student->學習人數


編寫Spider程式碼

定義了item後我們就能進行爬取部分的工作了。

為了簡單清晰,我們先抓取一個頁面中的資訊。

首先我們編寫爬取程式碼

我們在上文說過,爬取的部分在MySpider類的parse()方法中進行。 parse()方法負責處理response並返回處理的資料以及(/或)跟進的URL。 該方法及其他的Request回撥函式必須返回一個包含 Request 及(或) Item 的可迭代的物件。

我們在之前建立的MySpider.py中編寫如下程式碼。

注意和上邊MySpider.py的區別

# -*- coding: utf-8 -*- import scrapy import urllib from scrapytest.CourseItems import CourseItem class MySpider(scrapy.Spider): name = "MySpider" allowed_domains = ["imooc.com"] start_urls = ["http://www.imooc.com/course/list"] def parse(self, response): item = CourseItem() for box in response.xpath('.//div[@class="course-card-container"]'): item['url'] = 'http://www.imooc.com' + box.xpath('.//@href').extract()[0] item['title'] = box.xpath('.//h3/text()').extract()[0] item['image_url'] = box.xpath('.//@src').extract()[0] #獲取div中的學生人數 item['student'] = box.xpath('.//div[@class="course-card-info"]/span[2]/text()').extract()[0] #獲取div中的課程簡介 item['introduction'] = box.xpath('.//p/text()').extract()[0].strip() #是否有多個 if len(box.xpath('.//div[@class="course-label"]/label/text()').extract())==1: item['catycray'] = box.xpath('.//div[@class="course-label"]/label/text()').extract()[0] elif len(box.xpath('.//div[@class="course-label"]/label/text()').extract())==2: item['catycray'] = box.xpath('.//div[@class="course-label"]/label/text()').extract()[0]+' '+ box.xpath('.//div[@class="course-label"]/label/text()').extract()[1] elif len(box.xpath('.//div[@class="course-label"]/label/text()').extract())==3: item['catycray'] = box.xpath('.//div[@class="course-label"]/label/text()').extract()[0]+' '+box.xpath('.//div[@class="course-label"]/label/text()').extract()[1]+' '+ box.xpath('.//div[@class="course-label"]/label/text()').extract()[2] else : item['catycray'] = '' #下載圖片 #urllib.urlretrieve(item['image_url'],'pic/'+item['title']+'.jpg') #返回資訊 yield scrapy.Request(item['url'], callback=self.parseNest,meta=item) #課程詳情頁 def parseNest(self, response): item = response.meta #print item item['degree'] = response.xpath('.//div[@class="static-item l"]/span[@class="meta-value"]/text()').extract()[0] item['hour'] =response.xpath('.//div[@class="static-item l"]/span[@class="meta-value"]/text()').extract()[1] item['score']=response.xpath('.//div[@class="static-item l score-btn"]/span[@class="meta-value"]/text()').extract()[0] yield item #url跟進開始 #獲取下一頁的url資訊 #url = response.xpath("//a[contains(text(),'下一頁')]/@href").extract() #if url : #將資訊組合成下一頁的url #page = 'http://www.imooc.com' + url[0] #返回url for x in xrange(2,32): page='http://www.imooc.com/course/list?page='+str(x) yield scrapy.Request(page, callback=self.parse) #url跟進結束

注:這裡用到了xpath方式來獲取頁面資訊,這裡不做過多介紹,可以參考網上的xpath教程來自己學習。

在parse()方法中response引數返回一個下載好的網頁資訊,我們然後通過xpath來尋找我們需要的資訊。 在scrapy框架中,可以使用多種選擇器來尋找資訊,這裡使用的是xpath,同時我們也可以使用BeautifulSoup,lxml等擴充套件來選擇,而且框架本身還提供了一套自己的機制來幫助使用者獲取資訊,就是Selectors。 因為本文只是為了入門所以不做過多解釋。

在執行完以上步驟之後,我們可以執行一下爬蟲,看看是否出錯。

在命令列下進入工程資料夾,然後執行

scrapy crawl MySpider

如果操作正確會顯示如下資訊。

上面資訊表示,我們已經獲取了資訊,接下來我們開始進行資訊的儲存。


使用Pipeline處理資料

當我們成功獲取資訊後,要進行資訊的驗證、儲存等工作,這裡以儲存為例。 當Item在Spider中被收集之後,它將會被傳遞到Pipeline,一些元件會按照一定的順序執行對Item的處理。 Pipeline經常進行一下一些操作: 清理HTML資料 驗證爬取的資料(檢查item包含某些欄位) 查重(並丟棄) 將爬取結果儲存到資料庫中

將資料儲存在json檔案的操作:

首先在scrapytest/目錄下建立一個檔案MyPipelines.py

MyPipelines.py程式碼如下

# -*- coding: utf-8 -*- #引入檔案 from scrapy.exceptions import DropItem import json import codecs class MyPipeline(object): def __init__(self): #開啟檔案 self.file = open('data.json', 'w') self.file =codecs.open('data.json', 'w', encoding='utf-8') # #該方法用於處理資料 def process_item(self, item, spider): # #讀取item中的資料 line = json.dumps(dict(item), ensure_ascii=False) + "n" #寫入檔案 self.file.write(line) #返回item return item

要使用Pipeline,首先要註冊Pipeline

找到settings.py檔案,這個檔案時爬蟲的配置檔案

在其中新增

ITEM_PIPELINES = { 'scrapytest.MyPipelines.MyPipeline': 1, }

上面的程式碼用於註冊Pipeline,其中scrapytest.MyPipelines.MyPipeline為你要註冊的類,右側的’1’為該Pipeline的優先順序,範圍1~1000,越小越先執行。

進行完以上操作,我們的一個最基本的爬取操作就完成了

這時我們再執行

scrapy crawl MySpider

就可以在專案根目錄下發現data.json檔案,裡面儲存著爬取的課程資訊。

這樣一個簡單的爬蟲就完成了。


存入mysql資料庫

1,先在資料庫建好跟item相同欄位的表

2.安裝python 的MySQLdb模組

pip install mysql-python

參考:

http://www.cnblogs.com/rwxwsblog/p/4572367.html

3.修改MyPipelines.py程式碼如下:

# -*- coding: utf-8 -*- #引入檔案 from scrapy.exceptions import DropItem import MySQLdb import MySQLdb.cursors from twisted.enterprise import adbapi class MyPipeline(object): def __init__(self): self.conn = MySQLdb.connect(user='root', passwd='123456', db='test', host='127.0.0.1', charset="utf8", use_unicode=True) self.cursor = self.conn.cursor() #pipeline預設呼叫 def process_item(self, item, spider): try: self.cursor.execute("insert into mooc(title, student, catycray, degree, hour,score,introduction,url,image_url) values(%s, %s, %s, %s, %s, %s, %s, %s, %s)", (item['title'], item['student'], item['catycray'], item['degree'], item['hour'], item['score'], item['introduction'], item['url'], item['image_url'])) self.conn.commit() except MySQLdb.Error, e: print "Error %d: %s" % (e.args[0], e.args[1]) return item #異常處理 def _handle_error(self, failue, item, spider): log.err(failure) 該方法在spider被開啟時被呼叫。 def open_spider(self, spider): pass #該方法在spider被關閉時被呼叫。 def close_spider(self, spider): pass

然後再次執行爬蟲,下載資料如下:

url跟進

在上面我們介紹瞭如何進行簡單的單頁面爬取,但是我們可以發現慕課網的課程是分佈在去多個頁面的,所以為了完整的爬取資訊課程資訊,我們需要進行url跟進。

為了完成這個目標需要對MySpider.py檔案進行新增:

#url跟進結束

for x in xrange(2,32): page='http://www.imooc.com/course/list?page='+str(x) yield scrapy.Request(page, callback=self.parse)

修改成功後就可以自動進行url跟進了。


下載圖片

在上文我們爬取了慕課網全部的課程資訊,但是每個課程的標題圖片我們只獲得了url並沒有下載下了,這裡我們進行圖片下載的編寫。

首先我們在CourseItems.py檔案中新增如下屬性

#圖片地址image_path = scrapy.Field()

因為我們要下載圖片,所以需要用這個屬性用來儲存下載地址。

接下來我們需要在MySpider.py新增 :

import urllib

urllib.urlretrieve(item['image_url'],'pic/'+item['title']+'.jpg')

urllib.urlretrieve(url,path)函式需要兩個引數,一個是圖片的地址url,另一個就儲存路徑。

下載圖片如下:


總結

把多餘的檔案刪除後的目錄結構

上面的處理結束後我們就成功的抓取了慕課網的全部課程資訊了。

以上就是Scrapy入門小例子了。

有人會覺得在控制檯執行scrapy 不夠方便,想在IDE環境裡執行和除錯,比如pycharm

配置步驟如下:

用pycharm 開啟scrapy專案所在資料夾,新建一個begin.py檔案,新增程式碼:

# -*- coding: utf-8 -*-
from scrapy.cmdline import execute
execute()

然後點選pycharm介面上"run"小三角按鈕旁邊的Edit Configuration,開啟後點擊左上角的“+”號,新增一個python配置,Script框裡選擇剛剛建好的begin.py檔案,

Script parameters 框 填入crawl MySpider ,其實就是crawl +爬蟲名字,其他配置選項預設,點ok,就可以執行爬蟲了。

如下:

以上,把一個經典爬蟲的所有過程都講了,會了這些可以爬取大部分網頁了,可以優化地方就是 模擬瀏覽器,多程序等,這些需要具備一定的基礎。過幾天再來分享一個更強大,更簡單易用 的爬蟲框架--pyspider,可定時,可實時,可多執行緒爬取,支援開發複雜的爬蟲系統,有興趣可以一起關注。