[Python Scrapy爬蟲] 二.翻頁爬取農產品資訊並儲存本地

Eastmount發表於2018-02-10

前面 "Python爬蟲之Selenium+Phantomjs+CasperJS" 介紹了很多Selenium基於自動測試的Python爬蟲程式,主要利用它的xpath語句,通過分析網頁DOM樹結構進行爬取內容,同時可以結合Phantomjs模擬瀏覽器進行滑鼠或鍵盤操作。但是,更為廣泛使用的Python爬蟲框架是——Scrapy爬蟲。這篇文章是一篇基礎文章,主要內容包括:

    1.Scrapy爬取貴州農產品的詳細步驟;
    2.Scrapy如何將資料儲存至Json或CSV檔案中;
    3.Scrapy實現三種翻頁方法爬取農產品資料。

下面提供前面的一些相關文章:

    官方 Scrapy  : http://scrapy.org/
    官方英文文件: http://doc.scrapy.org/en/latest/index.html
    官方中文文件: https://scrapy-chs.readthedocs.org/zh_CN/0.24/index.html

    入門安裝知識: [Python爬蟲] scrapy爬蟲系列 <一>.安裝及入門介紹
  BeautifulSoup:
[python爬蟲] BeautifulSoup爬取+CSV儲存貴州農產品資料


在做資料分析時,通常會遇到預測商品價格的情況,而在預測價格之前需要爬取海量的商品價格資訊,比如淘寶、京東商品等,這裡作者採用Scrapy技術爬取貴州農產品資料集。

輸入 "http://www.gznw.gov.cn/priceInfo/getPriceInfoByAreaId.jx?areaid=22572&page=1網址,開啟貴州農經網,可以檢視貴州各個地區農產品每天價格的波動情況,如下圖所示,主要包括五個欄位:品種名稱、價格、計量單位、所在市場、上傳時間。


Scrapy框架自定義爬蟲主要步驟如下:

  • 在CMD命令列模型下建立爬蟲工程,即建立GZProject工程爬取貴州農經網。
  • 在items.py檔案中定義我們要抓取的資料欄目,對應商品名稱、價格、計量單位等五個欄位。
  • 通過瀏覽器審查元素功能分析所需爬取內容的DOM結構並定位HTML節點。
  • 建立Spiders爬蟲檔案,定位並爬取所需內容。
  • 分析網頁翻頁方法,併傳送多頁面跳轉爬取請求,不斷執行Spiders爬蟲直到結束。
  • 設定pipelines.py檔案,將爬取的資料集儲存至本地Json檔案或CSV檔案中。
  • 設定settings.py檔案,設定爬蟲的執行優先順序。

下面是完整的實現過程,重點知識是如何實現翻頁爬取及多頁面爬取,希望對您有幫助。




一. 建立工程

在Windows環境下,我們呼叫“Ctrl+R”快捷鍵開啟執行對話方塊,然後輸出“cmd”命令開啟命令列模式,然後呼叫“cd”命令去到某個目錄下,再呼叫“scrapy startproject GZProject”命令建立爬取貴州農經網產品資訊的爬蟲工程。

建立Scrapy爬蟲

scrapy startproject GZProject

在本地C盤根目錄建立的GZProject工程目錄如下圖所示,包括常見的檔案,如items.py、middlewares.py、pipelines.py、settings.py以及資料夾spiders等。




二. 設定items檔案

接在我們需要在items.py檔案中定義需要爬取的欄位,這裡主要是五個欄位,呼叫scrapy.item子類的 Field()函式建立欄位,程式碼如下所示。



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 GzprojectItem(scrapy.Item):
    num1 = scrapy.Field()           #品種名稱
    num2 = scrapy.Field()           #價格
    num3 = scrapy.Field()           #計量單位
    num4 = scrapy.Field()           #所在市場
    num5 = scrapy.Field()           #上傳時間

接下來就是核心內容,通過分析網頁DOM結構並編寫對應Spiders爬蟲程式碼。




三. 瀏覽器審查元素

開啟任意瀏覽器,然後呼叫“審查元素”或“檢查”功能(該功能在不同瀏覽器中稱呼不同,但功能都是相似的)檢視所需爬取內容的HTML原始碼,比如Chrome瀏覽器定位方法如圖13.21所示。選中需要爬取元素,然後右鍵滑鼠,點選“檢查”按鈕,可以看到元素對應的HTML原始碼,比如圖中的右邊部分。



