Scrapy 爬取豆瓣电影 Top250 榜单https://docs.scrapy.org/en/latest/intro/tutorial.html
工具和环境
- 语言: Python 3.7
- IDE: Pycharm
- 爬虫框架:Scrapy
- 浏览器: Google Chrome
- 浏览器插件: XPath Helper
创建项目在开始爬取之前,首先要创建一个新的 Scrapy 项目。这里以爬取豆瓣电影 Top250 为例,进入你打算存储代码的目录中,运行下列命令:
- scrapy startproject douban
复制代码 该命令将会创建包含下列内容的 douban 目录:
- douban
- |-- __init__.py
- |-- __pycache__
- | |-- __init__.cpython-37.pyc
- | |-- items.cpython-37.pyc
- | |-- pipelines.cpython-37.pyc
- | `-- settings.cpython-37.pyc
- |-- items.py
- |-- middlewares.py
- |-- pipelines.py
- |-- settings.py
- `-- spiders
- |-- __init__.py
- |-- __pycache__
- | |-- __init__.cpython-37.pyc
- | `-- douban_spider.cpython-37.pyc
- `-- douban_spider.py
- 3 directories, 13 files
复制代码 这些文件分别是:
- scrapy.cfg: 项目的配置文件。
- douban/: 该项目的 python 模块。之后您将在此加入代码。
- douban/items.py: 项目中的 item 文件。定义我们所要爬取的信息的相关属性。
- douban/pipelines.py: 项目中的 pipelines 文件。当数据被爬虫爬取下来后,它会被发送到 item pipelines 中,每个 item pipelines 组件(有时称为 “项目管道”)是一个实现简单方法的 Python 类。他们收到一个项目并对其执行操作,还决定该项目是否应该继续通过管道或被丢弃并且不再被处理。
- douban/settings.py: 项目的设置文件。
- douban/spiders/: 放置 spider 代码的目录。
观察页面结构首先我们打开豆瓣电影 TOP250 的页面,通过观察页面决定让我们的爬虫获取每一部电影的排名、电影名称、评分和评分的人数。
https://movie.douban.com/top250
运行Chrome F12开发者工具,使用选取工具选取整个电影的信息,可以发现,所有的信息都是放在单独的一个 li 标签中的,而且在 li 下还有一个 class 为 item 的 div 包裹着所有的信息。
- <li>
- <div class="item">
- <div class="pic">
- <em class="">1</em>
- <a href="https://movie.douban.com/subject/1292052/">
- <img width="100" alt="肖申克的救赎" src="https://img3.doubanio.com/view/photo/s_ratio_poster/public/p480747492.webp" class="">
- </a>
- </div>
- <div class="info">
- <div class="hd">
- <a href="https://movie.douban.com/subject/1292052/" class="">
- <span class="title"> 肖申克的救赎</span>
- <span class="title"> / The Shawshank Redemption</span>
- <span class="other"> / 月黑高飞 (港) / 刺激 1995 (台)</span>
- </a>
- <span class="playable">[可播放]</span>
- </div>
- <div class="bd">
- <p class="">
- 导演:弗兰克・德拉邦特 Frank Darabont 主演:蒂姆・罗宾斯 Tim Robbins /...<br>
- 1994 / 美国 / 犯罪 剧情
- </p>
-
- <div class="star">
- <span class="rating5-t"></span>
- <span class="rating_num" property="v:average">9.6</span>
- <span property="v:best" content="10.0"></span>
- <span>1338863 人评价</span>
- </div>
- <p class="quote">
- <span class="inq">希望让人自由。</span>
- </p>
- </div>
- </div>
- </div>
- </li>
复制代码 声明Item什么是 Items 呢?官方文档 Items 定义如下:
爬取的主要目标就是从非结构性的数据源提取结构性数据,例如网页。 Scrapy spider 可以以 python 的 dict 来返回提取的数据。虽然 dict 很方便,并且用起来也熟悉,但是其缺少结构性,容易打错字段的名字或者返回不一致的数据,尤其在具有多个 spider 的大项目中。
为了定义常用的输出数据,Scrapy 提供了 Item 类。 Item 对象是种简单的容器,保存了爬取到得数据。 其提供了 类似于词典 (dictionary-like) 的 API 以及用于声明可用字段的简单语法。
许多 Scrapy 组件使用了 Item 提供的额外信息: exporter 根据 Item 声明的字段来导出数据、 序列化可以通过 Item 字段的元数据 (metadata) 来定义、 trackref 追踪 Item 实例来帮助寻找内存泄露 (see 使用 trackref 调试内存泄露) 等等。
Item 使用简单的 class 定义语法以及 Field 对象来声明。我们打开 spider 目录下的 items.py 文件写入下列代码声明 Item:
- # -*- coding: utf-8 -*-
- # Define here the models for your scraped items
- #
- # See documentation in:
- # https://doc.scrapy.org/en/latest/topics/items.html
- import scrapy
- class DoubanItem(scrapy.Item):
- # define the fields for your item here like:
- # name = scrapy.Field()
- serial_number = scrapy.Field()
- movie_name = scrapy.Field()
- introduce = scrapy.Field()
- star = scrapy.Field()
- evaluate = scrapy.Field()
- describe = scrapy.Field()
复制代码 编写爬虫程序在编写代码前我们可以通过修改settings.py文件调整user-agent和其它参数 - # -*- coding: utf-8 -*-
- # Scrapy settings for douban project
- #
- # For simplicity, this file contains only settings considered important or
- # commonly used. You can find more settings consulting the documentation:
- #
- # https://doc.scrapy.org/en/latest/topics/settings.html
- # https://doc.scrapy.org/en/latest/topics/downloader-middleware.html
- # https://doc.scrapy.org/en/latest/topics/spider-middleware.html
- BOT_NAME = 'douban'
- SPIDER_MODULES = ['douban.spiders']
- NEWSPIDER_MODULE = 'douban.spiders'
- # Crawl responsibly by identifying yourself (and your website) on the user-agent
- USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36'
- # Obey robots.txt rules
- ROBOTSTXT_OBEY = False
- # Configure a delay for requests for the same website (default: 0)
- # See https://doc.scrapy.org/en/latest/topics/settings.html#download-delay
- # See also autothrottle settings and docs
- DOWNLOAD_DELAY = 0.5
- # Configure item pipelines
- # See https://doc.scrapy.org/en/latest/topics/item-pipeline.html
- ITEM_PIPELINES = {
- 'douban.pipelines.DoubanPipeline': 300,
- }
- mongo_host = '127.0.0.1'
- mongo_port = 27017
- mongo_db_name = 'douban'
- mongo_db_collection = 'douban_movie'
复制代码 在 spiders 文件夹下创建 douban_spider.py 文件
在我们编写爬虫之前,先了解一下 scrapy 的爬取机制,scrapy 提取数据有自己的一套机制。它们被称作选择器 (seletors),因为他们通过特定的 XPath 或者 CSS 表达式来 “选择” HTML 文件中的某个部分。
Xpath 学习教程
http://www.w3school.com.cn/xpath/index.asp
XPath Helper
https://chrome.google.com/webstore/detail/xpath-helper/hgimnogjllphhhkhlmebbmlgjoejdpjl
Scrapy xpath-tutorial
https://doc.scrapy.org/en/xpath-tutorial/topics/xpath-tutorial.html
- # -*- coding: utf-8 -*-
- import scrapy
- from douban.items import DoubanItem
- class DoubanSpiderSpider(scrapy.Spider):
- name = 'douban_spider'
- allowed_domains = ['movie.douban.com']
- start_urls = ['https://movie.douban.com/top250']
- def parse(self, response):
- movie_list = response.xpath("//div[@class='article']//ol[@class='grid_view']/li")
- for i_item in movie_list:
- douban_item = DoubanItem()
- douban_item['serial_number'] = i_item.xpath(".//div[@class='item']//em/text()").extract_first()
- douban_item['movie_name'] = i_item.xpath(".//div[@class='info']/div[@class='hd']/a/span[1]/text()").extract_first()
- content = i_item.xpath(".//div[@class='info']//div[@class='bd']/p[1]/text()").extract()
- for i_content in content:
- content_s = "".join(i_content.split())
- douban_item['introduce'] = content_s
- douban_item['star'] = i_item.xpath(".//span[@class='rating_num']/text()").extract_first()
- douban_item['evaluate'] = i_item.xpath(".//div[@class='star']//span[4]/text()").extract_first()
- douban_item['describe'] = i_item.xpath(".//p[@class='quote']//span/text()").extract_first()
- yield douban_item
- next_link = response.xpath("//span[@class='next']/link/@href").extract()
- if next_link:
- next_link = next_link[0]
- yield scrapy.Request("https://movie.douban.com/top250"+next_link,callback=self.parse)
复制代码 自动翻页
先别急着高兴,你难道没有发现一个问题吗?这样的话我们还是只能爬到当前页的 25 个电影的内容。怎么样才能把剩下的也一起爬下来呢?
实现自动翻页一般有两种方法:
- 在页面中找到下一页的地址;
- 自己根据 URL 的变化规律构造所有页面地址。
一般情况下我们使用第一种方法,第二种方法适用于页面的下一页地址为 JS 加载的情况。这次我们只说第一种方法。
首先利用 Chrome 浏览器的开发者工具找到下一页的地址,然后在解析该页面时获取下一页的地址并将地址交给调度器 (Scheduler)
|