【问题标题】:Python Scrapy web-crawling and scrapingPython Scrapy 网络爬取和抓取
【发布时间】:2017-06-14 20:38:24
【问题描述】:

我正在编写一个 Scrapy Spider 来遍历一个旅游网站。网站结构如下:

Continents
    North America
        USA
            lat: 123
            long: 456
        Canada
            lat: 123
            long: 456
    South America
        Brazil
            lat: 456
            long: 789
        Peru
            lat: 123
            long: 456

我已经弄清楚如何使用下面的脚本抓取每个国家/地区页面并获取纬度/经度信息,但我遇到的困难是存储信息。

import scrapy


class WorldSpider(scrapy.Spider):
    name = "world"

    def start_requests(self):
        urls = [
            'www.world.com'
        ]
        for url in urls:
            # yield scrapy.Request(url=url, callback=self.parse)
            yield scrapy.Request(url=url, callback=self.parse_region)

    def parse(self, response):
        for link in response.css(CONTINENT_SELECTOR):
            continent = link.css('a::attr(href)').extract_first()
            if continent is not None:
                continent = response.urljoin(continent)
                yield response.follow(continent, callback=self.parse_continent)

    def parse_continent(self, continent_response):
        country_urls = continent_response.css(COUNTRY_SELECTOR)
        if len(country_urls) == 0:
            # This if-statement is entered when the Spider is at a country web page (e.g. USA, Canada, etc.).
            # TODO figure out how to store this to text file or append to JSON object
            yield {
                'country': continent_response.css(TITLE_SELECTOR).extract_first(),
                'latitude' : continent_response.css(LATITUDE_SELECTOR).extract_first(),
                'longitude' : continent_response.css(LONGITUDE_SELECTOR).extract_first()
            }

        for link in country_urls:
            country = link.css('a::attr(href)').extract_first()
            if area is not None:
                yield continent_response.follow(continent_response.urljoin(area), callback=self.parse_continent)

如何将此信息写入文件或 JSON 对象?理想情况下,我希望数据结构能够捕捉网站的结构。

示例:

{
    "continents": [
        {"North America" : [
            {"country" : {"title": "USA", "latitude" : 123, "longitude" : 456}},
            {"country" : {"title": "Canada", "latitude" : 123, "longitude" : 456}}
        ]},
        {"South America" : [
            {"country" : {"title": "Brazil", "latitude" : 456, "longitude" : 789}},
            {"Peru" : {"title": "Peru", "latitude" : 123, "longitude" : 456}}
        ]}          
    ]
}

我应该如何修改我的 Spider 以实现上述目标?

【问题讨论】:

  • 你需要a pipeline
  • @Jan 感谢您的意见。我仍在学习 Scrapy,因此了解文档中的内容会很有帮助。谢谢!

标签: python web-scraping scrapy web-crawler scrapy-spider


【解决方案1】:

可以通过两种方式将数据存储在文件中。首先是@Jan 提到的,使用JsonWritePipeline,当scrapy spider 运行多次并且每次都用于追加到文件时,建议使用这种方法。

以下是此类执行的示例:

with open(filename, 'a') as f:
          f.write(response.body)
self.log('Saved file %s' % filename)

虽然最简单的方法是使用Feed Export 选项,这样更容易实现。

Feed Exports,它允许您使用多种序列化格式和存储后端生成包含抓取项目的 Feed。 为了序列化抓取的数据,提要导出使用 Item 出口商。开箱即用支持这些格式:

    JSON
    JSON lines
    CSV
    XML

以下是使用 FileExport 将数据存储为 JSON 文件的示例:

$scrapy crawl myExample -o output.json

注意: Scrapy 附加到给定文件而不是覆盖其内容。如果 您运行此命令两次而不在第二次之前删除文件 到时候,你会得到一个损坏的 JSON 文件。

至于 JSON 中数据的结构,我更喜欢使用Item,因为它为您提供了一个非常清晰的结构,并且具有许多深度 JSON 更适合验证结构。

对于您的实现,结构应声明为:

import scrapy

class Address(scrapy.Item):
    title = scrapy.Field()
    latitude = scrapy.Field()
    longitude = scrapy.Field()

class Place(scrapy.Item):
    country = scrapy.Field()         #object of Address

class Continents(scrapy.Item):
    name = scrapy.Field()             #array of Place

我会让你弄清楚如何实现它;-)

【讨论】:

    【解决方案2】:

    Scrapy 通过 Feed Exports 提供了开箱即用的此功能,它允许您使用多种序列化格式和存储后端生成包含抓取项目的 Feed。

    scrapy crawl WorldSpider -o name.json -t json 
    

    将保存已解析的项目。

    【讨论】:

    • 感谢您的意见。我将在 Scrapy 文档中查看 Feed Exports。
    猜你喜欢
    • 2017-11-14
    • 1970-01-01
    • 1970-01-01
    • 2023-03-30
    • 2014-11-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-04
    相关资源
    最近更新 更多