【问题标题】:Getting AttributeError error 'str' object has no attribute 'get'获取 AttributeError 错误“str”对象没有属性“get”
【发布时间】:2020-07-17 18:08:07
【问题描述】:

我在处理 JSON 响应时遇到错误:

Error: AttributeError: 'str' object has no attribute 'get'

可能是什么问题?

对于其余的值,我也收到以下错误:

***TypeError: 'builtin_function_or_method' 对象不可下标

'电话':值['_source']['primaryPhone'], KeyError: 'primaryPhone'***

# -*- coding: utf-8 -*-
import scrapy
import json


class MainSpider(scrapy.Spider):
    name = 'main'
    start_urls = ['https://experts.expcloud.com/api4/std?searchterms=AB&size=216&from=0']

def parse(self, response):

    resp = json.loads(response.body)
    values = resp['hits']['hits']

    for value in values:

        yield {
            'Full Name': value['_source']['fullName'],
            'Phone': value['_source']['primaryPhone'],
            "Email": value['_source']['primaryEmail'],
            "City": value.get['_source']['city'],
            "Zip Code": value.get['_source']['zipcode'],
            "Website": value['_source']['websiteURL'],
            "Facebook": value['_source']['facebookURL'],
            "LinkedIn": value['_source']['LinkedIn_URL'],
            "Twitter": value['_source']['Twitter'],
            "BIO": value['_source']['Bio']
        }

