1. 程式人生 > >Python Scrapy 爬蟲框架例項(一)

Python Scrapy 爬蟲框架例項(一)

之前有介紹 scrapy 的相關知識,但是沒有介紹相關例項,在這裡做個小例,供大家參考學習。

注:後續不強調python 版本,預設即為python3.x。

爬取目標

這裡簡單找一個圖片網站,獲取圖片的先關資訊。

該網站網址: http://www.58pic.com/c/

建立專案

終端命令列執行以下命令

scrapy  startproject AdilCrawler

 

命令執行後,會生成如下結構的專案。

 

執行結果如下

 

如上圖提示,cd 到專案下,可以執行 scrapy genspider example example.com 命令,建立 名為example,域名為example.com 的 爬蟲檔案。

 

編寫items.py

這裡先簡單抓取圖片的作者名稱、圖片主題等資訊。

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

# Define here the models for your scraped items
#
# See documentation in:
# https://doc.scrapy.org/en/latest/topics/items.html

import scrapy

class AdilcrawlerItem(scrapy.Item):
    # define the fields for your item here like:
# name = scrapy.Field() author = scrapy.Field() # 作者 theme = scrapy.Field() # 主題

 

編寫spider檔案 

進入AdilCrawler目錄,使用命令建立一個基礎爬蟲類:

 scrapy genspider  thousandPic www.58pic.com

#  thousandPic為爬蟲名,www.58pic.com為爬蟲作用範圍

 

執行命令後會在spiders資料夾中建立一個thousandPic.py的檔案,現在開始對其編寫:

 

# -*- coding: utf-8 -*-
import scrapy
# 爬蟲 小試

class ThousandpicSpider(scrapy.Spider):
    name = 'thousandPic'
    allowed_domains = ['www.58pic.com']
    start_urls = ['http://www.58pic.com/c/']

    def parse(self, response):

        '''
        檢視頁面元素
         /html/body/div[4]/div[3]/div/a/p[2]/span/span[2]/text()
          因為頁面中 有多張圖,而圖是以 /html/body/div[4]/div[3]/div[i]  其中i  為變數 作為區分的 ,所以為了獲取當前頁面所有的圖
          這裡 不寫 i 程式會遍歷 該 路徑下的所有 圖片。
        '''# author 作者
        # theme  主題
        author = response.xpath('/html/body/div[4]/div[3]/div/a/p[2]/span/span[2]/text()').extract()
        theme = response.xpath('/html/body/div[4]/div[3]/div/a/p[1]/span[1]/text()').extract()
        # 使用 爬蟲的log 方法在控制檯輸出爬取的內容。
        self.log(author)
        self.log(theme)
        # 使用遍歷的方式 打印出 爬取的內容,因為當前一頁有20張圖片。
        for i in range(1, 21):
            print(i,' **** ',theme[i - 1], ': ',author[i - 1] )

 

 執行命令,檢視列印結果

scrapy crawl thousandPic

 

結果如下,其中DEBUG為 log 輸出。

 

程式碼優化

引入 item AdilcrawlerItem

# -*- coding: utf-8 -*-
import scrapy
# 這裡使用 import 或是 下面from 的方式都行,關鍵要看 當前專案在pycharm的開啟方式,是否是作為一個專案開啟的,建議使用這一種方式。
import AdilCrawler.items as items

# 使用from 這種方式,AdilCrawler 需要作為一個專案開啟。
# from AdilCrawler.items import AdilcrawlerItem


class ThousandpicSpider(scrapy.Spider):
    name = 'thousandPic'
    allowed_domains = ['www.58pic.com']
    start_urls = ['http://www.58pic.com/c/']

    def parse(self, response):

        '''
        檢視頁面元素
         /html/body/div[4]/div[3]/div/a/p[2]/span/span[2]/text()
          因為頁面中 有多張圖,而圖是以 /html/body/div[4]/div[3]/div[i]  其中i  為變數 作為區分的 ,所以為了獲取當前頁面所有的圖
          這裡 不寫 i 程式會遍歷 該 路徑下的所有 圖片。
        '''

        item = items.AdilcrawlerItem()

        # author 作者
        # theme  主題

        author = response.xpath('/html/body/div[4]/div[3]/div/a/p[2]/span/span[2]/text()').extract()

        theme = response.xpath('/html/body/div[4]/div[3]/div/a/p[1]/span[1]/text()').extract()

        item['author'] = author
        item['theme']  = theme

        return item
  再次運營爬蟲,執行結果如下

 

儲存結果到檔案

執行命令如下
scrapy crawl thousandPic -o items.json