通過審查元素功能,我們可以發現每行資料都位於<tr>節點下,其class屬性為“odd gradeX”,如圖13.22所示,接著呼叫scrapy框架的xpath、css等功能進行爬取。




四. 建立Spiders爬蟲並執行

然後在spiders資料夾下建立一個Python檔案,主要用於實現Spider爬蟲程式碼,建立GZSpider.py檔案,工程目錄如下圖所示。




增加程式碼如下所示,在GZSpider類中定義了爬蟲名(name)為“gznw”,同時程式碼中allowed_domains表示所爬取網址的跟地址,start_urls表示開始爬取的網頁地址,然後呼叫parse()函式進行爬取,這裡首先爬取該網友的標題,通過response.xpath('//title')函式實現。程式碼如圖所示:



GZSpider.py

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

class GZSpider(scrapy.Spider):
    name = "gznw"                #貴州農產品爬蟲
    allowed_domains = ["gznw.gov.cn"]
    start_urls = [
     "http://www.gznw.gov.cn/priceInfo/getPriceInfoByAreaId.jx?areaid=22572&page=1"
    ]

    def parse(self, response):
        for t in response.xpath('//title'):
            title = t.extract()
            print title
        for t in response.xpath('//title/text()'):
            title = t.extract()
            print title 

接下來進入C工程目錄,執行下列命令啟動Spider爬蟲。

cd GZProject
scrapy crawl gznw

"scrapy crawl gznw"啟動Spider爬蟲,爬取貴州農經網商品,執行如圖所示。程式開始執行,自動使用start_urls構造Request併傳送請求,然後呼叫parse()函式對其進行解析,在這個解析過程中可能會通過連結再次生成Request,如此不斷迴圈,直到返回的文字中再也沒有匹配的連結,或排程器中的Request物件用盡,程式才停止。



輸出結果如下所示,包括爬取的標題HTML原始碼“<title>貴州農經網</title>”和標題內容“貴州農經網”,如圖所示。


接下來我們需要爬取商品資訊,呼叫response.xpath('//tr[@class="odd gradeX"]')方法定位到class屬性為“odd gradeX”的tr節點,並分別獲取五個td節點,對應五個欄位內容。完整程式碼如下所示:

GZSpider.py

# -*- coding: utf-8 -*-
import scrapy
from scrapy import Request
from scrapy.selector import Selector  
from GZProject.items import *  

class GZSpider(scrapy.Spider):
    name = "gznw"                #貴州農產品爬蟲
    allowed_domains = ["gznw.gov.cn"]
    start_urls = [
       "http://www.gznw.gov.cn/priceInfo/getPriceInfoByAreaId.jx?areaid=22572&page=1"
    ]

    def parse(self, response): 
        print '----------------Start------------------'
        print response.url

        for sel in response.xpath('//tr[@class="odd gradeX"]'):
            item = GzprojectItem()
            num1 = sel.xpath('td[1]/text()').extract()[0]
            num2 = sel.xpath('td[2]/text()').extract()[0]
            num3 = sel.xpath('td[3]/text()').extract()[0]
            num4 = sel.xpath('td[4]/text()').extract()[0]
            num5 = sel.xpath('td[5]/text()').extract()[0]
            print num1,num2,num3,num4,num5
            item['num1'] = num1
            item['num2'] = num2
            item['num3'] = num3
            item['num4'] = num4
            item['num5'] = num5
            yield item
        print '\n'

輸出內容如下所示,同時呼叫item = GzprojectItem()”程式碼宣告瞭欄目item,再呼叫“item['num1'] = num1”程式碼將爬取的資料儲存至欄目中。

