憨豆说安全 · 2020年08月12日

云芯一号教程 - Scrpay安装及爬虫编写教程

  Scrapy是一个基于Python爬虫框架,可以方便的抓取WEB网页,并从中提取结构化的数据。

1.Scrapy框架简介
1.1 Scrapy框架组成
  Scrapy框架主要由五大组件组成,分别是调度器(Scheduler)、下载器(Downloader)、爬虫(Spider)和实体管道(Item Pipeline)、Scrapy引擎(Scrapy Engine)。
  (1) 调度器(Scheduler)
  负责接受引擎发送过来的Request请求,并按照一定的方式进行整理排列,入队,当引擎需要时,交还给引擎。用户可根据自己的需求定制调度器。
  (2) 下载器(Downloader)
  负责下载Scrapy Engine(引擎)发送的所有Requests请求,并将其获取到的Responses交还给Scrapy Engine(引擎),由引擎交给Spider来处理。Scrapy下载器是建立在高效的异步模型twisted上的,效率非常高。
  (3) 爬虫(Spider)
  负责处理所有Responses,从中分析提取数据,获取Item字段需要的数据,并将需要跟进的URL提交给引擎,再次进入Scheduler(调度器)。爬虫需要用户根据自己的需求进行编写。
  (4) 实体管道(Item Pipeline)
  负责处理Spider中获取到的Item,并进行数据分析、过滤、验证、持久化等处理。
  (5) Scrapy引擎(Scrapy Engine)
  Scrapy引擎是整个框架的核心,负责Spider、ItemPipeline、Downloader、Scheduler中间的通讯,信号、数据传递等,相当于计算机的CPU,它控制着整个流程。

1.2 Scrapy爬虫编写步骤
  编写Scrapy爬虫可以分为四个步骤:
  (1) 新建项目 :新建一个新的爬虫项目
  (2) 明确目标 :明确你想要抓取的目标,编写items.py
  (3) 制作爬虫 :编写爬取网页的爬虫,编写spiders/xxspider.py
  (4) 存储内容 :设计管道存储爬取内容,编写pipelines.py

  此外,还需要根据所爬取的网站特点,修改scrapy.cfg配置文件。

2.安装Scrapy
2.1 安装pip3
  Scrapy是基于Python的,通过pip工具安装。首先需要安装pip工具,教程中采用系统自带的Python 3.6,因此要安装pip3。

  sudo apt install python3-pip

2.2 更换pip3源
  安装过程中,如果pip3安装下载缓慢,可以更换pip3的安装源到阿里的源。

  mkdir ~/.pip
  vim ~/.pip/pip.conf
  [global]
  index-url = https://mirrors.aliyun.com/pypi/simple

2.3 安装Scrapy所需的类库
  为了避免安装过程中出错,把Scrapy所需的类库预先安装好。

  sudo apt-get install python-dev python3-dev libxml2-dev libxslt1-dev zlib1g-dev libffi-dev libssl-dev

2.4 安装scrapy

  sudo pip3 install scrapy   

2.5 安装pymongo
  本教程中,把爬虫爬取的数据存入《MongoDB Replicaset集群搭建教程》中搭建的MongoDB Replicaset副本集,还需要安装pymongo。
  pymongo是在Python中用于连接 MongoDB服务器的驱动库。我们在Python3环境中访问MongoDB数据库时,需要pymongo连接并操作数据库。
  在python3环境中的安装命令如下:

  sudo pip3 install pymongo==3.2.0

  MongoDB Replicaset副本集的配置,请参考MongoDB数据库相关的教程。

3.编写scrapy爬虫
  豆瓣网是一个非常知名的社区网站。我们就以豆瓣电影网站movie.douban.com为例,结合scrapy爬虫抓取电影信息,来实践MongoDB数据库的数据库创建、collection的创建和document的存储。
3.1 新建爬虫
  3.1.1创建工程

scrapy startproject scrapy_douban

  3.1.2创建爬虫

scrapy genspider douban movie.douban.com

  3.1.3 去除setting.py中把ITEM-PIPELINES开关注释
  3.1.4 网站抓取数据太快的话,会出现服务器访问错误,因此我们设置0.5秒发送一个请求,在setting.py中修改DOWNLOAD-DELAY = 0.5

