开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第32天,点击查看活动详情
事前准备
该案例主要用来学习items.py和pipelines.py的使用。还是老方法,先创建项目框架,然后创建自定义的爬虫文件。
scrapy startproject scrapy_dang
cd .\scrapy_dang\scrapy_dang\spiders\
scrapy genspider dang http://category.dangdang.com/cp01.54.06.19.00.00.html
创建完成之后,先修改下目标地址,还有定位到我们需要的数据标签。
import scrapy
class DangSpider(scrapy.Spider):
name = 'dang'
allowed_domains = ['category.dangdang.com']
start_urls = ['http://category.dangdang.com/cp01.54.06.19.00.00.html']
def parse(self, response):
li_list = response.xpath('.//ul[@class="bigimg"]/li')
for li in li_list:
src = li.xpath('.//img/@data-original').extract_first()
if src is None:
src = li.xpath('.//img/@src').extract_first()
name = li.xpath('./a/@title').extract_first()
price = li.xpath('.//span[@class="search_now_price"]/text()').extract_first()
print(src, name, price)
items
数据拿到了,我们就需要使用items来自定义所需的一个数据格式了。通过scrapy.Field()将我们自定义的字段添加上即可。
class ScrapyDangItem(scrapy.Item):
src = scrapy.Field()
name = scrapy.Field()
price = scrapy.Field()
定义完成之后,我们在自定义的爬虫文件中传入获取到的数据。
- 引入
items,这里由报错不用管它,编译器显示错误,实际可以运行的
from scrapy_dang.items import ScrapyDangItem
- 传入参数
ScrapyDangItem(src=src, name=name, price=price)
pipelines
数据格式定义好了,那么就到了保存环节了。我们可以直接在pipelines文件中写保存操作。
class ScrapyDangPipeline:
def process_item(self, item, spider):
fp = open('books.json', 'a', encoding='utf-8')
fp.write(str(item))
return item
对了,这里记得一定要去settings文件中开启pipelines的启动开关并设置优先级。
将注释放开即可。
yield
目前到这里还不行,我们还少了最重要的一步,将数据交给pipelines。这就需要用到yield关键字了,该关键字主要有:
- 带
yield的函数是一个generator生成器,可用于迭代 - 其类似于
return关键字,它返回一个值,并且记住返回的位置,下次就从该位置后面开始。
book = ScrapyDangItem(src=src, name=name, price=price)
yield book
scrapy crawl dang
pipelines的前置/后置
运行之后可以看到多出来一个json文件,里面就有我们所需的数据了。但是这样的方式有很大问题,频繁的开启输入输出流,影响效率。我们可通过pipelines的前置函数与后置函数来实现一次开启,多次写入操作。
class ScrapyDangPipeline:
def open_spider(self, spider):
self.fp = open('books.json', 'w', encoding='utf-8')
def process_item(self, item, spider):
self.fp.write(str(item))
return item
def close_spider(self, spider):
self.fp.close()
多页数据爬取
通过srcapy.Request()函数,我们可以重新发起请求,在请求中替换掉url属性即可实现翻页爬取。
import scrapy
from scrapy_dang.items import ScrapyDangItem
class DangSpider(scrapy.Spider):
name = 'dang'
allowed_domains = ['category.dangdang.com']
start_urls = ['http://category.dangdang.com/cp01.54.06.19.00.00.html']
head_url = 'http://category.dangdang.com/pg'
page = 1
tail_url = '-cp01.54.06.19.00.00.html'
def parse(self, response):
li_list = response.xpath('.//ul[@class="bigimg"]/li')
for li in li_list:
src = li.xpath('.//img/@data-original').extract_first()
if src is None:
src = li.xpath('.//img/@src').extract_first()
name = li.xpath('./a/@title').extract_first()
price = li.xpath('.//span[@class="search_now_price"]/text()').extract_first()
print(src, name, price)
book = ScrapyDangItem(src=src, name=name, price=price)
yield book
if self.page < 5:
self.page = self.page + 1
url = self.head_url + str(self.page) + self.tail_url
yield scrapy.Request(url=url, callback=self.parse)
原先一页60条数据大概是240行左右,现在爬取了5页,1200左右可以匹配上。