Scrapy 在文件中保存 200 个带有空项目的状态 url
Scrapy saving 200 status urls with empty items in a file
我在 scrapy 日志中注意到一些 url 返回 200 状态但不包含任何项目。这似乎是网站的稳定性,因为重新抓取这些网址 1-2 次会再次产生项目。我想将这些网址保存在单独的文件中以供重新抓取。
我试图在蜘蛛程序中创建字典 class 来存储这些 url,但是没有简单的方法可以将字典保存到文件中。
我尝试的另一种方法是为 url 创建第二个项目 class 并使用项目管道。它仍然输出空文件。我不太先进,无法编写自己的管道。这是我的代码。
import scrapy
class MyItem(scrapy.Item):
productCode = scrapy.Field()
productName = scrapy.Field()
...
class UrlItem(scrapy.Item):
eurl = scrapy.Field()
解析
class MySpider(scrapy.Spider):
custom_settings = {
'FEEDS':{
'%(filename)s.csv':{'format':'csv', 'encoding':'utf-8',},
},
'FEED_EXPORTERS': {'csv': 'scrapy.exporters.CsvItemExporter',},}
def parsePage(self, response):
products = response.xpath(...)
if len(products) == 0:
url = UrlItem()
url['eurl'] = response.url
yield url
else:
item = MyItem()
item['...'] = ...
...
yield item
流水线
from .items import MyItem, UrlItem
import csv
class UrlPipeline:
def open_spider(self, spider):
self.file = open('%s.csv' % "noProductsUrls", 'w')
def close_spider(self, spider):
self.file.close()
def process_item(self, url, spider):
if isinstance(url, UrlItem):
csvWriter = csv.writer(self.file)
csvWriter.writerow(ItemAdapter(url))
from itemadapter import ItemAdapter
from scrapy.exceptions import DropItem
class MyPipeline:
def __init__(self):
self.ids_seen = set()
def process_item(self, item, spider):
if isinstance(item, MyItem):
adapter = ItemAdapter(item)
if adapter['productCode'] in self.ids_seen:
raise DropItem(f"Duplicate item found: {item!r}")
else:
self.ids_seen.add(adapter['productCode'])
return item
设置文件
'project.pipelines.MyPipeline': 300,
'project.pipelines.UrlPipeline': 300,
问题是我已经在 spider class 中设置了导出器,它保存了一个 csv。在管道中,我只想再添加一个 csv。两者有冲突吗?或者最好在管道中构建两个 csv 文件?
更新: 我选择了下面的@marcos 解决方案,它更胜一筹。
有一种在蜘蛛class中保存csv的方法是基于this post。
def __init__(self):
self.outfile = open("urls.csv", "w", newline = "")
self.writer = csv.writer(self.outfile)
def closed(self,reason):
self.outfile.close()
在 def parse 中添加以下内容
if len(products) == 0:
self.writer.writerow([response.url])
我建议您只要在页面上找不到产品时就发出重试请求,除非您有非常具体的理由来存储这些 URL。
代码如下:
class MySpider(scrapy.Spider):
custom_settings = {
'FEEDS':{
'%(filename)s.csv':{'format':'csv', 'encoding':'utf-8',},
},
'FEED_EXPORTERS': {'csv': 'scrapy.exporters.CsvItemExporter',},}
def parsePage(self, response):
products = response.xpath(...)
if not len(products):
yield self._retry_request(response)
return
item = MyItem()
item['...'] = ...
...
yield item
def _retry_request(self, response, max_retries=5):
retries = response.meta.get('retry_time', 0)
if retries < max_retries:
return response.request.replace(
meta={**response.meta, 'retry_time': retries + 1},
dont_filter=True,
)
else:
self.logger.warning(f'Max retries reached for {response.url}')
我在 scrapy 日志中注意到一些 url 返回 200 状态但不包含任何项目。这似乎是网站的稳定性,因为重新抓取这些网址 1-2 次会再次产生项目。我想将这些网址保存在单独的文件中以供重新抓取。
我试图在蜘蛛程序中创建字典 class 来存储这些 url,但是没有简单的方法可以将字典保存到文件中。
我尝试的另一种方法是为 url 创建第二个项目 class 并使用项目管道。它仍然输出空文件。我不太先进,无法编写自己的管道。这是我的代码。
import scrapy
class MyItem(scrapy.Item):
productCode = scrapy.Field()
productName = scrapy.Field()
...
class UrlItem(scrapy.Item):
eurl = scrapy.Field()
解析
class MySpider(scrapy.Spider):
custom_settings = {
'FEEDS':{
'%(filename)s.csv':{'format':'csv', 'encoding':'utf-8',},
},
'FEED_EXPORTERS': {'csv': 'scrapy.exporters.CsvItemExporter',},}
def parsePage(self, response):
products = response.xpath(...)
if len(products) == 0:
url = UrlItem()
url['eurl'] = response.url
yield url
else:
item = MyItem()
item['...'] = ...
...
yield item
流水线
from .items import MyItem, UrlItem
import csv
class UrlPipeline:
def open_spider(self, spider):
self.file = open('%s.csv' % "noProductsUrls", 'w')
def close_spider(self, spider):
self.file.close()
def process_item(self, url, spider):
if isinstance(url, UrlItem):
csvWriter = csv.writer(self.file)
csvWriter.writerow(ItemAdapter(url))
from itemadapter import ItemAdapter
from scrapy.exceptions import DropItem
class MyPipeline:
def __init__(self):
self.ids_seen = set()
def process_item(self, item, spider):
if isinstance(item, MyItem):
adapter = ItemAdapter(item)
if adapter['productCode'] in self.ids_seen:
raise DropItem(f"Duplicate item found: {item!r}")
else:
self.ids_seen.add(adapter['productCode'])
return item
设置文件
'project.pipelines.MyPipeline': 300,
'project.pipelines.UrlPipeline': 300,
问题是我已经在 spider class 中设置了导出器,它保存了一个 csv。在管道中,我只想再添加一个 csv。两者有冲突吗?或者最好在管道中构建两个 csv 文件?
更新: 我选择了下面的@marcos 解决方案,它更胜一筹。
有一种在蜘蛛class中保存csv的方法是基于this post。
def __init__(self):
self.outfile = open("urls.csv", "w", newline = "")
self.writer = csv.writer(self.outfile)
def closed(self,reason):
self.outfile.close()
在 def parse 中添加以下内容
if len(products) == 0:
self.writer.writerow([response.url])
我建议您只要在页面上找不到产品时就发出重试请求,除非您有非常具体的理由来存储这些 URL。
代码如下:
class MySpider(scrapy.Spider):
custom_settings = {
'FEEDS':{
'%(filename)s.csv':{'format':'csv', 'encoding':'utf-8',},
},
'FEED_EXPORTERS': {'csv': 'scrapy.exporters.CsvItemExporter',},}
def parsePage(self, response):
products = response.xpath(...)
if not len(products):
yield self._retry_request(response)
return
item = MyItem()
item['...'] = ...
...
yield item
def _retry_request(self, response, max_retries=5):
retries = response.meta.get('retry_time', 0)
if retries < max_retries:
return response.request.replace(
meta={**response.meta, 'retry_time': retries + 1},
dont_filter=True,
)
else:
self.logger.warning(f'Max retries reached for {response.url}')