当前位置: 首页 > 知识库问答 >
问题:

python - 为什么scapy爬虫用管道持久化存储时创建的文件一直为空写不进去?

乐正育
2024-04-11

最近在学习scrapy爬虫的用管道持久化存储时,遇到了这个问题,只知道这个创建的fp一直为none

  import scrapy  import sys  sys.path.append(r'D:\project_test\PyDemo\demo1\xunlian\mySpider\qiubai')  from ..items import QiubaiItem  class BiedouSpider(scrapy.Spider):      name = "biedou"      #allowed_domains = ["www.xxx.com"]      start_urls = ["https://www.biedoul.com/wenzi/"]          def parse(self, response):          #pass          dl_list = response.xpath('/html/body/div[4]/div[1]/div[1]/dl')          for dl in dl_list:              title = dl.xpath('./span/dd/a/strong/text()')[0].extract()              content = dl.xpath('./dd//text()').extract()              content = ''.join(content)              #完成数据解析              item = QiubaiItem()              item['title'] = title              item['content'] = content              yield item  #将item提交给管道              break

接下来分别是item.py的

  import scrapy  class QiubaiItem(scrapy.Item):      # define the fields for your item here like:      # name = scrapy.Field()      title = scrapy.Field()      content = scrapy.Field()

这个是pipelines.py:

     class QiubaiPipeline(object):      def __init__(self):          self.fp = None      def open_spdier(self,spider):#重写父类的文件打开方法          print("开始爬虫")          self.fp = open('./biedou.txt','w',encoding='utf-8')      def close_spider(self,spider):          print("结束爬虫")          self.fp.close()      def process_item(self, item, spider):          title = str(item['title'])          content = str(item['content'])          self.fp.write(title+':'+content+'\n')          return item

