鍍金池/ 問答/人工智能  Python/ scrapy 不同item寫入pipeline出錯。

scrapy 不同item寫入pipeline出錯。

想要達成的功能大致如下:

圖片描述

沒有報錯,書評的一級信息全部寫入,但是二級書評沒有寫入,代碼如下:

item代碼如下

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

import scrapy

class YswItem(scrapy.Item):

    #發(fā)帖時間
    time = scrapy.Field()

    #獲得贊同數量
    agree = scrapy.Field()

    #二級評論數量
    sec_num = scrapy.Field()

    #一級評論內容
    fir_text = scrapy.Field()

class YswItems(scrapy.Item):

    #發(fā)帖時間
    time = scrapy.Field()

    #獲得贊同數量
    agree = scrapy.Field()

    #二級評論數量
    sec_num = scrapy.Field()

    #一級評論內容
    fir_text = scrapy.Field()

    #二級評論內容
    sec_text = scrapy.Field()

————————————————————————————
spider.shuping類代碼如下:

# -*- coding: utf-8 -*-
import scrapy
from scrapy.http import Request
from ysw.items import YswItem
from ysw.spiders.shuping_two import Shuping_twoSpiser

class ShupingSpider(scrapy.Spider):
    name = 'shuping'
    #allowed_domains = ['www.yousuu.com']
    start_urls = ['http://www.yousuu.com/book/124600']

    #此方法解析評論第一頁的一級書評
    def parse(self, response):

        sp_two = Shuping_twoSpiser()
        #遍歷每個一級書評,獲得信息
        for r in response.xpath('//*[@id="content"]/div'):
            item = YswItem()

            #發(fā)帖時間
            item['time'] = r.xpath('string(./div/div/div[1]/div/span[2])').extract_first().strip()

            #獲得贊同數
            agree = r.xpath('string(./div/div/div[2]/button[1]/span)').extract_first().strip()
            if agree:
                item['agree'] = agree
            else:
                item['agree'] = '0'

            #一級書評內容
            item['fir_text'] = r.xpath('string(./div/div/p)').extract_first().replace('\r\n', '').replace(' ', '')

            #二級評論數:
            sec_num = r.xpath('string(./div/div/div[2]/button[2]/span)').extract_first().strip()
            if sec_num:
                item['sec_num'] = sec_num

                #獲取二級評論url的組成部分cid
                cid = r.xpath('./@cid').extract_first().strip()

                #補全二級評論第一頁的url
                sec_text_url = "http://www.yousuu.com/ajax/getonecomment?render=true&cid={}".format(cid)

                #將每一個一級書評下的所有二級書評的獲取都交給sp_two.parse
                sec_text_list = []
                yield Request(sec_text_url, meta={'sec_text_list':sec_text_list, 'item':item}, callback=sp_two.parse)
            else:
                item['sec_num'] = '0'

            yield item
        return print('一級書評第一頁!')

————————————————————————
spider.shuping_two類代碼如下:

# -*- coding: utf-8 -*-
import scrapy
from scrapy.http import Request
from ysw.items import YswItems
import re
import json
from scrapy.selector import Selector

#解析二級書評
class Shuping_twoSpiser(scrapy.Spider):

    name = 'shuping_two'
    #allowed_domains = ['www.yousuu.com']
    #start_urls = []
    
    def parse(self, response):
        items = YswItems()

        #json格式轉為python結構數據
        jsobj = json.loads(response.body)

        #從字典中提取html的值,也就是二級評論的html格式文本
        html = jsobj['html']

        #獲得二級書評第一頁的所有二級書評內容,放在列表result中,迭代這個parse方法時,依次是第2,3,頁等等
        result = Selector(text=html).xpath('//p/text()').extract()

        #獲得上一個Request傳遞過來的參數, 第一次是一個空列表
        sec_text_list = response.meta['sec_text_list']
        
        #獲得shuping.parse()傳來的item
        item = response.meta['item']
        
        '''每一頁的二級評論內容放在一個列表result中,這個列表又放在列表sec_text_list中
        二級書評每一頁的第一個書評都是它的一級書評內容,所以從每一頁新的二級書評從第二個算起'''
        sec_text_list.append(result[1:])

        #判斷二級評論是否還有下一頁
        nextpage = Selector(text=html).xpath('//a[text()="更多回復"]/@onclick').extract_first()
        if nextpage:
            #獲得下一頁的cid
            cid = re.search(r"(.*?)'(.*?)',(.*)", nextpage).group(2)
            #獲取下一頁的t
            t = re.search("(.*),(.*?)\)", nextpage).group(2)
            #組裝二級評論下一頁的url
            next_page_url = "http://www.yousuu.com/ajax/getcommentreply?cid={}&t={}&render=true".format(cid, t)
            #print('next_page_url')
            #迭代這個方法繼續(xù)獲得下一頁的二級評論內容
            yield Request(next_page_url, meta={'sec_text_list':sec_text_list, 'item':item}, callback=self.parse)
        else:

            items['sec_text'] = sec_text_list
            items['time'] = item['time']
            items['agree'] = item['agree']
            items['sec_num'] = item['sec_num']
            items['fir_text'] = item['fir_text']

            print('已獲取此一級書評的全部二級書評!')

            yield items

——————————————————————————
pipeline代碼如下:

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

