【问题标题】:scrapy returning an empty objectscrapy 返回一个空对象
【发布时间】:2020-10-31 01:10:29
【问题描述】:

我正在使用 css 选择器并不断得到空值的响应。这是代码。

import scrapy 

class WebSpider(scrapy.Spider):
name = 'activities'
start_urls = [
    'http://capetown.travel/events/'
]


def parse(self, response):
    all_div_activities = response.css("div.tribe-events-content")#gdlr-core-pbf-column gdlr-core-column-60 gdlr-core-column-first
    title = all_div_activities.css("h2.tribe-events-list-event-title::text").extract()#gdlr-core-text-box-item-content
    price = all_div_activities.css(".span.ticket-cost::text").extract()
    details = all_div_activities.css(".p::text").extract()
    yield {
        'title':title,
        'price':price,
        'details':details
    }

【问题讨论】:

  • 嗨,我可以知道预期的输出是什么吗?
  • @balandongiv {'title': [Stellenbosch on Stage: Libertas Choir virtual concert], 'price': [ZAR100], 'details': [世界级的 Libertas Choir 将表演一场7 月 11 日星期六的现场虚拟音乐会将让观众在家中舒适地观看独家表演。该节目是与 Visit Stellenbosch as Stellenbosch on Stage 联合举办的三项活动中的第一项,这是一项展示团结和团结的倡议。所有收益都将用于帮助 Stellenbosch Unite,这是一项在...]} 期间为弱势社区提供支持的合作项目

标签: python scrapy css-selectors web-crawler


【解决方案1】:

在您的代码中,您希望选择所有事件,但该输出将是一个列表,并且您无法像尝试那样使用带有列表的 extract() 来选择标题等。

这就是您无法获得所需数据的原因。在循环all_div_activities 的情况下,您将需要使用 for 循环来循环页面上的每个事件。

脚本代码

def parse(self,response):
    all_div_activities = response.css('div.tribe-events-event-content')
    for a in all_div_activities:
        title = a.css('a.tribe-event-url::text').get()

        if a.css('span.ticket-cost::text'):
            price = a.css('span.ticket-cost::text').get()
        else: 
            price = 'No price'

        details = a.css('div[class*="tribe-events-list-event-description"] > p::text').get()

        yield { 
               'title':title.strip(),
                'price':price,
                'details':details
              }

注意事项

  1. 对价格使用 if 语句,因为有些元素根本没有价格,因此输入一些信息是个好主意。
  2. 在生成字典时在标题上使用 strip(),因为标题有空格并附有 \n。

建议

作为一个小问题,Scrapy 建议使用 get() 和 getall() 方法而不是 extract_first() 和 extract()。使用 extract() 并不总是可以知道输出是否是一个列表,在这种情况下,我得到的输出是一个列表。这就是为什么 scrapy 文档建议使用 get() 代替。它也更紧凑。使用 get() 你总是会得到一个字符串。这也意味着我可以在上面的代码中看到标题中的换行符和空格。

另一个提示是,如果类属性很长,请使用 *= 选择器,只要您选择的部分属性为您想要的数据提供唯一的结果。请参阅此处了解更多详细信息here

从长远来看,使用项目而不是生成字典可能会更好,因为您可以为页面上的某些事件中您正在抓取的数据设置默认值,而其他事件则不是。您必须通过管道来执行此操作(同样,如果您不理解这一点,请不要担心)。有关项目的信息,请参阅文档,并在 here 了解有关项目的更多信息。

【讨论】:

  • 代码在 remove .strip() 时运行,但还有另一个问题,标题:不返回,价格:到处都没有价格@AaronS
  • 你能把脚本的全部代码贴出来吗?因为我的脚本正在运行,使用 strip() 并且所有标题都在那里。我也刚刚将我自己的 SO 条目重新复制到一个空白脚本中,它也可以工作。
  • 这个评论区太长了,我可以在哪里附加它
  • pastebin.com,创建一个新的粘贴并复制链接。正如我所说,我刚刚将我在 SO 中键入的函数复制到一个空白脚本中,它似乎正在运行,所以它可能在你自己的代码/scrapy 设置中是次要的。
  • 另外,更仔细地查看数据集,还会输出一些 unicode。当输出为 json 时,Scrapy 会自动以 unicode 编码,转换为 utf-8 将修复以 unicode 形式输出的字符。如果您在脚本中从 start_urls = [] 向下添加一行。 custom_settings = {'FEED_EXPORT_ENCODING': 'utf-8'} 这将解决此问题
【解决方案2】:

这是我的。希望对你有帮助。

for item in response.css('div.tribe-events-event-content'): 
    print(item.css('a.tribe-event-url::text').get()) 
    print(item.css('span.ticket-cost::text').get()) 
    print(item.css('p::text').get()) 

谢谢。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-03-31
    • 2014-07-15
    • 2018-08-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多