Python-Scrapy到Json输出拆分

Python-Scrapy到Json输出拆分,python,json,scrapy,output,Python,Json,Scrapy,Output,我正在学习NLP,为了做到这一点,我正在使用Scrapy抓取一篇亚马逊书评。我已经提取了我想要的字段,并将它们输出为Json文件格式。当该文件作为df加载时,每个字段都记录为一个列表,而不是一行一行的格式。如何拆分此列表,使df为每个项目都有一行,而不是将所有项目条目记录在单独的列表中?代码: import scrapy class ReviewspiderSpider(scrapy.Spider): name = 'reviewspider' allowed_domains

我正在学习NLP,为了做到这一点,我正在使用Scrapy抓取一篇亚马逊书评。我已经提取了我想要的字段,并将它们输出为Json文件格式。当该文件作为df加载时,每个字段都记录为一个列表,而不是一行一行的格式。如何拆分此列表,使df为每个项目都有一行,而不是将所有项目条目记录在单独的列表中?代码:

import scrapy


class ReviewspiderSpider(scrapy.Spider):
    name = 'reviewspider'
    allowed_domains = ['amazon.co.uk']
    start_urls = ['https://www.amazon.com/Gone-Girl-Gillian-Flynn/product-reviews/0307588378/ref=cm_cr_othr_d_paging_btm_1?ie=UTF8&reviewerType=all_reviews&pageNumber=1']

def parse(self, response):
    users = response.xpath('//a[contains(@data-hook, "review-author")]/text()').extract()
    titles = response.xpath('//a[contains(@data-hook, "review-title")]/text()').extract()
    dates = response.xpath('//span[contains(@data-hook, "review-date")]/text()').extract()
    found_helpful = response.xpath('//span[contains(@data-hook, "helpful-vote-statement")]/text()').extract()
    rating = response.xpath('//i[contains(@data-hook, "review-star-rating")]/span[contains(@class, "a-icon-alt")]/text()').extract()
    content = response.xpath('//span[contains(@data-hook, "review-body")]/text()').extract()

    yield {
        'users' : users.extract(),
        'titles' : titles.extract(),
        'dates' : dates.extract(),
        'found_helpful' : found_helpful.extract(),
        'rating' : rating.extract(),
        'content' : content.extract()
    }
样本输出:

users = ['Lauren', 'James'...'John']
dates = ['on September 28, 2017', 'on December 26, 2017'...'on November 17, 2016']
rating = ['5.0 out of 5 stars', '2.0 out of 5 stars'...'5.0 out of 5 stars']
期望输出:

index 1: [users='Lauren', dates='on September 28, 2017', rating='5.0 out of 5 stars']
index 2: [users='James', dates='On December 26, 2017', rating='5.0 out of 5 stars']
...

我知道应该编辑与spider相关的管道来实现这一点,但是我的Python知识有限,无法理解零碎的文档。我也尝试了来自和的解决方案,但是我知道的还不够多,无法用自己的代码整合答案。任何帮助都将不胜感激。

重新阅读您的问题后,我确信这就是您想要的:

def parse(self, response):
    users = response.xpath('//a[contains(@data-hook, "review-author")]/text()').extract()
    titles = response.xpath('//a[contains(@data-hook, "review-title")]/text()').extract()
    dates = response.xpath('//span[contains(@data-hook, "review-date")]/text()').extract()
    found_helpful = response.xpath('//span[contains(@data-hook, "helpful-vote-statement")]/text()').extract()
    rating = response.xpath('//i[contains(@data-hook, "review-star-rating")]/span[contains(@class, "a-icon-alt")]/text()').extract()
    content = response.xpath('//span[contains(@data-hook, "review-body")]/text()').extract()

    for user, title, date, found_helpful, rating, content in zip(users, titles, dates, found_helpful, rating, content):
        yield {
            'user': user,
            'title': title,
            'date': date,
            'found_helpful': found_helpful,
            'rating': rating,
            'content': content
        }

或者类似的东西。这就是我在第一篇评论中试图暗示的。

编辑:我能够通过使用.css方法而不是.xpath来提出解决方案。我用蜘蛛从一家时装零售商那里抓取衬衫清单:

import scrapy
from ..items import ProductItem

class SportsdirectSpider(scrapy.Spider):
    name = 'sportsdirect'
    allowed_domains = ['www.sportsdirect.com']
    start_urls = ['https://www.sportsdirect.com/mens/mens-shirts']

def parse(self, response):
    products = response.css('.s-productthumbbox')
    for p in products:
        brand = p.css('.productdescriptionbrand::text').extract_first()
        name = p.css('.productdescriptionname::text').extract_first()
        price = p.css('.curprice::text').extract_first()
        item = ProductItem()
        item['brand'] = brand
        item['name'] = name
        item['price'] = price
        yield item
相关items.py脚本:

import scrapy

class ProductItem(scrapy.Item):
    name = scrapy.Field()
    brand = scrapy.Field()
    name = scrapy.Field()
    price = scrapy.Field()
创建json行文件(在Anaconda提示符中):

用于将创建的.jl文件转换为数据帧的代码:

import json
import pandas as pd
contents = open('products3.jl', "r").read() 
data = [json.loads(str(item)) for item in contents.strip().split('\n')]
df2 = pd.DataFrame(data)
最终输出:

        brand        name                        price
0   Pierre Cardin    Short Sleeve Shirt Mens     £6.50 
1   Pierre Cardin    Short Sleeve Shirt Mens     £7.00 
...

如果我理解正确的话,这实际上不是一个专门针对Scrapy的问题,而是一个理解数据结构以及如何操作它们的问题。您拥有的是一个列表集合,每个列表中的一项对应于单个记录中的一个属性。相反,您希望输出一个记录列表。这两种数据结构完全可以互换。例如,请参见,问题在于列表不是作为元组返回的,因此需要指定分隔符。但是,这不能使用,因为分隔符是“,在多个列中重复多次(因此不能用作分隔符)。哦,你不应该试图解析scrapy的默认输出。如果你担心分隔符,那么你就错了。事实上,你可以像中一样实现一个管道来自定义如何输出每个项。但是让我们退一步:当你编写“所需输出”时“你的意思是你真的希望你的输出格式是这样的吗?您的数据的用途(通常)是什么以及如何使用?(顺便说一句,您发布的代码已损坏。
def parse
应该缩进,并且您有重复的
.extract()
调用。)感谢您的帮助。不幸的是,您的代码给了我一个错误:“SyntaxError:”yield“outside function”。但是,通过使用.css方法而不是.xpath(我将作为答案发布),我已经成功地实现了我想要的。我的代码没有给你这个错误。您没有正确地输入它——缩进在Python中很重要。我不知道这如何解决您的问题,因为它不适用于Amazon评论。使用
.xpath()
方法与使用
.css()
方法在这里并没有什么区别——它们是两种不同的语法,但在许多情况下是等效的,用于从页面提取元素。问题是,在提取元素后,您希望返回数据结构中的元素,该数据结构与您希望通过
parse()
方法返回的每个项目的数据结构相匹配(通过
yield
),字典中的每个值都是列表的单个字典。相反,您希望生成多个字典,这些列表中的每个项目对应一个字典。这就是我的答案,这也是这个答案的本质,在这两种情况下都是通过循环。
        brand        name                        price
0   Pierre Cardin    Short Sleeve Shirt Mens     £6.50 
1   Pierre Cardin    Short Sleeve Shirt Mens     £7.00 
...