简介
本文主要介绍crawlspider爬取豆瓣近一周同城活动。
要点:item/itemloader利用input_processor/output_processor对爬取的数据进行过滤。
实现
为了演示数据过滤,我们只爬取到第二页的数据。
一、定义item
vim items.py
class tongcheng(scrapy.Item):
#主题
title = scrapy.Field()
#时间
time = scrapy.Field()
#地址
address = scrapy.Field(output_processor=Join())
#票价
money = scrapy.Field()
#感兴趣人数
intrest = scrapy.Field()
#参加人数
join = scrapy.Field()
二、定义爬虫
# -*- coding: utf-8 -*-
#爬取豆瓣近一周同城活动
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from scrapy.loader import ItemLoader
from douban.items import tongcheng
class TongchengSpider(CrawlSpider):
name = 'tongcheng'
allowed_domains = ['douban.com']
start_urls = ['https://www.douban.com/location/shenzhen/events/week-all']
rules = (
#匹配到第二页
Rule(LinkExtractor(allow=r'start=10')),
#获取每页数据
Rule(LinkExtractor(allow=r'https://www.douban.com/event/\d+/'),callback='parse_item'),
)
def parse_item(self, response):
loader = ItemLoader(item=tongcheng(),selector=response)
info = loader.nested_xpath('//div[@class="event-info"]')
info.add_xpath('title','h1[@itemprop="summary"]/text()')
info.add_xpath('time','div[@class="event-detail"]/ul[@class="calendar-strs"]/li/text()')
info.add_xpath('address','div[@itemprop="location"]/span[@class="micro-address"]/span[@class="micro-address"]/text()')
info.add_xpath('money','div[@class="event-detail"]/span[@itemprop="ticketAggregate"]/text()')
info.add_xpath('intrest','div[@class="interest-attend pl"]/span[1]/text()')
info.add_xpath('join','div[@class="interest-attend pl"]/span[3]/text()')
yield loader.load_item()
三、执行爬虫
scrapy crawl toncheng -o tongcheng.json
vi toncheng.json
[
{"money": ["费用: \n 100元(预售)起\n "], "address": "深圳 南山区 华侨城创意园 北区C2栋北侧 B10现场", "join": ["65 "], "intrest": ["63 "], "title": ["张玮玮和郭龙“沿江而来”巡演深圳站 @B10现场\n\n\n "]},
{"money": ["费用: \n \n 93 - 281元\n "], "address": "深圳 南山文体中心剧院 小剧场 深圳市南山区南山大>道南山文体中心", "join": ["0 "], "intrest": ["1 "], "title": ["2018第五届城市戏剧节 以色列国宝级作家名著改编 王子川自导自演《雅各比和雷弹头》-深圳\n\n\n "]},
{"money": ["费用: \n \n 95 - 361元\n "], "address": "深圳 南山文体中心剧院大剧院 南山大道与南头街交汇
处南山文体中心", "join": ["6 "], "intrest": ["10 "], "title": ["【万有音乐系】My Song--Sophie Zelmani 苏菲 · 珊曼妮2018巡回演唱会\n\n\n "]},
{"money": ["费用: \n \n 263 - 357元\n "], "address": "深圳 深圳市少年宫剧场 深圳市福田区福中一路市少>年宫", "join": ["67 "], "intrest": ["158 "], "title": ["孟京辉戏剧作品《一个陌生女人的来信》深圳站\n\n\n "]},
{"money": ["费用: \n \n 170 - 483元\n "], "address": "深圳 华润深圳湾体育中心"春茧"体育场 深圳市滨>海大道3001号(南山区科苑南路与海德三道交汇处)", "join": ["37 "], "intrest": ["66 "], "title": ["亚洲之巅群星演唱会-深圳站\n ", "\n\n\n "]},
......
]
从上面的输出我们看到:
title字段带空格,我们需要的是去除空格的数据;
money字段是[“费用: \n \n 263 - 357元\n “],我们需要的是[”263 - 357元”];
我们需要使用item/itemloader的input_processor/output_processor对数据进行过滤,例如我们已经对address字段使用了output_processor=Join(),我们还需使用MapCompose方法进行过滤。
四、MapCompose
class scrapy.loader.processors.MapCompose(*functions, **default_loader_context)
MapCompose方法接受的数据是可迭代的,数据会经过第一个function进行处理,生成的新的迭代数据会进入第二个函数,以此类推直至所有函数都处理完,生成最终的迭代数据。
1、title字段
title字段需要unicode.strip去处空格,在item中定义如下:
title = scrapy.Field(input_processor=MapCompose(unicode.strip))
MapCompose通常被用作input_processor,因为我们用selector提取返回的的是可迭代数据。
另外scrapy 会将含有中文的field输出为 unicode字符串形式,因此我们使用unicode.strip来去除空格。
2、money字段
money字段提取的是[“费用: \n \n 263 - 357元\n “],我们只要”263 - 357元”。具体实现如下:
vim items.py
def filter_string(x):
str = x.split(':')
return str[1].strip()
money = scrapy.Field(input_processor=MapCompose(filter_string))
filter_string函数的功能就是提取263 - 357元。我们通过MapCompose中调用filter_string,将提取的数据过滤为我们想要的数据。
因此,完整的item代码如下:
# -*- coding: utf-8 -*-
import scrapy
from scrapy.loader.processors import Join, MapCompose, TakeFirst
def filter_string(x):
str = x.split(':')
return str[1].strip()
class tongcheng(scrapy.Item):
title = scrapy.Field(input_processor=MapCompose(unicode.strip))
time = scrapy.Field()
address = scrapy.Field(output_processor=Join())
money = scrapy.Field(input_processor=MapCompose(filter_string))
intrest = scrapy.Field()
join = scrapy.Field()
通过定义item后,我们最终提取的数据如下:
[
{"money": ["100元(预售)起"], "address": "深圳 南山区 华侨城创意园 北区C2栋北侧 B10现场", "join": ["65 "], "intrest": ["63 "], "title": ["张玮玮和郭>龙“沿江而来”巡演深圳站 @B10现场"]},
{"money": ["93 - 281元"], "address": "深圳 南山文体中心剧院 小剧场 深圳市南山区南山大道南山文体中心", "join": ["0 "], "intrest": ["1 "], "title": ["2018第五届城市戏剧节 以色列国宝级作家名著改编 王子川自导自演《雅各比和雷弹头》-深圳"]},
{"money": ["95 - 361元"], "address": "深圳 南山文体中心剧院大剧院 南山大道与南头街交汇处南山文体中心", "join": ["6 "], "intrest": ["10 "], "title": ["【万有音乐系】My Song--Sophie Zelmani 苏菲 · 珊曼妮2018巡回演唱会"]},
{"money": ["263 - 357元"], "address": "深圳 深圳市少年宫剧场 深圳市福田区福中一路市少年宫", "join": ["67 "], "intrest": ["158 "], "title": ["孟京辉戏
剧作品《一个陌生女人的来信》深圳站"]},
{"money": ["170 - 483元"], "address": "深圳 华润深圳湾体育中心"春茧"体育场 深圳市滨海大道3001号(南山区科苑南路与海德三道交汇处)", "join": ["37 "], "intrest": ["66 "], "title": ["亚洲之巅群星演唱会-深圳站", ""]},
{"money": ["59元"], "address": "深圳 海上世界文化艺术中心 深圳市南山区蛇口望海路1187号", "join": ["80 "], "intrest": ["116 "], "title": ["设计互联开>幕大展——“数字之维”及“设计的价值”展览"]},
.....
]