3.2 分析网站
  打开豆瓣电影主页,点击进入"选电影"页面,我们可以按照不同的标签来选电影,如"热门"、"最新"、"经典"等。
  我们以"热门"标签为例,来分析网页数据。选择"热门"标签后,具体电影的列表显示会以热度、时间、评价三种排序方式可供选择。
  我们选择默认的"按热度排序"方式,页面会显示20个电影信息,点击电影下方的"加载更多"后,会更新20个电影信息。
  点击具体电影后,会进入电影信息页面,我们可以在这个页面上抓取具体的影片信息,并存入MongoDB数据库。
  这样,整体的思路为:从"选电影"页面上抓取标签信息,然后轮询标签,抓取各个标签下的电影列表的URL,再从这些URL的页面上抓取具体的影片信息,存入MongDB数据库。

3.3 抓取标签信息
  我们来分析一下豆瓣电影的HTML代码,在页面上显示标签的位置,并没有直接的标签信息,而是一个form表单。

  ......
  <div class="filter">
      <form action="get" class="gaia_frm" autocomplete="off">
          <input type="hidden" name="type" value="movie">
          <div class="tags">
              <div class="tag-list"></div>
              <div class="custom-frm" data-type="tag">
                  <input type="text" />
                  <button>确定</button>
              </div>
          </div>
          ......
      </form>
      ......
  </div>

  这样就必须是由JS启动获取具体的标签请求,来填充这个form。我们分析chrome浏览器的开发者工具中的"Network"交互数据,找到了获取具体标签的URL请求:

  https://movie.douban.com/j/search_tags?type=movie&source=

  我觉得这样做是有好处的,一方面可以动态更新网页上的标签信息,另一方面也可以根据登录用户的历史数据,展示用户更喜欢的影片信息。

  我们简单处理标签问题,手动确定几个标签。

  tags = ['热门','经典','华语']

3.4 抓取电影列表
  跟标签类似,电影的列表信息也是由另外的请求获取的。我们同样从"Network"交互数据中找到了请求的URL:

  https://movie.douban.com/j/search_subjects?type=movie&tag=%E7%83%AD%E9%97%A8&sort=recommend&page_limit=20&page_start=0

  URL中有两个重要参数:tag为标签信息,page-start为获取影片的起始index,以步长20累加,每次点击"加载更多",都会page-start都会增加20,取获取新的影片列表。
  我们定义parse-movielist函数来处理循环获取的电影列表:

  url_tpl = "https://movie.douban.com/j/search_subjects?type=movie&tag={tag}&sort=recommend&page_limit=20&page_start={page}"
  tags = ['热门','经典','华语']

  for tag in tags:
      # 可以自行调整抓取的页数 页数 = max/20
      max = 40
      start = 0
      while start <= max:
          url = url_tpl.format(tag=tag, page=start)
          yield scrapy.Request(url, callback=self.parse_movielist)
          start += 20

  运行上述代码时,会出现以下错误:

  2019-11-15 19:58:38 [scrapy.downloadermiddlewares.robotstxt] DEBUG: Forbidden by robots.txt: <GET https://movie.douban.com/j/search_subjects?type=movie&tag=%E7%83%AD%E9%97%A8&sort=recommend&page_limit=20&page_start=0>
  2019-11-15 19:58:39 [scrapy.core.engine] INFO: Closing spider (finished)

  这是因为scrapy在爬取设定的URL之前,会先向服务器根目录请求一个robots.txt文件,这个文件规定了爬取范围,scrapy会查看自己是否符合权限,出错说明不符合,所以我们设定
不遵守这个协议。
  在settings.py中找到ROBOTSSTXT的设置项目,设为FALSE。

  ROBOTSTXT_OBEY = False

3.5 抓取影片信息
  请求返回的数据是标准的json数据,存放了20个影片的概要信息,我们可以从中获取影片详情的URL,并存放在数组中,然后循环获取影片详情。

  def parse_movielist(self, respones):
      #respones是json字符串
      resjson = respones.body.decode()
      movielist = json.loads(resjson)

      urls = []

      for movie in movielist.get("subjects"):
          urls.append(movie["url"].replace('\/','/'))

      for url in urls:
          yield scrapy.Request(url, callback=self.parse_movie)

  返回的影片列表信息中包含16进制的UTF-8中文编码,需要先decode,才能转换成json结构。

3.6 存储影片信息
  进入影片详情页面,从页面的HTML代码中可以找到影片的详情都在id="content"的div中,直接解析获取即可。
  我们在items.py中给影片信息定义5个字段,分别为:电影名字、详情、发布年份、评星、电影简介。

  class ScrapyDoubanItem(scrapy.Item):
      moviename = scrapy.Field()
      info = scrapy.Field()
      year = scrapy.Field()
      stars = scrapy.Field()
      synopsis = scrapy.Field()

  获取到影片详情后,存入MongoDB数据库。
  MongoDB中的数据库名字为douban,collection名字为movies。

  class ScrapyDoubanPipeline(object):
      def __init__(self):
          host = '127.0.0.1'
          port = 27017
          dbname = 'douban'
          sheetname = 'movies'
          self.client = pymongo.MongoClient('mongodb://admin:admin@127.0.0.1:27017/')
          db = self.client[dbname]
          self.moviedb = db[sheetname]

      def process_item(self, item, spider):
          data = dict(item)
             self.moviedb.insert(data)