【问题讨论】:

    标签: json api scrapy


    【解决方案1】:

    它的嵌套比你想象的要深。这就是您收到错误消息的原因。

    代码示例

    import scrapy
    import json
    
    
    class MainSpider(scrapy.Spider):
        name = 'test'
        start_urls = ['https://experts.expcloud.com/api4/std?searchterms=AB&size=216&from=0']
    
        def parse(self, response):
            resp = json.loads(response.body)
            values = resp['hits']['hits']
    
            for value in values:
                yield {
                    'Full Name': value['_source']['fullName'],
                    'Primary Phone':value['_source']['primaryPhone']
                }
    

    解释

    resp 变量正在创建一个 python 字典,但这个 JSON 数据中没有 resp['hits']['hits']['fullName']。您正在寻找的数据,fullName 实际上是resp['hits']['hits'][i]['_source']['fullName']i 是一个数字,因为 resp['hits']['hits'] 是一个列表。

    resp['hits'] 是一个字典,因此 values 变量很好。 但是resp['hits']['hits'] 是一个列表,因此您不能使用get 请求,它只接受数字作为[] 中的值,而不是字符串。因此出现错误。

    提示

    1. 使用 response.json() 代替 json.loads(response.body),从 Scrapy v2.2 开始,scrapy 现在内部支持 json。在幕后它已经导入了 json。

    2. 还要检查 json 数据,我使用 requests 是为了方便,只是进行嵌套,直到我得到你需要的数据。

    3. 生成字典对于这种类型的数据来说很好,因为它的结构很好,但是任何其他需要修改或更改或某些地方错误的数据。使用 Items 字典或 ItemLoader。这两种产生输出的方式比产生字典要灵活得多。我几乎从不生成字典,唯一的时候是你拥有高度结构化的数据。

    更新代码

    查看 JSON 数据,有相当多的缺失数据。这是网络抓取的一部分,您会发现这样的错误。这里我们使用 try 和 except 块,因为当我们得到一个 KeyError 时,这意味着 python 无法识别与值关联的键。我们必须处理这个异常,我们在这里通过说产生一个字符串'No XXX'

    一旦您开始发现差距等,最好考虑使用 Items 字典或 Itemloaders。

    现在值得看看关于项目的 Scrapy 文档。本质上,Scrapy 做了两件事,它从网站中提取数据,并提供了一种存储这些数据的机制。它这样做的方式是将其存储在一个名为 Items 的字典中。代码与生成字典没有太大区别,但 Items 字典允许您更轻松地操作提取的数据,并使用 scrapy 可以做的额外事情。您需要先使用所需的字段编辑 items.py。我们创建一个名为 TestItem 的类,我们使用 scrapy.Field() 定义每个字段。然后我们可以在我们的蜘蛛脚本中导入这个类。

    项目.py

    import scrapy
    
    
    class TestItem(scrapy.Item):
        # define the fields for your item here like:
        # name = scrapy.Field()
        full_name = scrapy.Field()
        Phone = scrapy.Field()
        Email = scrapy.Field()
        City = scrapy.Field()
        Zip_code = scrapy.Field()
        Website = scrapy.Field()
        Facebook = scrapy.Field()
        Linkedin = scrapy.Field()
        Twitter = scrapy.Field()
        Bio = scrapy.Field()
    

    这里我们指定了我们想要的字段,不幸的是你不能使用带空格的字符串,因此为什么全名是 full_name。 field() 为我们创建了 item 字典的字段。

    我们使用from ..items import TestItem 将此项目字典导入我们的蜘蛛脚本。 from ..items 表示我们将 items.py 从父文件夹带到蜘蛛脚本,并且我们正在导入类 TestItem。这样我们的蜘蛛就可以用我们的 json 数据填充项目字典。

    请注意,在 for 循环之前,我们通过 item = TestItem() 实例化 TestItem 类。实例化意味着调用类,在这种情况下它会创建一个字典。这意味着我们正在创建项目字典,然后我们用键和值填充该字典。从 for 循环中可以看到,您必须在添加键和值之前执行此操作。

    蜘蛛脚本

    import scrapy
    import json
    from ..items import TestItem
    
    class MainSpider(scrapy.Spider):
       name = 'test'
       start_urls = ['https://experts.expcloud.com/api4/std?searchterms=AB&size=216&from=0']
    
       def parse(self, response):
           resp = json.loads(response.body)
           values = response.json()['hits']['hits']
           item = TestItem()
           for value in values:
            try:
                item['full_name'] = value['_source']['fullName']
            except KeyError:
                item['full_name'] = 'No Name'
            try:
                item['Phone'] = value['_source']['primaryPhone']
            except KeyError:
                item['Phone'] = 'No Phone number'
            try:
                item["Email"] =  value['_source']['primaryEmail']
            except KeyError:
                item['Email'] = 'No Email'
            try:
                item["City"] = value['_source']['activeLocations'][0]['city']
            except KeyError:
                item['City'] = 'No City'
            try:
                 item["Zip_code"] = value['_source']['activeLocations'][0]['zipcode']
            except KeyError:
                item['Zip_code'] = 'No Zip code'
                    
            try:
                item["Website"] = value['AgentMarketingCenter'][0]['Website']
            except KeyError:
                item['Website'] = 'No Website'
                   
            try:
                item["Facebook"] = value['_source']['AgentMarketingCenter'][0]['Facebook_URL']
            except KeyError:
                item['Facebook'] = 'No Facebook'
                    
            try:
                item["Linkedin"] = value['_source']['AgentMarketingCenter'][0]['LinkedIn_URL']
            except KeyError:
                item['Linkedin'] = 'No Linkedin'    
            try:
                item["Twitter"] = value['_source']['AgentMarketingCenter'][0]['Twitter']
            except KeyError:
                item['Twitter'] = 'No Twitter'
            
            try:
                 item["Bio"]: value['_source']['AgentMarketingCenter'][0]['Bio']
            except KeyError:
                item['Bio'] = 'No Bio'
                   
            yield item
                        
    

    【讨论】:

    • 感谢您的精彩解释。我试过你的方法,它奏效了,但出于某种原因,它并没有刮掉所有的名字和电话。它刮掉了其中的 166 个,其余的,它显示了错误之后的错误。我还更新了我想要获取但不起作用的其他值的问题。 "'Phone': value['_source']['primaryPhone'], KeyError: 'primaryPhone'"
    • 我怀疑部分 json 数据没有“primaryPhone”类别,因此您没有收到任何其他数据。向上滚动以检查它是否有效时,我错过了这个错误。将调查 JSON 数据。
    • 对不起,我正在更新它,我认为 Item 字典对于这种缺少数据的数据要好得多。希望这个解释对你有意义。
    • 看来您需要更仔细地查看 JSON 我正在使用您的变量来获取该数据。
    • 更新了代码,JSON 对象的结构也不是老实说。我已经检查了多个不同的值 ['_sources'] 有很大一部分没有 facebook/etc... 我已经更新到我认为可以捕获您需要的数据的代码。如果有不一致的地方,它会隐藏在嵌套的 JSON 之间,我建议你自己去看看。我将不胜感激接受一个答案。
    猜你喜欢
    • 2020-04-01
    • 2021-05-22
    • 1970-01-01
    • 2015-02-17
    • 2020-12-18
    • 2018-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多