Python利用Scrapy框架爬取豆瓣电影示例


Posted in Python onJanuary 17, 2020

本文实例讲述了Python利用Scrapy框架爬取豆瓣电影。分享给大家供大家参考,具体如下:

1、概念

Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架。 可以应用在包括数据挖掘,信息处理或存储历史数据等一系列的程序中。

通过Python包管理工具可以很便捷地对scrapy进行安装,如果在安装中报错提示缺少依赖的包,那就通过pip安装所缺的包

pip install scrapy

scrapy的组成结构如下图所示

Python利用Scrapy框架爬取豆瓣电影示例

引擎Scrapy Engine,用于中转调度其他部分的信号和数据传递

调度器Scheduler,一个存储Request的队列,引擎将请求的连接发送给Scheduler,它将请求进行排队,但引擎需要时再将队列中的第一个请求发送给引擎

下载器Downloader,引擎将请求Request链接发送给Downloader之后它就从互联网上下载相应的数据,并将返回的数据Responses交给引擎

爬虫Spiders,引擎将下载的Responses数据交给Spiders进行解析,提取我们需要的网页信息。如果在解析中发现有新的所需要的url连接,Spiders会将链接交给引擎存入调度器

管道Item Pipline,爬虫会将页面中的数据通过引擎交给管道做进一步处理,进行过滤、存储等操作

下载中间件Downloader Middlewares,自定义扩展组件,用于在请求页面时封装代理、http请求头等操作

爬虫中间件Spider Middlewares,用于对进入Spiders的Responses和出去的Requests等数据作一些修改

scrapy的工作流程:首先我们将入口url交给spider爬虫,爬虫通过引擎将url放入调度器,经调度器排队之后返回第一个请求Request,引擎再将请求转交给下载器进行下载,下载好的数据交给爬虫进行爬取,爬取的数据一部分是我们需要的数据交给管道进行数据清洗和存储,还有一部分是新的url连接会再次交给调度器,之后再循环进行数据爬取

2、新建Scrapy项目

首先在存放项目的文件夹内打开命令行,在命令行下输入scrapy startproject 项目名称,就会在当前文件夹自动创建项目所需的python文件,例如创建一个爬取豆瓣电影的项目douban,其目录结构如下:

Db_Project/
  scrapy.cfg        --项目的配置文件
  douban/          --该项目的python模块目录,在其中编写python代码
    __init__.py      --python包的初始化文件
    items.py       --用于定义item数据结构
    pipelines.py     --项目中的pipelines文件
    settings.py      --定义项目的全局设置,例如下载延迟、并发量
    spiders/       --存放爬虫代码的包目录
      __init__.py
      ...

之后进入spiders目录下输入scrapy genspider 爬虫名 域名,就会生成爬虫文件douban.py文件,用于之后定义爬虫的爬取逻辑和正则表达式等内容

scrapy genspider douban movie.douban.com

3、定义数据

要爬取的豆瓣电影网址为 https://movie.douban.com/top250,其中的每个电影如下

Python利用Scrapy框架爬取豆瓣电影示例

我们要爬取其中的序号、名称、介绍、星级、评论数、描述这几个关键信息,因此需要在管道文件items.py中先定义这几个对象,类似于ORM,通过scrapy.Field()方法为每个字段定义一个数据类型

import scrapy
 
 
class DoubanItem(scrapy.Item):
  ranking = scrapy.Field()  # 排名
  name = scrapy.Field()  # 电影名
  introduce = scrapy.Field() # 简介
  star = scrapy.Field()  # 星级
  comments = scrapy.Field()  # 评论数
  describe = scrapy.Field()  # 描述

4、数据爬取

打开之前在spiders文件夹下创建的爬虫文件movie.py如下所示,以及自动创建了三个变量和一个方法,在parse方法中进行返回数据response的处理,我们需要在start_urls提供爬虫的入口地址。注意爬虫会自动过滤掉allowed_domains之外的域名,因此需要注意这个变量的赋值