4.运行爬虫
  在命令行中,运行scrapy crawl douban, 爬虫就开始工作啦!
  我们来看一下爬虫的成果。

  mongo命令,连接MongoDB Replicaset的主(Primary)节点。
  用"show dbs"命令查看数据库,douban数据库已经建立。

  jishu@Jishu:~$ sudo mongo 127.0.0.1:27017/admin -u admin -p admin
  MongoDB shell version v4.2.6
  ......
  
  test:PRIMARY> show dbs;
  admin   0.000GB
  config  0.000GB
  douban  0.000GB
  local   0.001GB

  进入douban数据库,用"show collections"命令查看collections,collection douban成功建立。

  test:PRIMARY> use douban
  switched to db douban
  test:PRIMARY> show tables;
  movies

  查看collection douban中的数据。

  > db.movies.find()
  { "_id" : ObjectId("5dd3c5b374fece22577d3949"), "moviename" : "比悲伤更悲伤的故事 比悲傷更悲傷的故事", "year" : "2018", "info" : "\n        导演: 林孝谦\n        编剧: 吕安弦\n        主演: 陈意涵 / 刘以豪 / 张书豪 / 陈庭妮 / 吴映洁 / 禾浩辰 / 游大庆 / 石知田 / 黄丽玲 / 姚爱宁\n        类型: 爱情\n        \n        制片国家/地区: 中国台湾\n        语言: 汉语普通话\n        上映日期: 2018-11-30(中国台湾) / 2019-03-14(中国大陆)\n        片长: 105分钟\n        又名: More Than Blue\n        IMDb链接: tt9081562\n\n", "stars" : "4.8", "synopsis" : "唱片制作人张哲凯(刘以豪)和王牌作词人宋媛媛(陈意涵)相依为命,两人自幼身世坎坷只有彼此为伴,他们是亲人、是朋友,也彷佛是命中注定的另一半。父亲罹患遗传重症而被母亲抛弃的哲凯,深怕自己随时会发病不久人世,始终没有跨出友谊的界线对媛媛展露爱意。眼见哲凯的病情加重,他暗自决定用剩余的生命完成他们之间的终曲,再为媛媛找个可以托付一生的好男人。这时,事业有 成温柔体贴的医生(张书豪)适时的出现让他成为照顾媛媛的最佳人选,二人按部就班发展着关系。一切看似都在哲凯的计划下进行。然而,故事远比这里所写更要悲伤......" }
  { "_id" : ObjectId("5dd3c5b574fece22577d394a"), "moviename" : "一条狗的使命2 A Dog's Journey", "year" : "2019", "info" : "\n        导演: 盖尔·曼库索\n        编剧: W·布鲁斯·卡梅伦 / 玛雅·福布斯 / 凯瑟琳·迈克 / 华莱士·沃洛达斯基\n        主演: 丹尼斯·奎德 / 凯瑟琳·普雷斯科特 / 刘宪华 / 玛格·海根柏格 / 贝蒂·吉尔平 / 乔什·加德 / 艾比·莱德·弗特森 / 杰克·曼利 / 达妮埃拉·巴博萨 / 陈琦烨 / 杰夫·罗普 / 吉姆·科比\n        类型: 剧情 / 喜剧 / 家庭\n        \n        制片国家/地区: 中国大陆 / 印度 / 中国香港 / 美国\n        语言: 英语\n        上映日期: 2019-05-17(美国/中国大陆)\n        片长: 108分钟\n        又名: 再见亦是狗朋友2(港) / 狗狗的旅程(台) / 一条狗的旅程 / 为了与你相遇2 / A Dog's Purpose 2\n        IMDb链接: tt8385474\n\n", "stars" : "6.9", "synopsis" : "小狗贝利延续使命,在主人伊森的嘱托下,通过不断的生命轮回, 执着守护伊森的孙女CJ,将伊森对孙女的爱与陪伴,当做最重要的 使命和意义,最终帮助CJ收获幸福,再次回到主人伊森身边。" }
  ......

  数据都正常存储。

  mongo命令,连接备份(Secondary)节点,也可以查询到douban数据库的数据。

推荐阅读
关注数
4278
内容数
71
低成本Arm微服务器开发平台“云芯1号”教程及应用,欢迎关注
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息