具体流程分析:
进入热门电影页面
抓取所有电影链接
- 抓取每个电影的标题、评分、首页评论
进入下一页继续递归爬取
Scrapy基本架构:
- 引擎(Scrapy Engine):处理整个系统的数据流,触发事务。
- 调度器(Scheduler):接受引擎发过来的请求,压入调度队列,并在引擎再次请求的时候返回。
- 下载器(Downloader):下载网页内容,并将网页内容返回给蜘蛛。
- 蜘蛛(Spider):定制特定域名或网页的解析规则。
- 项目管道(ItemPipeline):处理由蜘蛛从网页中提取的结构性数据,主要任务是清洗、验证和存储数据。
- 中间件(Middlewares):包括下载器中间件(引擎与下载器之间)、蜘蛛中间件(引擎与蜘蛛之间)、调度中间件(引擎与调度器之间)等。
实战:
创建项目:
1 | scrapy startproject doubanmoviePract |
1 | 文件结构: |
自定义结构性数据:
首先编辑根目录下的items文件,在项目对象下设置自己想要爬取的信息,这里设置了标题、评分、网址链接、首页的评论信息
1 | \doubanmoviePract\doubanmoviePract\items.py |
编写解析网页的spider:
解析网页的spider是位于spider目录下的crawler文件,这里我主要增加了
1 | import scrapy |
首先从豆瓣的/j接口网页中获得热门电影的信息,然后将标题、评分、链接放到字典的不同值里,并且将链接yield给comment_parse进行首页评论的爬取。结构相对比较简单。
这里有几个地方花费了大量的时间理解:
如何让不同的函数对同一对象进行操作
如何在callback回调中传输参数
第一个问题,如何让不同的函数对同一个对象进行操作:
因为面向对象的知识实在是过于久远了,很多东西都还给课本了,我一开始直接按逻辑思路在两个函数中对item的不同属性进行操作,但是操作的前提是有item对象,所以我就在每个方法中都生成了一个item对象,结果是,程序运行后只保留了后一个对象,于是我打算只建一个对象,然后两个函数对同一个对象进行操作,结果是我没法确定应该在哪新建这个对象,因为在哪新建她都给我报错,于是我决定看看怎么把”对对象的操作“放进一个函数里,于是引出了第二个问题,如何在回调中传递参数:
参考链接里的方法是,将parse中的Item对象直接加到request里,然后通过response调出这个对象之后交给other_parse,因为我当时已经在下面写好了item的操作了,所以只把网页信息加到了request里。
自定义数据管道
通常这一步进行的是如何清洗并存储你的数据,这里由于是小规模爬取,我就没有进行数据的存储。
自定义中间件
中间件即项目目录下的middlewares文件,可以实现的功能有很多,这两天大概了解了随机UA和动态ip的使用,由于动态ip比较费劲,而且已经23:54了,我就没接着折腾,随机UA会减缓一定程度的封锁,但是动态ip更吊一些。
1 | class DoubanmoviepractDownloaderMiddleware: |
设置settings
前面设置的pipeline和middlewares在自己定义好后需要从设置里注册并设置优先级:
1 | DOWNLOADER_MIDDLEWARES = { |
这里一个问题就是,在设置随机UA时,要把系统的UA给关掉。以及要把ROBOTSTXT_OBEY 设为False,不然的话,scrapy会遵守目标网站的规则,而通常,目标网站是不会让普通机器人爬取信息的。
启动spider
1 | scrapy crawl crawler -o re.csv |
因为没有设置数据存储的中间件,所以在启动程序的时候,直接 ”-o 目标文件“即可输出定义的值。
检查爬虫结果:
1 | {'first_p_comment': ['<span ' |
这里没有进行数据清洗,所以还有很多html标签。
源码
由于只是个小demo,代码也还有很多需要改善的地方,主要有两点,一个是数据清洗,一个是动态ip的设置,所以就不贴代码了。