Scrapy是一个非常强大的爬虫框架,只需极少代码便可应付一个简单爬虫。
但如果需要几十万几百万的数据量,中间一旦有中断,重新爬取则太浪费时间。
本文介绍一种思路,结合mysql,实现断点重爬的方式。
以国外美食网站Yelp为例,指定爬取香港的所有餐厅信息:餐厅名称、地址、评价等信息。
任务分析
首先我们找到Yelp香港餐厅的列表页面,这个页面是我们的起始页面,对我们有用的信息为:餐厅列表和跳转页码。
列表页面展示餐厅列表
餐厅列表和跳转页码
点击进入餐厅的详情页面,可以看到基本信息和用户评论,这里需要注意评论是区分语言的
详情页面展示餐厅的详情及用户评论
Scrapy项目结构
.
├── README.md
└── yelp
├── __init__.py
├── scrapy.cfg
└── yelp
├── __init__.py
├── items.py
├── middlewares.py
├── pipelines.py
├── settings.py
└── spiders
├── YelpSpider.py
└── __init__.py
这就是一个普通的Scrapy爬虫的项目结构,本文主要介绍如何实现断点续爬,所以如何获取详细字段内容的方式可以直接查看源码。
断点续爬的实现
由于我们需要断点续爬,那么就必须要在某一个时刻记录当前的爬虫状态,哪些页面已经爬过,哪些还没有爬过。
我们将每一个需要爬取的页面抽象为一个爬虫任务,从该页面获取数据完成则认为该任务完成。设计这个任务的数据结构:
class TaskBean(base):
__tablename__ = 'yelp_tasks'
id = Column(Integer, primary_key=True) # 任务ID
city = Column(String(256), nullable=False)
url = Column(String(1024), nullable=False) # 爬虫任务的URL
is_finished = Column(Boolean, default=False) # 标记该页面是否已经爬过
parent_id = Column(Integer, default=-1) # 父任务的ID,这样所有任务形成一棵树
type = Column(Integer) # 任务类型,1. 页面列表任务 2. 餐厅详情任务 3. 评论任务
def to_dict(self):
return {'task_id': self.id, 'city': self.city, 'url': self.url, 'is_finished': self.is_finished,