scrapy json输出一行上的所有项目

时间:2018-02-19 00:33:49

标签: python json web-scraping scrapy

我正在尝试让我的输出看起来像json格式中的以下内容。

{"loser": "De Schepper K." ,"winner": "Herbert P.", "url":
"https://www.sofascore.com/tennis/2018-02-07"}

但我现在正在为每个失败者项目和获胜者项目获取单独的行。我希望赢家和输家都与网址保持一致。

{"loser": "De Schepper K.", "url": 
"https://www.sofascore.com/tennis/2018-02-07"}
{"winner": "Herbert P.", "url": 
"https://www.sofascore.com/tennis/2018-02-07"}
{"loser": "Sugita Y.", "url": 
 "https://www.sofascore.com/tennis/2018-02-07"}

我不确定这是我的选择器是否会导致这种行为,但我想知道如何自定义管道,以便失败者,赢家和日期都在同一个json线上

我之前从未提取过json格式,所以对我来说这是新手。 如何使用自定义管道指定每行上的json键和值?

我也尝试使用csv item exporter来做这件事并且也有奇怪的行为。 REF Scrapy output is showing empty rows per column

这是我的spider.py

import scrapy
from scrapy_splash import SplashRequest
from scrapejs.items import SofascoreItemLoader
from scrapy import Spider

import json
from scrapy.http import Request, FormRequest

    class MySpider(scrapy.Spider):
    name = "jsscraper"

    start_urls = ["https://www.sofascore.com/tennis/2018-02-07"]


    def start_requests(self):
        for url in self.start_urls:
            yield SplashRequest(url=url,
                            callback=self.parse,
                            endpoint='render.html',
                            args={'wait': 1.5})



    def parse(self, response):
            for row in response.css('.event-team'):
                    il = SofascoreItemLoader(selector=row)
                    il.add_css('winner' , '.event-team:nth-
                      child(2)::text')
                    il.add_css('loser' , '.event-team:nth-
                    child(1)::text')
                    il.add_value('url', response.url)

                    yield il.load_item()

items.py

import scrapy

from scrapy.loader import ItemLoader
from scrapy.loader.processors import TakeFirst, MapCompose
from operator import methodcaller
from scrapy import Spider, Request, Selector

class SofascoreItem(scrapy.Item):
    loser = scrapy.Field()
    winner = scrapy.Field()
    url = scrapy.Field()



class SofascoreItemLoader(ItemLoader):
    default_item_class = SofascoreItem
    default_input_processor = MapCompose(methodcaller('strip'))
    default_output_processor = TakeFirst()

pipeline.py

import json
import codecs
from collections import OrderedDict

class JsonPipeline(object):

    def __init__(self):
        self.file = codecs.open('data_utf8.json' , 'w' , 
        encoding='utf-8')

    def process_item(self , item , spider):
        line = json.dumps(OrderedDict(item) , ensure_ascii=False , 
        sort_keys=False) + "\n"
        self.file.write(line)
        return item

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

2 个答案:

答案 0 :(得分:1)

所以我回顾了你的问题,现在我找到了问题所在:

for row in response.css('.event-team'):

使用上面的行,您将获得许多选择器(或SelectorList)。但是,在每个选择器或行中,您只能获得一个字段:赢家或输家。你无法得到它们。 enter image description here

这就是为什么输出中会有空行的原因。

解决方案:尝试以下行:

for row in response.css('div[class=“cell__section--main s-tennisCell curb-width”]')

答案 1 :(得分:1)

这里的问题是您要循环.event-team个元素 其中一个元素只能是赢家或输家,所以每个元素都有一个项目。

你应该做的是循环包含两者的元素(.list-event似乎是一个好的候选者),并从中提取胜负者。

这样,每个事件都有一个循环,因此每个事件有一个项目。