【问题标题】:scrapy add data to the json file from different functionsscrapy 从不同的函数将数据添加到 json 文件中
【发布时间】:2018-10-27 02:47:52
【问题描述】:

我是scrapy 和json 的新手,并且正在从事一个scrapy 项目。这是我的脚本:

import scrapy

class MoulaviSpider(scrapy.Spider):
    name = "moulavi"

    def start_requests(self):
    start_urls = [
        'https://ganjoor.net/moulavi/masnavi/daftar1/sh1/',
        'https://ganjoor.net/moulavi/masnavi/daftar1/sh2/',
    ]
        for url in start_urls:
            yield scrapy.Request(url=url, callback=self.title)

    def title(self, response):
        #'hetitle': response.css('h2').extract(), 
        return scrapy.Request(callback=self.parse)

    def parse(self, response):
        for line in response.css('div.b'):
            yield {
                'right_column': line.css('div.m1').extract(),
                'left_column': line.css('div.m2').extract(),
}

我使用 scrapy crawl moulavi -o moulavi.json 运行它。

我知道我的脚本现在不正确。 我想将每个页面的标题添加到 "def title" 内的 json 文件中,然后调用 "def parse" 将其他数据添加到 json 文件中.但是由于我对callback和yield不是很熟悉,所以不知道该怎么做。

正如您在我的代码中看到的,我已经注释了我希望将标题添加到 json 文件中的那一行,但不知道该怎么做。

所以我要做的是 url,找到页面的标题,然后写入json文件,然后启动for循环查找所有div标签使用类'm1'和'm2'并将它们写入json文件。然后开始抓取下一个url。

我想要这样的输出:(如果语法正确,则不是 suro)

{
"title":"first page title",
"content":[
    {"right_column": ["<div class=\"m1\"><p>من چگونه هوش دارم پیش و پس</p></div>"], "left_column": ["<div class=\"m2\"><p>چون نباشد نور یارم پیش و پس</p></div>"]},
    {"right_column": ["<div class=\"m1\"><p>عشق خواهد کین سخن بیرون بود</p></div>"], "left_column": ["<div class=\"m2\"><p>آینه غماز نبود چون بود</p></div>"]},
    {"right_column": ["<div class=\"m1\"><p>آینت دانی چرا غماز نیست</p></div>"], "left_column": ["<div class=\"m2\"><p>زانک زنگار از رخش ممتاز نیست</p></div>"]}
]
"title":"second page title",
"content":[
    {"right_column": ["<div class=\"m1\"><p>بشنو این نی چون شکایت می‌کند</p></div>"], "left_column": ["<div class=\"m2\"><p>از جداییها حکایت می‌کند</p></div>"]},
    {"right_column": ["<div class=\"m1\"><p>کز نیستان تا مرا ببریده‌اند</p></div>"], "left_column": ["<div class=\"m2\"><p>در نفیرم مرد و زن نالیده‌اند</p></div>"]},
]}

提前谢谢你:)

【问题讨论】:

  • url 中的 scrapy.Request(url=url, callback=self.parse) 是什么。该代码不正确,因为范围内没有名为 url 的变量。
  • 我知道我的脚本暂时不正确。
  • 我刚刚编辑了我的脚本并删除了那个 url 部分。
  • 您想在函数之间传递值并最终返回收集所有属性的项目?
  • 你可以在一个函数中完成所有这些,毕竟你会得到同一个页面的标题,对吧?

标签: python json function web-scraping scrapy


【解决方案1】:

你不需要创建新的回调来解析标题,你可以在parse函数中创建你想要的结构,你需要做的就是简单地创建一个具有你想要的属性的对象。

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

class MoulaviSpider(scrapy.Spider):
    name = 'moulavi'

    def start_requests(self):

        start_urls = [
            'https://ganjoor.net/moulavi/masnavi/daftar1/sh1/',
            'https://ganjoor.net/moulavi/masnavi/daftar1/sh2/',
        ]

        for url in start_urls:
            yield scrapy.Request(url=url, callback=self.parse)

    def parse(self, response):

        item = dict(title=response.xpath('//title/text()').extract_first(),content=[])

        for line in response.css('div.b'):
            item['content'].append({
                'right_column': line.css('div.m1').extract_first(),
                'left_column': line.css('div.m2').extract_first()})

        yield item

【讨论】:

    【解决方案2】:

    通常,一个方法将负责解析页面的内容,然后生成解析的数据。最后,在产生所有项目后,此方法可以产生更多请求,以便在需要时对更多页面进行解析。

    解析后的数据将用于创建Item 的实例,然后通过项目管道进行复杂的处理和持久化。在这里,我坚持使用产生字典以使示例更简单。

    根据您提供的所需输出,content 是输出 json 中的顶级键,它的值是一个列表。列表的元素是一个字典,有两个键left_column & right_column,值是列表类型。

    在这种情况下,parse 方法可能如下所示:

    import scrapy
    
    class MoulaviSpider(scrapy.Spider):
        name = "moulavi"
    
        def start_requests(self):
            start_urls = [
                'https://ganjoor.net/moulavi/masnavi/daftar1/sh1/',
                'https://ganjoor.net/moulavi/masnavi/daftar1/sh2/',
            ]
    
            for url in start_urls:
                yield scrapy.Request(url=url, callback=self.parse)
    
        def parse(self, response):
            # build up the content through a list comprehension
            # consider using `extract_first` instead of `extract` for 
            # less nested output
            content = [
              {'right_column': line.css('div.m1').extract(),
               'left_column': line.css('div.m2').extract()}
              for line in response.css('div.b')
            ]            
            yield {'title': response.css('h2').extract_first(),
                   'content': content}
    

    注意,为了提取title,我使用extract_first 而不是提取。考虑将extract_first 用于left_columnright_column 值,因为它们似乎是1 个元素的列表。

    【讨论】:

      猜你喜欢
      • 2020-04-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-22
      • 1970-01-01
      • 2018-08-25
      • 2022-01-13
      相关资源
      最近更新 更多