# spiders/movie.py
import scrapy
 
 
class MovieSpider(scrapy.Spider):
  # 爬虫名
  name = 'movie'
  # 允许爬取的域名
  allowed_domains = ['movie.douban.com']
  # 入口url
  start_urls = ['https://movie.douban.com/top250']
 
  def parse(self, response):
    pass

在进行数据爬取之前首先要设置一些网络代理,在settings.py文件内找到USER_AGENT变量修改如下:

USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:70.0) Gecko/20100101 Firefox/70.0'

可以在命令行通过如下命令启动名为douban的爬虫:scrapy crawl douban,也可以编写一个启动文件run.py文件如下,运行即可

from scrapy import cmdline
cmdline.execute('scrapy crawl movie'.split())

接下来要对爬取到的数据进行过滤,通过Xpath规则可以使我们便捷地选中网页中的指定元素,如下图所示,每个电影条目都包裹在<ol class="grid_view">下的一个<li>标签,因此通过xpath://ol[@class='grid_view']/li 就选中了本页面所有的电影条目。可以通过谷歌浏览器的Xpath插件或者火狐浏览器的ChroPath获得xpath值,在浏览器右键查看元素,弹出如下图所示的开发者工具,其中最右边就是ChroPath插件,它直观地显示了元素的Xpath值: //div[@id='wrapper']//li
 

Python利用Scrapy框架爬取豆瓣电影示例

爬虫response对象的xpath()方法可以直接处理xpath规则字符串并返回对应的页面内容,这些内容都是选择器对象Selector,可以进一步作细化的内容选取,通过xpath选择出其中的电影名字、简介、评价、星级等内容,即之前在items.py文件中所定义的数据结构DoubanItem。循环遍历每个电影列表从其中爬取到准确的电影信息,并保存为DoubanItem对象item,最后通过yield将item对象从Spiders返回到Item管道。

爬虫除了从页面提取Item数据之外还会爬取url链接从而形成下一页的Request请求,如下图所示为豆瓣页面底部的下一页信息,第二页的参数为"?start=25&filter=",与网站地址https://movie.douban.com/top250拼接起来就可以得到下一页面的地址。和上面一样通过xpath提取该内容,如果不为空,则拼接得到的Request请求yield提交给调度器

Python利用Scrapy框架爬取豆瓣电影示例

最终的爬虫movie.py文件如下

# -*- coding: utf-8 -*-
import scrapy
from items import DoubanItem
 
 
class MovieSpider(scrapy.Spider):
  # 爬虫名
  name = 'movie'
  # 爬取网站的域名
  allowed_domains = ['movie.douban.com']
  # 入口url
  start_urls = ['https://movie.douban.com/top250']
 
  def parse(self, response):
    # 首先抓取电影列表
    movie_list = response.xpath("//ol[@class='grid_view']/li")
    for selector in movie_list:
      # 遍历每个电影列表,从其中精准抓取所需要的信息并保存为item对象
      item = DoubanItem()
      item['ranking'] = selector.xpath(".//div[@class='pic']/em/text()").extract_first()
      item['name'] = selector.xpath(".//span[@class='title']/text()").extract_first()
      text = selector.xpath(".//div[@class='bd']/p[1]/text()").extract()
      intro = ""
      for s in text: # 将简介放到一个字符串
        intro += "".join(s.split()) # 去掉空格
      item['introduce'] = intro
      item['star'] = selector.css('.rating_num::text').extract_first()
      item['comments'] = selector.xpath(".//div[@class='star']/span[4]/text()").extract_first()
      item['describe'] = selector.xpath(".//span[@class='inq']/text()").extract_first()
      # print(item)
      yield item # 将结果item对象返回给Item管道
    # 爬取网页中的下一个页面url信息
    next_link = response.xpath("//span[@class='next']/a[1]/@href").extract_first()
    if next_link:
      next_link = "https://movie.douban.com/top250" + next_link
      print(next_link)
      # 将Request请求提交给调度器
      yield scrapy.Request(next_link, callback=self.parse)