會生成如圖的檔案

 

再次優化,使用 ItemLoader 功能類

使用itemLoader ,以取代雜亂的extract()和xpath()。

程式碼如下: 

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

# 匯入 ItemLoader 功能類
from scrapy.loader import ItemLoader

# optimize  優化
# 爬蟲專案優化

class ThousandpicoptimizeSpider(scrapy.Spider):
    name = 'thousandPicOptimize'
    allowed_domains = ['www.58pic.com']
    start_urls = ['http://www.58pic.com/c/']

    def parse(self, response):

        '''
        檢視頁面元素
         /html/body/div[4]/div[3]/div/a/p[2]/span/span[2]/text()
          因為頁面中 有多張圖,而圖是以 /html/body/div[4]/div[3]/div[i]  其中i  為變數 作為區分的 ,所以為了獲取當前頁面所有的圖
          這裡 不寫 i 程式會遍歷 該 路徑下的所有 圖片。
        '''

        # 使用功能類 itemLoader,以取代 看起來雜亂的 extract() 和 xpath() ,優化如下
        i = ItemLoader(item = AdilcrawlerItem(),response = response )
        # author 作者
        # theme  主題
        i.add_xpath('author','/html/body/div[4]/div[3]/div/a/p[2]/span/span[2]/text()')
        i.add_xpath('theme','/html/body/div[4]/div[3]/div/a/p[1]/span[1]/text()')
        return i.load_item()

  

編寫pipelines檔案 

 預設pipelines.py 檔案

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

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


class Adilcrawler1Pipeline(object):
    def process_item(self, item, spider):
        return item

 

優化後代碼如下

 

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

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

import json

class AdilcrawlerPipeline(object):
    '''
        儲存item資料
    '''

    def __init__(self):
        self.filename = open('thousandPic.json','w')

    def process_item(self, item, spider):

        #  ensure_ascii=False 可以解決 json 檔案中 亂碼的問題。
        text = json.dumps(dict(item), ensure_ascii=False) + ',\n'   #  這裡是一個字典一個字典儲存的,後面加個 ',\n' 以便分隔和換行。
        self.filename.write(text)

        return item

    def close_spider(self,spider):
        self.filename.close()

 

settings檔案設定

修改settings.py配置檔案

找到pipelines 配置進行修改

# Configure item pipelines
# See https://doc.scrapy.org/en/latest/topics/item-pipeline.html
# ITEM_PIPELINES = {
#    'AdilCrawler.pipelines.AdilcrawlerPipeline': 300,
# }

# 啟動pipeline 必須將其加入到“ITEM_PIPLINES”的配置中
# 其中根目錄是tutorial,pipelines是我的pipeline檔名,TutorialPipeline是類名
ITEM_PIPELINES = {
    'AdilCrawler.pipelines.AdilcrawlerPipeline': 300,
}

# 加入後,相當於開啟pipeline,此時在執行爬蟲,會執行對應的pipelines下的類,並執行該類相關的方法,比如這裡上面的儲存資料功能。

 

執行命令

scrapy crawl thousandPicOptimize

執行後生成如下圖檔案及儲存的資料

 

 

使用CrawlSpider類進行翻頁抓取

使用crawl 模板建立一個 CrawlSpider 
執行命令如下
scrapy genspider -t crawl thousandPicPaging www.58pic.com

items.py 檔案不變,檢視 爬蟲 thousandPicPaging.py 檔案

# -*- coding: utf-8 -*-
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule


class ThousandpicpagingSpider(CrawlSpider):
    name = 'thousandPicPaging'
    allowed_domains = ['www.58pic.com']
    start_urls = ['http://www.58pic.com/']

    rules = (
        Rule(LinkExtractor(allow=r'Items/'), callback='parse_item', follow=True),
    )

    def parse_item(self, response):
        i = {}
        #i['domain_id'] = response.xpath('//input[@id="sid"]/@value').extract()
        #i['name'] = response.xpath('//div[@id="name"]').extract()
        #i['description'] = response.xpath('//div[@id="description"]').extract()
        return i

 

修改後如下

# -*- coding: utf-8 -*-
import scrapy
# 匯入連結規則匹配類,用來提取符合規則的連線
from scrapy.linkextractors import LinkExtractor
# 匯入CrawlSpider類和Rule
from scrapy.spiders import CrawlSpider, Rule
import AdilCrawler.items as items

