【问题标题】:scrapy output item as 1 list element per rowscrapy 输出项目为每行 1 个列表元素
【发布时间】:2019-09-07 04:59:59
【问题描述】:

scrapy 新手,在过去一周或更长时间里到处寻找解决我的问题的方法。我正在尝试在http://ufcstats.com/event-details/6420efac0578988b 处抓取 ufc 1 的表格数据。

我的蜘蛛工作正常,它会将每个项目作为字符串列表返回。例如: '赢家':['罗伊斯格雷西', '杰森德卢西亚', '罗伊斯格雷西', “杰拉德·戈尔多”, '肯三叶草', '罗伊斯格雷西', '凯文罗西尔', '杰拉德·戈尔多']} 当我输出到 csv 时,事件赢家/输家/其他统计信息仅作为 1 行中的字符串列表输出。我想在它自己的行中输出每个项目元素。我已经能够在 pandas 中解决这个问题,但感觉工作量不必要,我怀疑它能否很好地扩展。

希望能够像在表格中一样输出到 csv。不知道这是否应该在蜘蛛本身、项目/项目加载器或管道中完成。

似乎是一个常见问题,但一直无法找到一个简单的解决方案

尝试使用我的标准 itemloader、item 输入处理器和/或输出处理器以及我在 SO 的各种示例中可以找到但未能实现所需输出的所有其他内容在蜘蛛代码中迭代 for 循环。虽然能够解决其他先前的问题。非常卡住,这里的任何帮助将不胜感激

#items.py
import scrapy
from scrapy.loader.processors import Identity, TakeFirst, Compose, 
MapCompose, Join

def compact(s):
    return s if s else None

class StatsItem(scrapy.Item):
# define the fields for your item here like:
   event_name = scrapy.Field(input_processor=MapCompose(str.strip, compact), )
   event_date = scrapy.Field(input_processor=MapCompose(str.strip, compact), )
   event_loc  = scrapy.Field(input_processor=MapCompose(str.strip, compact), )
   attendance = scrapy.Field(input_processor=MapCompose(str.strip, compact), )
   f_info = scrapy.Field(input_processor=MapCompose(str.strip, compact,),)
   winner = scrapy.Field(input_processor=MapCompose(str.strip),)
   loser = scrapy.Field(input_processor=MapCompose(str.strip),) 

#spider code
import scrapy
from ..items import StatsItem
from scrapy.loader import ItemLoader
#from scrapy.loader.processors import Join, MapCompose, TakeFirst

class StatsSpider(scrapy.Spider):
name = 'stats'
allowed_domains = ['fcstats...']
start_urls = ['http://fcstats.../']

custom_settings = {
    # specifies exported fields and order
    'FEED_EXPORT_FIELDS': 
    ['event_name','event_date','event_loc','attendance', 
'winner',#'w_str', 'w_td', 'w_sub', 'w_pass', 'w_wclass', 'w_method', 'w_mthdtl', 'w_round', 'w_time', 
'loser' ,#'l_str', 'l_td', 'l_sub', 'l_pass', 'l_wclass', 'l_method', 'l_mthdtl', 'l_round', 'l_time',
    'f_info',]}

def parse(self, response):
    rev_orderd_events = response.css('tr.b-statistics__table-row')[::-1]
    # full event_links
    # event_links = rev_orderd_events.css('i>a::attr(href)').extract()
    # for url in event_links:
    #     yield scrapy.Request(url=event_links, callback=self.parse_event)
    event_links = rev_orderd_events.css('i>a::attr(href)').extract_first()
    yield scrapy.Request(url=event_links,callback=self.parse_event)

# follow links
def parse_event(self, response):
    #sel = Selector(response)
    pg = response.css('div.l-page__container')
    #fights = response.css('tr.b-fight-details__table-row.b-fight-details__table-row__hover.js-fight-details-click')
    #table = response.css('table.b-fight-details__table.b-fight-details__table_style_margin-top.b-fight-details__table_type_event-details.js-fight-table')

    for match in pg:
        il = ItemLoader(StatsItem(), response=response)       
        il.add_css('event_name','h2.b-content__title>span::text')
        il.add_css('event_date','ul.b-list__box-list>li:nth-child(1)::text')
        il.add_css('event_loc' ,'ul.b-list__box-list>li:nth-child(2)::text')
        il.add_css('attendance','ul.b-list__box-list>li:nth-child(3)::text')
        il.add_css('winner','p.b-fight-details__table-text:nth-child(odd)>a::text')
        il.add_css('loser' ,'p.b-fight-details__table-text:nth-child(even)>a::text')
        il.add_css('f_info', 'td p.b-fight-details__table-text::text')
        yield il.load_item()