以下是我的报错:

  PS D:\project_test\PyDemo\demo1\xunlian\mySpider\qiubai> py -m scrapy crawl biedou  2024-04-11 10:36:12 [scrapy.core.scraper] ERROR: Error processing {'content': '笑点不同怎么做朋友。。', 'title': '笑点太低了吧'}  Traceback (most recent call last):    File "C:\Users\空条承太郎\AppData\Roaming\Python\Python312\site-packages\twisted\internet\defer.py", line 1078, in _runCallbacks      current.result = callback(  # type: ignore[misc]    File "C:\Users\空条承太郎\AppData\Roaming\Python\Python312\site-packages\scrapy\utils\defer.py", line 340, in f      return deferred_from_coro(coro_f(*coro_args, **coro_kwargs))  TypeError: Object of type QiubaiItem is not JSON serializable  结束爬虫  2024-04-11 10:36:12 [scrapy.core.engine] ERROR: Scraper close failure  Traceback (most recent call last):    File "C:\Users\空条承太郎\AppData\Roaming\Python\Python312\site-packages\twisted\internet\defer.py", line 1078, in _runCallbacks      current.result = callback(  # type: ignore[misc]    File "D:\project_test\PyDemo\demo1\xunlian\mySpider\qiubai\qiubai\pipelines.py", line 24, in close_spider      self.fp.close()  AttributeError: 'NoneType' object has no attribute 'close'

真的找了很久的问题了,像是那种重写父类方法的问题我也比对过感觉自己重写的方式是正确的,还有就是setting文件中pipelines也有手动打开,但是始终不知道自己创建的这个fp为什么是None,一直无法写入,连txt文件都没法创建,希望有大佬能帮我解决,十分感激!

共有1个答案

云光明
2024-04-11

从报错信息来看,问题主要有两个:

  1. TypeError: Object of type QiubaiItem is not JSON serializable:这个错误表明Scrapy试图将QiubaiItem对象序列化为JSON,但失败了。默认情况下,Scrapy会将爬取到的item序列化为JSON并写入到磁盘,但你的QiubaiItem对象可能包含无法被序列化为JSON的内容,例如文件对象、自定义类等。
  2. AttributeError: 'NoneType' object has no attribute 'close':这个错误表明你试图关闭一个为None的文件对象。这可能是因为open_spider方法中的文件打开操作失败了,或者在你试图关闭文件之前,文件对象已经被垃圾回收或手动关闭了。

为了解决这个问题,你可以尝试以下步骤:

  1. 检查文件路径和权限:确保你有足够的权限在当前目录下创建文件,并且文件路径是正确的。你也可以尝试使用绝对路径来打开文件,看看是否可以解决问题。
  2. 重写process_item方法:在process_item方法中,不要试图写入文件。而是返回一个item,让Scrapy默认的处理机制来处理这个item。这样,如果item中包含无法序列化的内容,Scrapy会抛出错误,帮助你更容易地找到问题所在。
  3. 自定义序列化:如果你确定item中的内容无法被序列化为JSON,你可以自定义一个序列化方法,将item转换为一个可以被序列化的格式,如字符串或字典。然后,你可以在process_item方法中使用这个序列化方法来处理item。
  4. 检查open_spiderclose_spider方法:确保这两个方法被正确调用,并且文件对象在open_spider中被正确创建,在close_spider中被正确关闭。你也可以在这两个方法中添加一些调试信息,以便更好地了解问题的所在。

以下是一个修改后的pipelines.py示例,其中包含了自定义序列化方法:

class QiubaiPipeline(object):    def __init__(self):        self.fp = None    def open_spider(self, spider):        print("开始爬虫")        self.fp = open('./biedou.txt', 'w', encoding='utf-8')    def close_spider(self, spider):        print("结束爬虫")        if self.fp:            self.fp.close()    def process_item(self, item, spider):        # 自定义序列化方法        serialized_item = self.serialize_item(item)        self.fp.write(serialized_item + '\n')        return item    def serialize_item(self, item):        # 将item转换为一个可以被序列化的格式        title = str(item['title'])        content = str(item['content'])        return f"{title}:{content}"

希望这个示例能帮助你解决问题。如果还有其他问题,请随时提问。

 类似资料:
  • 我有一个将Apache Ignite用作单节点集群的应用程序。也就是说,Ignite由应用程序启动和停止,其生命周期与应用程序匹配。 Ignite缓存同时启用了持久存储和读通。所以 首先调用cache.get 所有这一切似乎都运转得很好。这是我的问题:有时(经常)当应用程序被跳转或重新部署时,持久存储区数据目录就Apache Ignite而言仍然保持锁定状态。因此,Ignite会无声地创建一个新的

  • 我的CN1应用程序在这里生成文件filesystemstorage.getinstance().getapphomePath()。我可以正确地读/写那里的文件。 此文件夹名类似于:- 我如何保证这部分保持不变?谢谢你的帮助。

  • 本平台是通过storageclass来动态创建PV。也就是说咱们依赖于storageclass,如果您的Kubernetes不支持相应的存储试,将无法非常方便的进行挂载。 目前暂不支持挂载多个PVC,或许以后会更新吧。 这里演示的是用的NFS进行演示,实际使用时可根据自己的需求配置相应的provisioner,其他配置是一样的不需要调整,只需要在“模版管理” 调整StorageClass和Pers

  • 我试图使一个属性文件在Java。可悲的是,当我启动Minecraft(因为这是Forge中的一个mod)时,文件不会创建。我会非常感谢任何帮助我的人。下面是代码:

  • 通常,我会通过Azure DevOps门户创建一个新的构建管道。然后,编辑器将带我完成选择项目源、存储库和模板的步骤。之后,我可以选择创建一个新分支或直接提交到主分支。 但是,这一次,我的分支中有一个现有的文件。我在本地使用文本编辑器创建了它,并将此分支推送到Azure运营模式。我想附加此文件,并让Azure管道创建新版本并将其排队。但是我找不到任何选择。导入生成管道选项仅接受JSON文件。 是否

  • 本地持久化卷允许用户通过标准 PVC 接口以简单便携的方式访问本地存储。PV 中包含系统用于将 Pod 安排到正确节点的节点亲和性信息。 一旦配置了本地卷,外部静态配置器(provisioner)可用于帮助简化本地存储管理。请注意,本地存储配置器与大多数配置器不同,并且尚不支持动态配置。相反,它要求管理员预先配置每个节点上的本地卷,并且这些卷应该是: Filesystem volumeMode(默