1. 程式人生 > >使用Item Loaders對Item資料進行提取和解析(整理)

使用Item Loaders對Item資料進行提取和解析(整理)

1.當建立item物件(item=JobboleItem())的時候, 會去Item.py檔案中初始化對應的input/output_processor處理器

2.當item中的處理器初始化完成, 回到bole.py爬蟲檔案中, 建立item_loader物件

3.item_loader物件建立完成, 開始通過add_xpath/add_css/add_value收集資料

4.每收集一個數據, 就會將該資料傳遞給對應欄位的inout_processor繫結的函式進行資料處理, 資料處理完成, 會暫時儲存在ItemLoader中

5迴圈第四步, 將每一個欄位的資料提取並交給input_processor, 直到所有資料提取完畢, 所有資料都會被儲存在ItemLoader中

6.呼叫load_item()函式, 給item物件進行賦值

bole.py:

from jobbole.items import JobboleItem
from scrapy.loader import ItemLoader

item_loader = ItemLoader(item=JobboleItem(), response=response)
        item_loader.add_xpath('title', '//div[@class="entry-header"]/h1/text()')
        item_loader.add_xpath('date_time', '//p[@class="entry-meta-hide-on-mobile"]/text()')
        item_loader.add_xpath('tags', '//p[@class="entry-meta-hide-on-mobile"]/a/text()')
        item_loader.add_xpath('content', '//div[@class="entry"]//text()')
        item_loader.add_xpath('zan_num', '//div[@class="post-adds"]/span[contains(@class, "vote-post-up")]//text()')
        item_loader.add_xpath('keep_num', '//div[@class="post-adds"]/span[contains(@class, "bookmark-btn")]/text()')
        item_loader.add_xpath('comment_num', '//div[@class="post-adds"]/a/span/text()')
        item_loader.add_value('img_src', [response.meta['img_src']])

        item = item_loader.load_item()
        yield item

items.py:

import scrapy, re
from datetime import datetime
from scrapy.contrib.loader.processor import Join, MapCompose, TakeFirst


# 函式中的引數value值,是add_xpath/add_css/add_value傳過來的列表資料中的每一個元素。
# def input_test_title(value):
#     return value + '===='
#
# def output_test_title(value):
#     return '---' + value
#
# def result(value):
#     # 這裡面join拼接的大列表裡的一個元素
#     return ''.join(value)


def convert_datetime(value):
    # 將字串型別轉化成datetime型別
    value = value.replace('·', '').strip()
    try:
        # strptime(時間字串,轉化後的格式): 函式返回值是datetime型別的物件
        date_time = datetime.strptime(value, '%Y/%m/%d')
    except:
        # 如果轉化失敗,將當前時間作為預設值。
        date_time = datetime.now()

    return date_time

def convert_tags(value):
    # ['自由職業', '1 評論', '職業']
    # 過濾 "評論"
    if "評論" in value:
        return ""
    return value

def zan_number(value):
    if value.strip() != "":
        pattern = re.compile(r'\d+')
        num = re.findall(pattern, value)
        if num:
            num = int(num[0])
        else:
            num = 0
        return num

def get_number(value):
    # 提取評論、點贊數
    pattern = re.compile(r'\d+')
    num = re.findall(pattern, value)
    if num:
        num = int(num[0])
    else:
        num = 0
    return num

def process_image(value):
    # 拼接圖片地址
    return value

class JobboleItem(scrapy.Item):
    title = scrapy.Field(
        # MapCompose對映類,可以將ItemLoader傳遞過來的列表中的元素,依次作用到test_title函式上,類似於map()函式。
        # input_processor=MapCompose(input_test_title),
        # Join(): 對列表進行合併,add_xpath/add_css/add_value傳過來的列表資料。
        # output_processor=TakeFirst()
    )
    date_time = scrapy.Field(
        input_processor=MapCompose(convert_datetime),
        # TakeFirst(): 獲取列表中的首個元素
        # output_processor=TakeFirst()
    )
    tags = scrapy.Field(
        input_processor=MapCompose(convert_tags),
        # 覆蓋預設的default_output_processor = TakeFirst()
        output_processor=Join()
    )
    content = scrapy.Field(
        output_processor=Join()
    )
    zan_num = scrapy.Field(
        # ['', '1', ' 贊']
        input_processor=MapCompose(zan_number),
        # output_processor=TakeFirst()
    )
    keep_num = scrapy.Field(
        input_processor=MapCompose(get_number),
        # output_processor=TakeFirst()
    )
    comment_num = scrapy.Field(
        input_processor=MapCompose(get_number),
        # output_processor=TakeFirst()
    )
    # 圖片的源地址
    img_src = scrapy.Field()
    # 圖片在本地的下載路徑, 該欄位只有在圖片下載完成以後,才能進行賦值。
    img_path = scrapy.Field()

實現自定義的圖片修改:

from scrapy.contrib.loader import ItemLoader
class CustomItemloader(ItemLoader):
    """
    實現自定義的ItemLoader,可以指定預設的output_processor的值。可以避免在每一個欄位中,設定重複的值。
    """
    default_output_processor = TakeFirst()