实际结果:

event_name  event_date  event_loc   attendance  winner  loser   f_info

UFC 1: The Beginning    12-Nov-93   Denver, Colorado, USA   2,800   Royce Gracie,Jason DeLucia,Royce Gracie,Gerard Gordeau,Ken Shamrock,Royce Gracie,Kevin Rosier,Gerard Gordeau    Gerard Gordeau,Trent Jenkins,Ken Shamrock,Kevin Rosier,Patrick Smith,Art Jimmerson,Zane Frazier,Teila Tuli  1,0,1,0,1,0,2,0,Open Weight,SUB,Rear Naked Choke,1,1:44,3,1,1,0,1,0,1,0,Open Weight,SUB,Rear Naked Choke,1,0:52,0,0,0,0,1,0,2,0,Open Weight,SUB,Rear Naked Choke,1,0:57,11,0,0,0,0,0,0,0,Open Weight,KO/TKO,1,0:59,1,4,1,0,2,0,0,0,Open Weight,SUB,Heel Hook,1,1:49,0,0,1,0,0,0,2,0,Open Weight,SUB,Other,1,2:18,15,12,0,0,0,0,0,0,Open Weight,KO/TKO,1,4:20,3,0,0,0,0,0,0,0,Open Weight,KO/TKO,Kick,1,0:26

预期结果会更像:

event_name  event_date  event_loc   attendance  winner  loser   f_info

UFC 1: The Beginning    12-Nov-93   Denver, Colorado, USA   2,800   Royce Gracie, Gerard Gordeau, 1,0,1,0,1,0,2,0,Open Weight,SUB,Rear Naked Choke,1,1:44,

UFC 1: The Beginning    12-Nov-93   Denver, Colorado, USA   2,800 Jason DeLucia, Trent Jenkins 3,1,1,0,1,0,1,0,Open Weight,SUB,Rear Naked Choke,1,0:52 ....

*为清晰起见进行了编辑

【问题讨论】:

  • 您能否指定您在 csv 文件中写入的代码?在我看来,您需要在每个 UFC 之前添加 \n
  • 我一直在命令行输出:scrapy crawl stats.py -o fcstats.csv。我怎么能把那个 \n 添加到我的输出中?
  • 无论如何,如果你这样做 for match in pg 你只迭代一次。我觉得你应该写for match in pg[0],因为response.css的结果是一个列表;然后选择与每个玩家相关的容器类,创建getall 或任何其他类似函数,然后迭代该集合。看,我试图废弃你的网站,我有几个授权问题......我必须解决它们,然后我会提供一个解决方案(如果之前没有人应该发布过......)。

标签: python pandas scrapy


【解决方案1】:

我已经在 Scrapy 工作了很多年,我发现这个 Item 类没用而且非常混乱,特别是对于那些刚接触 Scrapy 的人来说

在您的情况下,您需要在 for 循环中迭代赢家和输家元素,然后一个接一个地产生

class StatsSpider(scrapy.Spider):
    name = 'stats'
    allowed_domains = ['ufcstats.com']
    start_urls = ['http://ufcstats.com/statistics/events/completed?page=all']


    def parse(self, response):
        rev_orderd_events = response.css('tr.b-statistics__table-row')[::-1]

        event_links = rev_orderd_events.css('i>a::attr(href)').extract_first()
        yield scrapy.Request(url=event_links,callback=self.parse_event)

    # follow links
    def parse_event(self, response):
        pg = response.css('div.l-page__container')

        for match in pg:

            event_name = item.css("h2.b-content__title>span::text").extract_first()
            event_date = item.css("ul.b-list__box-list>li:nth-child(1)").extract_first()
            event_loc = item.css("ul.b-list__box-list>li:nth-child(2)::text").extract_first()

            for item in match.css("p.b-fight-details__table-text:nth-child(odd)>a"):
                winner = {}
                winner['name'] = item.css("::text").extract_first()
                winner['type'] = 'winner'
                winner['event_name'] = event_name
                winner['event_date'] = event_date
                winner['event_loc'] = event_loc

                yield winner

            for item in match.css("p.b-fight-details__table-text:nth-child(even)>a"):
                loser = {}
                loser['name'] = item.css("::text").extract_first()
                winner['type'] = 'loser'
                loser['event_name'] = event_name
                loser['event_date'] = event_date
                loser['event_loc'] = event_loc
                yield loser