----------------Start------------------
http://www.gznw.gov.cn/priceInfo/getPriceInfoByAreaId.jx?areaid=22572&page=1
獼猴桃 26 元/公斤 貴陽市息烽縣城區集貿市場 2018-02-09 14:22:28
山楂 40 元/公斤 貴陽市息烽縣城區集貿市場 2018-02-09 14:22:28
柿子 12 元/公斤 貴陽市息烽縣城區集貿市場 2018-02-09 14:22:28
板栗 36 元/公斤 貴陽市息烽縣城區集貿市場 2018-02-09 14:22:28
開心果 80 元/公斤 貴陽市息烽縣城區集貿市場 2018-02-09 14:22:28
草莓 50 元/公斤 貴陽市息烽縣城區集貿市場 2018-02-09 14:22:28
核桃 36 元/公斤 貴陽市息烽縣城區集貿市場 2018-02-09 14:22:28
菜籽油 20 元/公斤 貴陽市息烽縣城區集貿市場 2018-02-09 14:22:28
龍眼 20 元/公斤 貴陽市息烽縣城區集貿市場 2018-02-09 14:22:28
車釐子 100 元/公斤 貴陽市息烽縣城區集貿市場 2018-02-09 14:22:28

對應輸出內容如圖所示。



講到這裡,我們已經將貴州農經網第一頁的商品資訊爬取了,那其他頁面的資訊,不同日期的商品資訊如何爬取呢?Scrapy又怎麼實現跳轉翻頁爬蟲呢?




五. 實現翻頁功能及多頁面爬取

接下來我們講解Scrapy爬蟲的三種翻頁方法供大家學習。當然還有更多方法,比如利用Rule類定義網頁超連結的規則進行爬取,請讀者下來研究,這裡主要提供三種簡單的翻頁思想。

貴州農經網的超連結可以通過URL欄位“page=頁碼”實現翻頁,比如第二頁的超連結為“http://www.gznw.gov.cn/priceInfo/getPriceInfoByAreaId.jx?areaid=22572&page=2”,我們訪問該超連結就可以獲取第二頁的商品資訊,如下圖所示,訪問其他網頁的原理一樣。



方法一:定義URLs超連結列表單分別爬取

Scrapy框架是支援並行爬取的,其爬取速度非常快,如果讀者想爬取多個網頁,可以將網頁URL依次列在start_urls中。

# -*- coding: utf-8 -*-
import scrapy
from scrapy import Request
from scrapy.selector import Selector  
from GZProject.items import *  

class GZSpider(scrapy.Spider):
    name = "gznw"                #貴州農產品爬蟲
    allowed_domains = ["gznw.gov.cn"]
    start_urls = [
     "http://www.gznw.gov.cn/priceInfo/getPriceInfoByAreaId.jx?areaid=22572&page=1",
     "http://www.gznw.gov.cn/priceInfo/getPriceInfoByAreaId.jx?areaid=22572&page=2",
     "http://www.gznw.gov.cn/priceInfo/getPriceInfoByAreaId.jx?areaid=22572&page=3"
    ]

    def parse(self, response): 
        print '----------------Start------------------'
        print response.url

        for sel in response.xpath('//tr[@class="odd gradeX"]'):
            item = GzprojectItem()
            num1 = sel.xpath('td[1]/text()').extract()[0]
            num2 = sel.xpath('td[2]/text()').extract()[0]
            num3 = sel.xpath('td[3]/text()').extract()[0]
            num4 = sel.xpath('td[4]/text()').extract()[0]
            num5 = sel.xpath('td[5]/text()').extract()[0]
            print num1,num2,num3,num4,num5

        print '\n'

輸出如下圖所示,可以看到採用Scrapy爬取了三頁商品內容。

方法二:拼接不同網頁URL併傳送請求爬取

假設我們的URL很多,如果採用方法一顯然是不可行的,那麼怎麼處理呢?這裡我們提出了第二種方法,通過拼接不同網頁的URL,迴圈傳送請求進行爬取。拼接方法如下:

next_url="http://www.gznw.gov.cn/priceInfo/getPriceInfoByAreaId.jx?areaid=22572&page="+str(i)

在parse()函式中定義一個while迴圈,通過“yield Request(next_url)”程式碼傳送新的爬取請求,並迴圈呼叫parse()函式進行爬取。完整程式碼如下所示:

GZSpider.py

# -*- coding: utf-8 -*-
import scrapy
from scrapy import Request
from scrapy.selector import Selector  
from GZProject.items import *  