class YswPipeline(object):
    def process_item(self, item, spider):

        base_dir = os.getcwd()
        file_name = base_dir + '/SP.txt'

        with open(file_name, 'a', encoding='utf-8') as f:
            if spider.name=='shuping':
                f.write('時間:' + item['time'] + '\n'
                    '贊同數:' + item['agree'] + '\n'
                    '二級評論數量:' + item['sec_num'] + '\n'                         
                    '一級評論內容:' + item['fir_text'] + '\n\n'
                    )
            elif spider.name=='shuping_two':
                f.write('時間:' + item['time'] + '\n'
                    '贊同數:' + item['agree'] + '\n'
                    '二級評論數量:' + item['sec_num'] + '\n'                         
                    '一級評論內容:' + item['fir_text'] + '\n'
                    '二級評論內容:' + '\n'.join(item['sec_text']) + '\n\n'
                    )
        return item

寫入結果如下:

圖片描述

請知道怎么處理的前輩指點迷津,卡在這一天了,真的很虐心。感謝!感謝!

回答
編輯回答
赱丅呿

為什么要弄兩個spider呢?你完完全全可以在第一個spider下再寫一個parse_shuping_two啊.


對你的代碼稍作了修改,可以達到你的要求(別忘了在settings.py中加上ITEM_PIPELINES = {'ysw.pipelines.YswPipeline': 300}以激活pipeline):
spiders/shuping.py

# -*- coding: utf-8 -*-
import scrapy
from scrapy.http import Request
from ysw.items import YswItem, YswItems
import json
from scrapy import Selector
import re


class ShupingSpider(scrapy.Spider):
    name = 'shuping'
    #allowed_domains = ['www.yousuu.com']
    start_urls = ['http://www.yousuu.com/book/124600']

    #此方法解析評論第一頁的一級書評
    def parse(self, response):

        #遍歷每個一級書評,獲得信息
        for r in response.xpath('//*[@id="content"]/div'):
            item = YswItem()

            #發(fā)帖時間
            item['time'] = r.xpath('string(./div/div/div[1]/div/span[2])').extract_first().strip()

            #獲得贊同數
            agree = r.xpath('string(./div/div/div[2]/button[1]/span)').extract_first().strip()
            if agree:
                item['agree'] = agree
            else:
                item['agree'] = '0'

            #一級書評內容
            item['fir_text'] = r.xpath('string(./div/div/p)').extract_first().replace('\r\n', '').replace(' ', '')

            #二級評論數:
            sec_num = r.xpath('string(./div/div/div[2]/button[2]/span)').extract_first().strip()
            if sec_num:
                item['sec_num'] = sec_num

                #獲取二級評論url的組成部分cid
                cid = r.xpath('./@cid').extract_first().strip()

                #補全二級評論第一頁的url
                sec_text_url = "http://www.yousuu.com/ajax/getonecomment?render=true&cid={}".format(cid)

                #將每一個一級書評下的所有二級書評的獲取都交給sp_two.parse
                sec_text_list = []
                yield Request(sec_text_url, meta={'sec_text_list':sec_text_list, 'item':item}, callback=self.parse_shuping_two)
            else:
                item['sec_num'] = '0'
                yield item
        return print('一級書評第一頁!')

    def parse_shuping_two(self, response):
        items = YswItems()

        # json格式轉為python結構數據
        jsobj = json.loads(response.body)

        # 從字典中提取html的值,也就是二級評論的html格式文本
        html = jsobj['html']

        # 獲得二級書評第一頁的所有二級書評內容,放在列表result中,迭代這個parse方法時,依次是第2,3,頁等等
        result = Selector(text=html).xpath('//p/text()').extract()

        # 獲得上一個Request傳遞過來的參數, 第一次是一個空列表
        sec_text_list = response.meta['sec_text_list']

        # 獲得shuping.parse()傳來的item
        item = response.meta['item']

        '''每一頁的二級評論內容放在一個列表result中,這個列表又放在列表sec_text_list中
        二級書評每一頁的第一個書評都是它的一級書評內容,所以從每一頁新的二級書評從第二個算起'''
        sec_text_list.extend(result[1:])

        # 判斷二級評論是否還有下一頁
        nextpage = Selector(text=html).xpath('//a[text()="更多回復"]/@onclick').extract_first()
        if nextpage:
            # 獲得下一頁的cid
            cid = re.search(r"(.*?)'(.*?)',(.*)", nextpage).group(2)
            # 獲取下一頁的t
            t = re.search("(.*),(.*?)\)", nextpage).group(2)
            # 組裝二級評論下一頁的url
            next_page_url = "http://www.yousuu.com/ajax/getcommentreply?cid={}&t={}&render=true".format(cid, t)
            # print('next_page_url')
            # 迭代這個方法繼續(xù)獲得下一頁的二級評論內容
            yield Request(next_page_url, meta={'sec_text_list': sec_text_list, 'item': item}, callback=self.parse_shuping_two)
        else:

            items['sec_text'] = sec_text_list
            items['time'] = item['time']
            items['agree'] = item['agree']
            items['sec_num'] = item['sec_num']
            items['fir_text'] = item['fir_text']

            print('已獲取此一級書評的全部二級書評!')

            yield items

pipelines.py

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

class YswPipeline(object):
    def process_item(self, item, spider):

        base_dir = os.getcwd()
        file_name = base_dir + '/SP.txt'

        with open(file_name, 'a', encoding='utf-8') as f:
            if item['sec_num'] == '0':
                f.write('時間:' + item['time'] + '\n'
                    '贊同數:' + item['agree'] + '\n'
                    '二級評論數量:' + item['sec_num'] + '\n'
                    '一級評論內容:' + item['fir_text'] + '\n\n'
                    )
            else:
                f.write('時間:' + item['time'] + '\n'
                    '贊同數:' + item['agree'] + '\n'
                    '二級評論數量:' + item['sec_num'] + '\n'
                    '一級評論內容:' + item['fir_text'] + '\n'
                    '二級評論內容:' + '\n'.join(item['sec_text']) + '\n\n'
                    )
        return item
2017年12月29日 19:51