首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

Python爬虫-scrapy-爬取豆瓣电影TOP250

前言

新接触爬虫,经过一段时间的实践,写了几个简单爬虫,爬取豆瓣电影的爬虫例子网上有很多,但都很简单,大部分只介绍了请求页面和解析部分,对于新手而言,我希望能够有一个比较全面的实例。所以找了很多实例和文章,并整合在一起,在现有豆瓣爬虫的基础上,增加了一些内容,算是比较全的内容了。主要包括项目建立、请求页面、xpath解析、自动翻页、数据输出、编码处理等等。。

系统环境

System Version:Ubuntu 16.04

Python Version:3.5.2

Scrapy Version:1.5.0

1.建立项目

执行如下命令建立scrapy爬虫项目

scrapy startproject spider_douban

命令执行完成后,建立了spider_douban文件夹,目录结构如下:

.

├── scrapy.cfg

└── spiderdouban

├──init.py

├── items.py

├── middlewares.py

├── pipelines.py

├── settings.py

└── spiders

├── doubanspider.py

└── __init.py

2.建立爬虫数据模型

打开./spider_douban/items.py文件,编辑内容如下:

3.新建爬虫文件

新建./spiders/douban_spider.py文件,编辑内容如下:

爬虫文件各部分功能记录

douban_spider.py文件主要有几部分构成。

导入模块

Request类用于请求要爬取的页面数据

Spider类是爬虫的基类

DoubanMovieItem是我们第一步建立的爬取数据模型

初始设置

基于spider类定义的爬虫类DoubanMovieTop250Spider中,首先定义爬虫的基本信息:

name:在项目中爬虫的名称,可以在项目目录中执行scrapy list获取已经定义的爬虫列表

start_urls:是爬取的第一个页面地址

headers:是向web服务器发送页面请求的时候附加的user-agent消息,告诉web服务器是什么类型的浏览器或设备在请求页面,对于不具备简单反爬机制的网站,headers部分可以省略。

为了迷惑web服务器,一般会在爬虫发送web请求的时候定义user-agent信息,这里有两种写法。

header的第一种定义:

可以看到,这种写法中,start_urls定义没有了,转而定义了start_requests函数,开始的url写到了函数里。同时,定义了headers字典,在发送Request请求的时候,将headers字典一并发送。这种写法简单直观,缺点是在一个爬虫项目执行期间,所有请求都是一个User-Agent属性。

header的第二种定义:

简单、直接的定义start_urls属性,而Request中的header属性通过其他方法另外定义,容后再说。

parse处理函数

逐句分解说明

1.基于我们定义的DoubanMovieItem类创建item实例

item = DoubanMovieItem()

2.解析页面 - 获取内容框架

通过分析页面源码,我们能够看到,页面中的电影信息是保存在了标签中,这个标签有一个独特的样式表,而每一个单独的电影信息保存在了标签中,下面代码获取属性为的标签下的所有标签内容。

