【问题标题】:Scraping Multi level data using Scrapy, optimum way使用 Scrapy 抓取多级数据,最佳方式
【发布时间】:2015-05-07 05:26:26
【问题描述】:

我一直想知道使用 scrapy 废弃多级数据的最佳方法是什么 我将分四个阶段描述情况,

  1. 我为抓取这些数据而遵循的当前架构
  2. 基本代码结构
  3. 困难以及为什么我认为必须有更好的选择
  4. 我尝试存储数据并失败然后部分成功的格式

当前架构

  1. 数据结构

首页:艺术家名单

第二页:每个艺术家的专辑列表

第三页:每张专辑的歌曲列表

  1. 基本代码结构

类 MusicLibrary(蜘蛛): name = '音乐库'

def parse(self, response):

    items = Discography()
    items['artists'] = []
    for artist in artists:
            item = Artist()
            item['albums'] = []
            item['artist_name'] = "name"
            items['artists'].append(item)
            album_page_url = "extract link to album and yield that page"
            yield Request(album_page_url,
                          callback=self.parse_album,
                          meta={'item': items,
                                'artist_name': item['artist_name']})

def parse_album(self, response):
    base_item = response.meta['item']
    artist_name = response.meta['artist_name']
    # this will search for the artist added in previous method and append album under that artist
    artist_index = self.get_artist_index(base_item['artists'], artist_name)
    albums = "some path selector"
    for album in albums:
        item = Album()
        item['songs'] = []
        item['album_name'] = "name"
        base_item['artists'][artist_index]['albums'].append(item)
        song_page_url = "extract link to song and yield that page"
        yield Request(song_page_url,
                      callback=self.parse_song_name,
                      meta={'item':  base_item,
                            "key": item['album_name'],
                            'artist_index': artist_index})

def parse_song_name(self, response):
    base_item = response.meta['item']
    album_name = response.meta['key']
    artist_index = response.meta["artist_index"]
    album_index = self.search(base_item['artists'][artist_index]['albums'], album_name)
    songs = "some path selector "

    for song in songs:
        item = Song()
        song_name = "song name"
        base_item['artists'][artist_index]['albums'][album_index]['songs'].append(item)
        # total_count (total songs to parse) = Main Artist page is having the list of total songs for each artist
        # current_count(currently parsed) = i will go to each artist->album->songs->[] and count the length

        # i will yield the base_item only when songs to scrape and song scraped count matches
        if current_count == total_count:
            yield base_item
  1. 困难以及为什么我认为必须有更好的选择

    • 目前我只在所有页面和子页面都被抓取时才产生项目对象,条件是要抓取的歌曲和抓取的歌曲计数匹配..
    • 但是给出抓取的性质和抓取的数量......有些页面要给我除 (200-status ok) 之外的代码,这些歌曲不会被抓取,项目计数也不匹配
    • 所以最后,即使 90% 的页面将被成功抓取并且计数不匹配,也不会产生任何结果,并且所有 CPU 功率都将丢失..
  2. 我尝试存储数据并失败然后部分成功的格式

    • 我想要单行格式的每个项目对象的数据 即艺术家名-专辑名-歌曲名 因此,如果艺术家 A 有 1 张专辑 (aa),其中包含 8 首歌曲 ... 8 个商品将存储,每首歌曲有一个条目 (item)
    • 但是对于当前格式,当我尝试在最后一个函数“parse_song_name”中每次都产生时,它每次都会产生复杂的结构,并且对象每次都是递增的......
    • 然后我认为在第一个 Discography->artist 然后是 Artist->albums 然后是 Albums->songs 中附加所有内容是问题所在,但是当我删除附加并尝试不这样做时,我只产生了一个对象,即最后一个不是全部..
    • 所以最后,如前所述开发了这个工作,但它不是每次都工作(在没有 200 状态代码的情况下)
    • 当它工作时,在屈服之后,我编写了一个管道,在其中我再次解析这个 JSON 并将其存储为我最初想要的数据格式(每首歌曲一行 --flat 结构)

谁能建议我在这里做错了什么,或者当某些页面返回非 200 代码时,我该如何提高效率并使其正常工作?

【问题讨论】:

  • 能否请您发布开始网址?
  • 如果可能,请也发布输出 json 格式?如果您可以发布 start-url 那就太好了,因为有时对 url 进行一些简单的调整可以减少额外的代码行以及请求。
  • 我从失败的代码版本重新开始,其中所有项目对象都具有相同的专辑和艺术家名称但歌曲名称不同......问题是可变对象......项目列表/字典是可变对象,每个回调方法都在接收同一个对象,并且所有迭代都在更改同一个对象....
  • 所以我的解决方案是使用 copy.deepcopy 在每个回调函数中创建新的项目对象并生成该新对象,而保持该基础引用不变..

标签: python selenium data-structures web-crawler scrapy


【解决方案1】:

上面代码的问题是:

  1. 可变对象 (list, dict) :所有回调在每个循环中都在改变同一个对象,因此...第一和第二级数据在最后第三个循环(mp3_son_url)中被覆盖... (这是我失败的尝试)

解决方案是使用简单的 copy.deepcopy 并在回调方法中从 response.meta 对象创建一个新对象,而不更改 base_item 对象

当我有时间时会尝试解释完整的答案..

【讨论】:

  • 我可能不应该为解释而屏住呼吸 :)
  • 我屏住呼吸的时间太长了,再也没有了!没有了!
  • 嗨,这在过去丢失了,这里的问题是当你将你的项目对象传递给元时,它是通过引用而不是值传递的,所以在每个 for 循环和回调之间,同一个项目对象被传递(通过引用传递),因此结果不可预测,解决方案是创建对象的新副本,修改并传递回调
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-05-23
  • 2020-11-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多