【问题标题】:Scrapy: Duplicate item fields due to multiple for loopsScrapy:由于多个 for 循环,重复的项目字段
【发布时间】:2019-08-20 02:47:16
【问题描述】:

我的问题几乎与:Scrapy - Why Item Inside For Loop Has The Same Value While Accessed in Another Parser

除了我有两个 For 循环,所以创建一个新项目会导致我丢失第一个抓取页面中的数据。

基本结构是:

  • 知道第一个网址。

  • For 循环遍历已知 url

    • 数据和下一个url的for循环

      • For 循环获取更多数据和下一个 url

        • 更多数据和下一个网址。

        • 更多数据和下一个网址。

        • 产量

每页有 10-40 条数据,但我有一个简化的代码来查找 1-2。

import scrapy


class Product(scrapy.Item):
    Date = scrapy.Field()
    Name = scrapy.Field()
    Winner_Name= scrapy.Field()
    Match_Duration= scrapy.Field()
    Loser_Url= scrapy.Field()
    Winner_Birthday= scrapy.Field()
    Loser_Birthday= scrapy.Field()


    pass
import scrapy
from urllib.parse import urljoin
from items import Product
start = 2018
finish =2019


class QuotesSpider(scrapy.Spider):
    name = "brief"
    custom_settings = {'CONCURRENT_REQUESTS':1,'DOWNLOAD_DELAY':1}

    def start_requests(self):

        urls = "https://www.atptour.com/en/scores/results-archive?year=2018"


        for year in range(start, finish):
            next_page = urljoin(urls,"?year=" + str(year))
            yield scrapy.Request(next_page, callback=self.parse, meta={'dont_obey_robotstxt': True},dont_filter=True)




    def parse(self, response):
        for tournament in response.css('tr.tourney-result'):
                item = Product()
                item['Date']=tournament.css('span.tourney-dates::text').get().replace("\r", '').replace("\n", '').replace("\t", '').strip(),
                item['Name']= tournament.css('span.tourney-title::text').get().replace("\r", '').replace("\n", '').replace("\t", '').strip(),
                Tourney_URL= response.urljoin(tournament.css('a.button-border::attr(href)').get())
                yield scrapy.Request(Tourney_URL, callback=self.tourney_info, meta={'dont_obey_robotstxt': True, 'item':item},dont_filter=True)

    def tourney_info(self, response):
        table = response.css('table.day-table tbody')
        rows = table.css('tr')
        for row in rows:
            item = response.meta['item']
            names = row.css('td.day-table-name a::text').getall()
            item['Winner_Name']= names[0].replace("\r", '').replace("\n", '').replace("\t", '').strip(),
            Match_URL = response.urljoin(row.css('td.day-table-score a::attr(href)').get())
            yield scrapy.Request(Match_URL, callback=self.matchinfo, meta={'dont_obey_robotstxt': True,'item':item},dont_filter=True)



    def matchinfo(self, response):
            item = response.meta['item']
            table = response.css('table.match-stats-table')
            mytime = response.css('td.time::text').get().replace("\r", '').replace("\n", '').replace("\t", '').strip()
            factors = (60, 1, 1 / 60)
            t1 = sum(i * j for i, j in zip(map(int, mytime.split(':')), factors))
            item['Match_Duration'] = t1
            item['Loser_Url']=response.urljoin(response.css('div.player-right-image a::attr(href)').get())
            winner_url = response.urljoin(response.css('div.player-left-image a::attr(href)').get())
            yield scrapy.Request(winner_url, callback=self.winnerinfo, meta={'dont_obey_robotstxt': True,'item':item},dont_filter=True)

    def winnerinfo(self, response):
            item = response.meta['item']
            item['Winner_Birthday'] = response.css('span.table-birthday::text').get().replace("\r", '').replace("\n", '').replace("\t", '').strip()

            yield scrapy.Request(item['Loser_Url'], callback=self.loserinfo, meta={'dont_obey_robotstxt': True, 'item': item},dont_filter=True)

    def loserinfo(self, response):
            item = response.meta['item']
            item['Loser_Birthday'] = response.css('span.table-birthday::text').get().replace("\r", '').replace("\n", '').replace("\t", '').strip()

            yield item

非常简化的结果是:

  • For 循环遍历已知 url(工作)

    • 数据和下一个 url 的 For 循环(工作)

      • 更多数据和下一个 url 的 For 循环(将为该循环中的所有数据提供相同的值)

        • 更多数据和下一个网址。 (工作)

        • 更多数据和下一个网址。 (工作)

        • 产量

Scrapy 是否具有我所缺少的能够在整个抓取过程中保留一个项目的功能?

结果:

应该是:

             A      B      C

             A      D      E

             A      F      G

             B      H      I 

             B      J      K

是:

             A      B      C

             A      B      E

             A      B      G

             B      H      I 

             B      H      K

【问题讨论】:

  • 您可以在pipeline.py 中过滤重复项:创建一个类变量saved_items = {} 并在process_item() 中检查它
  • 我删除了关于重复项的句子,因为这不是主要问题。

标签: python scrapy


【解决方案1】:

您用来存储抓取数据的项目是可变的。您应该在将其传递给下一个请求之前将其复制到 item.copy() 中,例如在 parse 上(也可能在 tourney_info 上)。由于每个方法都会在 json 文件中生成一个 en 条目,但您持有对同一项目的多个引用,因此预计会发生这种情况。

如果你愿意,也检查https://docs.scrapy.org/en/latest/topics/items.html#copying-items

【讨论】:

  • 就是这样。谢谢。
猜你喜欢
  • 1970-01-01
  • 2014-07-30
  • 2013-06-11
  • 2017-02-12
  • 2014-06-28
  • 1970-01-01
  • 2013-02-19
  • 1970-01-01
相关资源
最近更新 更多