movies = response.xpath(‘//ol[@class=”grid_view”]/li’)

3.解析页面 - 获取分项

在每一个标签中,还有内部结构,通过xpath()解析,将每一项内容解析出来,赋值给item实例中的各个字段。通过查看页面的源码可以很容易找到这个标签定义的内容。如果我们通过type()函数查看movies的变量类型,可以发现他的类型是。标签中的每一个标签都是这个列表中的一项,那么就可以对movies做迭代。

首先看看标签中的页面结构:

可以看到要提取数据的各部分所在标签位置:

排名:class属性为pic的

标签下,,标签中...

电影名:class属性为hd的

标签下,标签中的第一个标签...

评分:class属性为star的

标签下,class属性为rating_num的标签中...

评论人数:class属性为star的

标签下,标签中。由于使用了re正则表达式,所以没有特别指定是哪一个标签。

回到代码部分,对之前定义的movies做迭代,逐项获取要抓取的数据。

4.Url跳转(翻页)

如果到此为止,我们可以将https://movie.douban.com/top250页面中的第一页内容爬取到,但只有25项记录,要爬取全部的250条记录,就要执行下面代码:

首先通过xpath解析了页面中后页的链接,并赋值给next_url变量,如果我们当前在第一页,那么解析后页的链接就是?start=25&filter=。将解析的后页链接与完整url连接形成完整的地址,再次执行Request(),就实现了对全部250条记录的爬取。注意:通过xpath解析出的结果是列表,所以在引用的时候写成next_url[0]。

处理随机Head属性(随机User-Agent)

实现随机的head属性发送。主要改两个文件:

settings.py

USER_AGENT_LIST定义了一些浏览器user-agent属性,网上有很多,可以找来直接加进去,需要注意的是有些user-agent信息是移动设备(手机或平板)的,如果不注意的话,可能请求到的数据与你看到的数据有较大差异;

DOWNLOADER_MIDDLEWARES定义了下载器中间件,它在发送页面请求数据的时候被调用。

middlewares.py

在RandomUserAgentMiddleware()中,每次发送请求数据,会在USER_AGENT_LIST中随机选择一条User-Agent记录。

结果保存

编辑pipelines.py文件:

SpiderDoubanPipeline类是建立项目的时候自行建立的,为了保存文件,做了修改。

def from_crawler(cls, crawler):

如果存在,则调用此类方法从Crawler创建pipeline实例。它必须返回一个新的pipeline实例。抓取对象提供对所有Scrapy核心组件的访问,如settings和signals; 这是pipeline访问它们并将其功能挂接到Scrapy的一种方式。

在此方法中,定义了一个数据收集器(cls)的实例:‘pipeline’。

signals:Scrapy使用信号来通知事情发生。您可以在您的Scrapy项目中捕捉一些信号(使用 extension)来完成额外的工作或添加额外的功能,扩展Scrapy。虽然信号提供了一些参数,不过处理函数不用接收所有的参数 - 信号分发机制(singal dispatching mechanism)仅仅提供处理器(handler)接受的参数。您可以通过 信号(Signals) API 来连接(或发送您自己的)信号。

connect:链接一个接收器函数(receiver function) 到一个信号(signal)。signal可以是任何对象,虽然Scrapy提供了一些预先定义好的信号。

def spider_opened(self, spider):

当spider开始爬取时发送该信号。该信号一般用来分配spider的资源,不过其也能做任何事。该信号支持返回deferreds。

此方法中,创建了一个文件对象实例:savefile。

CsvItemExporter(savefile):输出 csv 文件格式. 如果添加 fields_to_export 属性, 它会按顺序定义CSV的列名.

def spider_closed(self, spider):

当某个spider被关闭时,该信号被发送。该信号可以用来释放每个spider在 spider_opened 时占用的资源。该信号支持返回deferreds。

def process_item(self, item, spider):

每个item pipeline组件都需要调用该方法,这个方法必须返回一个 Item (或任何继承类)对象, 或是抛出 DropItem 异常,被丢弃的item将不会被之后的pipeline组件所处理。

启用pipeline

为了让我们定义的pipeline生效,要在settings.py文件中,打开ITEM_PIPELINES注释:

执行爬虫

执行爬虫能够看到爬取到的数据。。。

如果之前pipeline部分代码没有写,也可以用下面的命令,在爬虫执行的时候直接导出数据:

增加-o参数,可以将爬取到的数据保存到douban.csv文件中。。

文件编码的问题

我在linux服务器执行爬虫,生成csv文件后,在win7系统中用excel打开变成乱码。在网上找了一些文章,有的文章直接改变linux文件默认编码,但是感觉这么做会对其他项目产生影响。最后选择一个相对简单的方式。按这几步执行就可以:

不要直接用excel打开csv文件。先打开excel,建立空白工作表。

选择数据选项卡,打开获取外部数据中的自文本。

在导入文本文件对话框中选择要导入的csv文件。

在文本导入向导 - 第1步中,设置文件原始格式为65001 : Unicode (UTF-8)

继续下一步选择逗号分隔,就可以导入正常文本了。

作者:Jero来源:https://segmentfault.com/a/1190000013268442

学习Python和网络爬虫关注公众号:datanami

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180301B04Z6G00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券