xpath选择器

/表示从当前位置的下一级目录进行寻找,//表示从当前位置的任意一级子目录进行寻找,

默认从根目录开始查找,. 代表从当前目录开始查找,@后跟标签属性,text()函数代表取出文字内容

//div[@id='wrapper']//li  代表先从根目录开始查找id为wrapper的div标签,然后取出其下的所有li标签

.//div[@class='pic']/em[1]/text()  代表从当前选择器目录开始查找所有class为pic的div之下的第一个em标签,取出文字内容

string(//div[@id='endText']/p[position()>1]) 代表选取id为endText的div下第二个p标签之后的所有文字内容

/bookstore/book[last()-2] 选取属于 bookstore 子元素的倒数第3个 book 元素。

CSS选择器

还可以使用css选择器来选择页面内的元素,其通过CSS伪类的方式表达选择的元素,使用如下

# 选择类名为left的div下的p标签中的文字
response.css('div.left p::text').extract_first()
 
# 选取id为tag的元素下类名为star元素中的文字
response.css('#tag .star::text').extract_first()

5、数据保存

在运行爬虫文件时通过参数-o指定文件保存的位置即可,可以根据文件后缀名选择保存为json或者csv文件,例如

scrapy crawl movie -o data.csv

还可以piplines.py文件中对取得的Item数据作进一步操作从而通过python操作将其保存到数据库中

6、中间件设置

有时为了应对网站的反爬虫机制,需要对下载中间件进行一些伪装设置,包括使用IP代理和代理user-agent方式,在middlewares.py文件中新建一个user_agent类用于为请求头添加用户列表,从网上查一些常用的用户代理放入USER_AGENT_LIST列表,然后通过random函数从中随机抽取一个作为代理,设置为reques请求头的User_Agent字段

class user_agent(object):
  def process_request(self, request, spider):
    # user agent 列表
    USER_AGENT_LIST = [
      'MSIE (MSIE 6.0; X11; Linux; i686) Opera 7.23',
      'Opera/9.20 (Macintosh; Intel Mac OS X; U; en)',
      'Opera/9.0 (Macintosh; PPC Mac OS X; U; en)',
      'iTunes/9.0.3 (Macintosh; U; Intel Mac OS X 10_6_2; en-ca)',
      'Mozilla/4.76 [en_jp] (X11; U; SunOS 5.8 sun4u)',
      'iTunes/4.2 (Macintosh; U; PPC Mac OS X 10.2)',
      'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:5.0) Gecko/20100101 Firefox/5.0',
      'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:9.0) Gecko/20100101 Firefox/9.0',
      'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20120813 Firefox/16.0',
      'Mozilla/4.77 [en] (X11; I; IRIX;64 6.5 IP30)',
      'Mozilla/4.8 [en] (X11; U; SunOS; 5.7 sun4u)'
    ]
    agent = random.choice(USER_AGENT_LIST) # 从上面列表中随机抽取一个代理
    request.headers['User_Agent'] = agent # 设置请求头的用户代理

在settings.py文件内设置开启下载中间件即取消如下几行的注释,注册代理类user_agent并设置优先级,数字越小优先级越高

Python利用Scrapy框架爬取豆瓣电影示例

更多关于Python相关内容可查看本站专题:《Python Socket编程技巧总结》、《Python正则表达式用法总结》、《Python数据结构与算法教程》、《Python函数使用技巧总结》、《Python字符串操作技巧汇总》、《Python入门与进阶经典教程》及《Python文件与目录操作技巧汇总》

希望本文所述对大家Python程序设计有所帮助。

Python 相关文章推荐
python类和函数中使用静态变量的方法
May 09 Python
python实现获取Ip归属地等信息
Aug 27 Python
Linux下为不同版本python安装第三方库
Aug 31 Python
Python爬虫实例爬取网站搞笑段子
Nov 08 Python
Tesserocr库的正确安装方式
Oct 19 Python
Pandas读写CSV文件的方法示例
Mar 27 Python
python操作openpyxl导出Excel 设置单元格格式及合并处理代码实例
Aug 27 Python
python django生成迁移文件的实例
Aug 31 Python
详解python itertools功能
Feb 07 Python
python实现logistic分类算法代码
Feb 28 Python
Python环境管理virtualenv&amp;virtualenvwrapper的配置详解
Jul 01 Python
Python中如何处理常见报错
Jan 18 Python
Python下利用BeautifulSoup解析HTML的实现
Jan 17 #Python
pytorch forward两个参数实例
Jan 17 #Python
Python实现CNN的多通道输入实例
Jan 17 #Python
Python面向对象编程基础实例分析
Jan 17 #Python
通过python实现windows桌面截图代码实例
Jan 17 #Python
PyTorch加载预训练模型实例(pretrained)
Jan 17 #Python
python 正则表达式参数替换实例详解
Jan 17 #Python
You might like
全国FM电台频率大全 - 30 宁夏回族自治区
2020/03/11 无线电
curl不使用文件存取cookie php使用curl获取cookie示例
2014/01/26 PHP
php编写的一个E-mail验证类
2015/03/25 PHP
PHP之密码加密的几种方式
2015/07/29 PHP
10个超级有用的PHP代码片段果断收藏
2015/09/23 PHP
使用phpexcel类实现excel导入mysql数据库功能(实例代码)
2016/05/12 PHP
PHP实现防止表单重复提交功能【基于token验证】
2018/05/24 PHP
Laravel框架路由管理简单示例
2019/05/07 PHP
模仿JQuery.extend函数扩展自己对象的js代码
2009/12/09 Javascript
Jquery Ajax 学习实例2 向页面发出请求 返回JSon格式数据
2010/03/15 Javascript
JavaScript Scoping and Hoisting 翻译
2012/07/03 Javascript
js中for in语句的用法讲解
2015/04/24 Javascript
JQuery之proxy实现绑定代理方法
2016/08/01 Javascript
JS实现用户注册时获取短信验证码和倒计时功能
2016/10/27 Javascript
vue 根据数组中某一项的值进行排序的方法
2018/08/30 Javascript
微信小程序如何获取手机验证码
2018/11/04 Javascript
详解Angular Forms中自定义ngModel绑定值的方式
2018/12/10 Javascript
vue-for循环嵌套操作示例
2019/01/28 Javascript
详解keep-alive + vuex 让缓存的页面灵活起来
2019/04/19 Javascript
微信小程序 搜索框组件代码实例
2019/09/06 Javascript
vue 的 solt 子组件过滤过程解析
2019/09/07 Javascript
Vue实现点击按钮复制文本内容的例子
2019/11/09 Javascript
在vue中使用inheritAttrs实现组件的扩展性介绍
2020/12/07 Vue.js
利用Python中的输入和输出功能进行读取和写入的教程
2015/04/14 Python
Python实现的堆排序算法示例
2018/04/29 Python
python读取图片任意范围区域
2019/01/23 Python
使用python爬取微博数据打造一颗“心”
2019/06/28 Python
python和c语言的主要区别总结
2019/07/07 Python
python系列 文件操作的代码
2019/10/06 Python
python中uuid模块实例浅析
2020/12/29 Python
Html5 new XMLHttpRequest()监听附件上传进度
2021/01/14 HTML / CSS
Ajax请求总共有多少种Callback
2016/07/17 面试题
质量保证书格式模板
2015/02/27 职场文书
国家助学金受助感言
2015/08/01 职场文书
小学语文教师研修日志
2015/11/13 职场文书
教你使用RustDesk 搭建一个自己的远程桌面中继服务器
2022/08/14 Servers