class GZSpider(scrapy.Spider):
    name = "gznw"                #貴州農產品爬蟲
    allowed_domains = ["gznw.gov.cn"]
    start_urls = [
     "http://www.gznw.gov.cn/priceInfo/getPriceInfoByAreaId.jx?areaid=22572&page=1"
    ]

    def parse(self, response): 
        print '----------------Start------------------'
        print response.url

        for sel in response.xpath('//tr[@class="odd gradeX"]'):
            item = GzprojectItem()
            num1 = sel.xpath('td[1]/text()').extract()[0]
            num2 = sel.xpath('td[2]/text()').extract()[0]
            num3 = sel.xpath('td[3]/text()').extract()[0]
            num4 = sel.xpath('td[4]/text()').extract()[0]
            num5 = sel.xpath('td[5]/text()').extract()[0]
            print num1,num2,num3,num4,num5
            item['num1'] = num1
            item['num2'] = num2
            item['num3'] = num3
            item['num4'] = num4
            item['num5'] = num5
            yield item
        print '\n'

        #迴圈換頁爬取
        i = 2
        while i<=10:
            next_url = "http://www.gznw.gov.cn/priceInfo/getPriceInfoByAreaId.jx?areaid=22572&page="+str(i)
            i = i + 1
            yield Request(next_url)

輸出部分結果如下所示:

----------------Start------------------
http://www.gznw.gov.cn/priceInfo/getPriceInfoByAreaId.jx?areaid=22572&page=8
豇豆 12 元/公斤 貴陽市息烽縣城區集貿市場 2018-02-09 14:22:25
紅薯 12 元/公斤 貴陽市息烽縣城區集貿市場 2018-02-09 14:22:25
老南瓜 15 元/公斤 貴陽市息烽縣城區集貿市場 2018-02-09 14:22:25
菠菜 12 元/公斤 貴陽市息烽縣城區集貿市場 2018-02-09 14:22:25
平菇/凍菌 20 元/公斤 貴陽市息烽縣城區集貿市場 2018-02-09 14:22:25
貢梨 26 元/公斤 貴陽市息烽縣城區集貿市場 2018-02-09 14:22:25
油菜薹 23 元/公斤 貴陽市息烽縣城區集貿市場 2018-02-09 14:22:25
韭菜 15 元/公斤 貴陽市息烽縣城區集貿市場 2018-02-09 14:22:25
綠豆(幹) 12 元/公斤 貴陽市息烽縣城區集貿市場 2018-02-09 14:22:25
絲瓜 12 元/公斤 貴陽市息烽縣城區集貿市場 2018-02-09 14:22:25

----------------Start------------------
http://www.gznw.gov.cn/priceInfo/getPriceInfoByAreaId.jx?areaid=22572&page=10
黃瓜 15 元/公斤 貴陽市息烽縣城區集貿市場 2018-02-09 14:22:25
花生油 40 元/公斤 貴陽市息烽縣城區集貿市場 2018-02-09 14:22:25
鵪鶉蛋 20 元/公斤 貴陽市息烽縣城區集貿市場 2018-02-09 14:22:25
血橙 15 元/公斤 貴陽市息烽縣城區集貿市場 2018-02-09 14:22:24
羊肉 240 元/公斤 貴陽市息烽縣城區集貿市場 2018-02-09 14:22:24
蓮花白 6 元/公斤 貴陽市息烽縣城區集貿市場 2018-02-09 14:22:24
小蔥 12 元/公斤 貴陽市息烽縣城區集貿市場 2018-02-09 14:22:24
綠豆 25 元/公斤 貴陽市息烽縣城區集貿市場 2018-02-09 14:22:24
麵粉(標準一級) 6 元/公斤 貴陽市息烽縣城區集貿市場 2018-02-09 14:22:24
臍橙 15 元/公斤 貴陽市息烽縣城區集貿市場 2018-02-09 14:22:24