class ThousandpicpagingSpider(CrawlSpider):
    name = 'thousandPicPaging'
    allowed_domains = ['www.58pic.com']
    # 修改起始頁地址
    start_urls = ['http://www.58pic.com/c/']

    # Response裡連結的提取規則,返回的符合匹配規則的連結匹配物件的列表
    # http://www.58pic.com/c/1-0-0-03.html  根據翻頁連線地址,找到 相應的 正則表示式   1-0-0-03  -> \S-\S-\S-\S\S  而且 這裡使用 allow
    # 不能使用 restrict_xpaths ,使用 他的話,正則將失效
    page_link = LinkExtractor(allow='http://www.58pic.com/c/\S-\S-\S-\S\S.html', allow_domains='www.58pic.com')

    rules = (
        # 獲取這個列表裡的連結,依次傳送請求,並且繼續跟進,呼叫指定回撥函式處理
        Rule(page_link, callback='parse_item', follow=True),  # 注意這裡的 ',' 要不會報錯
    )


    # 加上這個 方法是為了 解決 parse_item() 不能抓取第一頁資料的問題 parse_start_url 是 CrawlSpider() 類下的方法,這裡重寫一下即可
    def parse_start_url(self, response):
        i = items.AdilcrawlerItem()
        author = response.xpath('/html/body/div[4]/div[3]/div/a/p[2]/span/span[2]/text()').extract()
        theme = response.xpath('/html/body/div[4]/div[3]/div/a/p[1]/span[1]/text()').extract()
        i['author'] = author
        i['theme'] = theme

        yield i

    # 指定的回撥函式
    def parse_item(self, response):
        i = items.AdilcrawlerItem()
        author = response.xpath('/html/body/div[4]/div[3]/div/a/p[2]/span/span[2]/text()').extract()
        theme = response.xpath('/html/body/div[4]/div[3]/div/a/p[1]/span[1]/text()').extract()
        i['author'] = author
        i['theme'] = theme
        yield i

 

再次執行 

scrapy crawl thousandPicPaging

 

檢視執行結果,可以看到是有4頁的內容

 

再次優化引入 ItemLoader  類

# -*- coding: utf-8 -*-
import scrapy
# 匯入連結規則匹配類,用來提取符合規則的連線
from scrapy.linkextractors import LinkExtractor
# 匯入CrawlSpider類和Rule
from scrapy.loader import ItemLoader
from scrapy.spiders import CrawlSpider, Rule
import AdilCrawler.items as items

class ThousandpicpagingopSpider(CrawlSpider):
    name = 'thousandPicPagingOp'
    allowed_domains = ['www.58pic.com']
    # 修改起始頁地址
    start_urls = ['http://www.58pic.com/c/']

    # Response裡連結的提取規則,返回的符合匹配規則的連結匹配物件的列表
    # http://www.58pic.com/c/1-0-0-03.html  根據翻頁連線地址,找到 相應的 正則表示式   1-0-0-03  -> \S-\S-\S-\S\S  而且 這裡使用 allow
    # 不能使用 restrict_xpaths ,使用 他的話,正則將失效
    page_link = LinkExtractor(allow='http://www.58pic.com/c/\S-\S-\S-\S\S.html', allow_domains='www.58pic.com')

    rules = (
        # 獲取這個列表裡的連結,依次傳送請求,並且繼續跟進,呼叫指定回撥函式處理
        Rule(page_link, callback='parse_item', follow=True),  # 注意這裡的 ',' 要不會報錯
    )

    # 加上這個 方法是為了 解決 parse_item() 不能抓取第一頁資料的問題 parse_start_url 是 CrawlSpider() 類下的方法,這裡重寫一下即可
    def parse_start_url(self, response):

        i = ItemLoader(item = items.AdilcrawlerItem(),response = response )
        i.add_xpath('author','/html/body/div[4]/div[3]/div/a/p[2]/span/span[2]/text()')
        i.add_xpath('theme','/html/body/div[4]/div[3]/div/a/p[1]/span[1]/text()')

        yield  i.load_item()

    # 指定的回撥函式
    def parse_item(self, response):
        i = ItemLoader(item = items.AdilcrawlerItem(),response = response )
        i.add_xpath('author','/html/body/div[4]/div[3]/div/a/p[2]/span/span[2]/text()')
        i.add_xpath('theme','/html/body/div[4]/div[3]/div/a/p[1]/span[1]/text()')

        yield  i.load_item()

 

執行結果是一樣的。

最後插播一條 線上正則表示式測試 工具的廣告,地址: http://tool.oschina.net/regex/

應用如下

 

 

 

至此,簡單完成了一個網站的簡單資訊的爬取。後面還會有其他內容的介紹~

如果你要覺得對你有用的話,請不要吝惜你打賞,這將是我無盡的動力,謝謝!