【讨论】:

    【解决方案2】:

    感谢@umair 和@Catalina_Chircu

    def parse_event(self, response):
    
        pg = response.css('div.l-page__container')
    
        for event in response.css('div.b-fight-details'):
            event_name = pg.css('h2.b-content__title>span::text').extract_first()
            event_date = event.css('ul.b-list__box-list>li:nth-child(1)::text').extract()
            event_loc  = event.css('ul.b-list__box-list>li:nth-child(2)::text').extract()
            attendance = event.css('ul.b-list__box-list>li:nth-child(3)::text').extract()
    
    
            for fights in event.css('tr')[1:]: 
                il = ItemLoader(StatsItem(), selector=fights)
                il.add_value('event_name', event_name)
                il.add_value('event_date', event_date)
                il.add_value('event_loc', event_loc)
                il.add_value('attendance', attendance)
                il.add_css('winner', 'td.b-fight-details__table-col:nth-child(2) p.b-fight-details__table-text:nth-child(odd)>a::text')
                il.add_css('loser', 'td.b-fight-details__table-col:nth-child(2) p.b-fight-details__table-text:nth-child(even)>a::text')
                #il.add_css('f_info', ':nth-child(3) p.b-fight-details__table-text::text')
                il.add_css('w_str' ,'td.b-fight-details__table-col:nth-child(3)>p:nth-child(odd)::text')
                il.add_css('l_str' ,'td.b-fight-details__table-col:nth-child(3)>p:nth-child(even)::text')
                il.add_css('w_td'  ,'td.b-fight-details__table-col:nth-child(4)>p:nth-child(odd)::text')
                il.add_css('l_td'  ,'td.b-fight-details__table-col:nth-child(4)>p:nth-child(even)::text')
                il.add_css('w_sub' ,'td.b-fight-details__table-col:nth-child(5)>p:nth-child(odd)::text')
                il.add_css('l_sub' ,'td.b-fight-details__table-col:nth-child(5)>p:nth-child(even)::text')
                il.add_css('w_pass','td.b-fight-details__table-col:nth-child(6)>p:nth-child(odd)::text')
                il.add_css('l_pass','td.b-fight-details__table-col:nth-child(6)>p:nth-child(even)::text')
                il.add_css('w_wclass','td.b-fight-details__table-col:nth-child(7)>p:nth-child(1)::text')
                il.add_css('l_wclass','td.b-fight-details__table-col:nth-child(7)>p:nth-child(1)::text')
                il.add_css('w_method','td.b-fight-details__table-col:nth-child(8)>p:nth-child(odd)::text')
                il.add_css('l_method','td.b-fight-details__table-col:nth-child(8)>p:nth-child(odd)::text')
                il.add_css('w_mthdtl','td.b-fight-details__table-col:nth-child(8)>p:nth-child(even)::text')
                il.add_css('l_mthdtl','td.b-fight-details__table-col:nth-child(8)>p:nth-child(even)::text')
                il.add_css('w_round','td.b-fight-details__table-col:nth-child(9)>p:nth-child(odd)::text')
                il.add_css('l_round','td.b-fight-details__table-col:nth-child(9)>p:nth-child(odd)::text')
                il.add_css('w_time','td.b-fight-details__table-col:nth-child(10)>p:nth-child(odd)::text')
                il.add_css('l_time','td.b-fight-details__table-col:nth-child(10)>p:nth-child(odd)::text')
                yield il.load_item()'
    

    与相关项目的输入/输出处理器为我提供了我所希望的大部分内容

    【讨论】:

    • 干得好!实际上,您必须首先报废图形的容器,然后逐个 tr。我写了这个,但无法测试它,因为我似乎被网站阻止了:def parse(self, response): pg = response.css('div.l-page__container') if pg: infoContainer = pg[0] myinfolist = infoContainer.css('tr.b-fight-details__table-row').getall() for oneLine in myinfolist: # extract here one line as you wish
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-14
    • 2020-03-12
    • 1970-01-01
    • 2013-11-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多