scrapy根据第一层页面的链接爬取第二层后,第一层的内容没有保存

2016年统计用区划代码和城乡划分代码

新手开始学习scrapy爬虫,拿国家统计局的这个地区划分的网页来练手。
最终目标是:把地区信息按照province->city->country->town的4层存入数据库(网站上5层,但数据量太大了,只打算爬4层),在同一张表中,按级别从高到低入库,自增主键,低级的区域通过parent_id关联上级地区。


目前打算先把省和市的信息爬出来,也不搞数据库,就以json格式导出就好。
但是一旦从省的页面获取到的各省子页面的url,进去爬市的信息,前面的省的信息就不保存了。
scrapy是自己摸索的,可能一开始就把框架理解错了,望大神指出。

import scrapy
from scrapy_test.items import RegionalismItem


class RegionalismSpider(scrapy.Spider):
    name = 'regionalism'

    def parse(self, response):
        pass

    def start_requests(self):
        url = 'http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2016/index.html'
        yield scrapy.Request(url=url, callback=self.parse_province)

    def parse_province(self, response):
        provinces = response.css('tr.provincetr > td')
        items = []
        for province in provinces:
            item = RegionalismItem()
            item['name'] = province.css('a::text').extract_first().strip()
            item['url'] = response.urljoin(province.xpath('a/@href').extract_first().strip())
            items.append(item)
            yield scrapy.Request(item['url'], callback=self.parse_city)
        yield items

    def parse_city(self, response):
        citys = response.css('tr.citytr > td:nth-child(2)')
        items = []
        for city in citys:
            item = RegionalismItem()
            item['name'] = city.css('a::text').extract_first().strip()
            item['url'] = response.urljoin(city.xpath('a/@href').extract_first().strip())
            # yield scrapy.Request(item['url'], callback=self.parse_country)
            items.append(item)
        yield items

无论yield和return怎么改来改去,要么就是什么都没有,要么就是只有市的信息,没有省。
请问错误在哪里?

阅读 8.6k
3 个回答
新手上路,请多包涵

看了一下代码,约摸估计就是Item返回值的问题。
就是

items = []
for ...:
    item = RegionalismItem()
    ...
    items.append(item)
    ...
yield items

这部分。

测试了一下,运行中出现这样的错误,验证了我的猜想。
ERROR: Spider must return Request, BaseItem, dict or None, got 'list' in <GET http://www.stats.gov.cn/tjsj/...;

简单地说就是数据抓到了,但你返回的形式有问题,不应该以list的形式返回。

返回值 items=[item1,item2,item3,...] 是不被scrapy接受的,你如果直接返回item就不会出这样的问题。

建议直接改成:

for ...:
    item = RegionalismItem()
    ...
    yield item

我试了一下,修改之后可以正常抓取数据并保存为json文件。

scrapy声明字段的时候是这样的:

class ScrapyTestItem(scrapy.Item):
    # define the fields for your item here like:
    name = scrapy.Field()

源码里,field是继承了dict

class Field(dict):
    """Container of field metadata"""

因此,定义的字段信息是字典dict类型的,而你自定义了一个列表并yield返回自然就不行了。

回调函数有如下定义:

clipboard.png

可以去掉items,直接yield item

yield scrapy.Request(item['url'], callback=self.parse_city)

yield scrapy.Request(url=url, callback=self.parse_province)
修改成
yield from scrapy.Request(item['url'], callback=self.parse_city)

yield from scrapy.Request(url=url, callback=self.parse_province)

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题