----------------Start------------------
http://www.gznw.gov.cn/priceInfo/getPriceInfoByAreaId.jx?areaid=22572&page=6
羔蟹 50 元/公斤 貴陽市息烽縣城區集貿市場 2018-02-09 14:22:26
草魚 50 元/公斤 貴陽市息烽縣城區集貿市場 2018-02-09 14:22:26
青蛇果 36 元/公斤 貴陽市息烽縣城區集貿市場 2018-02-09 14:22:26
紅蛇果 32 元/公斤 貴陽市息烽縣城區集貿市場 2018-02-09 14:22:26
芒果 26 元/公斤 貴陽市息烽縣城區集貿市場 2018-02-09 14:22:26
豬肉(肥瘦) 32 元/公斤 貴陽市息烽縣城區集貿市場 2018-02-09 14:22:26
都勻毛尖 1,000 元/公斤 貴陽市息烽縣城區集貿市場 2018-02-09 14:22:26
鯉魚 60 元/公斤 貴陽市息烽縣城區集貿市場 2018-02-09 14:22:26
鰱魚 60 元/公斤 貴陽市息烽縣城區集貿市場 2018-02-09 14:22:26
鱔魚 60 元/公斤 貴陽市息烽縣城區集貿市場 2018-02-09 14:22:26

方法三:獲取下一頁超連結請求爬取內容

下面講解另一種方法,獲取下一頁的超連結併傳送請求進行爬取。通過審查元素,我們可以看到“下一頁”對應的HTML原始碼如下圖所示。



這裡我們通過程式碼獲取class為“page-link next”的超連結(<a>),如果存在“下一頁”超連結,則進行跳轉爬取,如果“下一頁”超連結為空,則停止爬取。核心程式碼如下:

next_url = response.xpath('//a[@class="page-link next"]/@href').extract()
if next_url is not None:
    next_url = 'http://www.gznw.gov.cn/priceInfo/getPriceInfoByAreaId.jx' + next_url[0]
    yield Request(next_url, callback=self.parse)

爬取的結果為"?areaid=22572&page=3",再對獲取的超連結進行拼接,得到的URL為"http://www.gznw.gov.cn/priceInfo/getPriceInfoByAreaId.jx?areaid=22572&page=3",再呼叫Request()函式傳送請求,爬取內容。但由於貴州農經網有4萬多個頁面,建議大家設定爬取網頁的數量,程式碼如下:

i = 0
next_url = response.xpath('//a[@class="page=link next"]/@href').extract()
if next_(url is not None) and i<20:
    i = i + 1
    next_url = 'http://www.gznw.gov.cn/priceInfo/getPriceInfoByAreaId.jx' + next_url[0]
    yield Request(next_url, callback=self.parse)

接下來告訴大家如何將爬取的資料儲存至本地。




六. 設定pipelines檔案儲存資料至本地

pipeLine檔案是用來對Spider返回的Item列表進行儲存操作,可以寫入到檔案或者資料庫中。pipeLine只有一個需要實現的方法:process_item比如將我們的Item儲存到JSON格式檔案中,完整程式碼如下:

pipelines.py

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

# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: http://doc.scrapy.org/en/latest/topics/item-pipeline.html
import codecs
import json

class GzprojectPipeline(object):

    def __init__(self):  
        self.file = codecs.open('guizhou.json', 'w', encoding='utf-8')
        
    def process_item(self, item, spider):
        line = json.dumps(dict(item), ensure_ascii=False) + "\n"  
        self.file.write(line)  
        return item  
        
    def spider_closed(self, spider):  
        self.file.close()  

呼叫codecs.open('guizhou.json', 'w', encoding='utf-8')函式將資料儲存至“guizhou.json”檔案中,最後設定settings.py檔案的優先順序。




七. 設定settings檔案

在該檔案中設定如下程式碼,將貴州農經網爬蟲的優先順序設定為1優先順序範圍從11000,越小優先順序越高;“GZProject.pipelines.GzprojectPipeline”表示要設定的通道。

settings.py

ITEM_PIPELINES = {
    'GZProject.pipelines.GzprojectPipeline': 1
}

最後輸入程式碼“scrapy crawl gznw”執行爬蟲,輸出部分結果如下所示。



同時,在本地建立的“guizhou.json”檔案中儲存資料如下所示,採用鍵值對形式顯示。


如果讀者想儲存為CSV檔案,則執行“scrapy crawl gznw -o gz.csv”,輸出截圖如下所示:


寫到這裡,一個完整的Scrapy爬取貴州農經網的農產品資料已經講完了,後面我也將繼續學習Rule類以及其不同頁面的爬取,甚至包括儲存至資料庫中。更多的爬蟲知識希望讀者下來結合實際需求和專案進行深入學習,並爬取所需的資料集。

(By:Eastmount 2018-02-11 深夜4點 http://blog.csdn.net/eastmount/)


相關文章