爬虫——豆瓣电影top250

无论是动态网页爬虫和静态网页爬虫,实现的思路基 本上都是获取页面 html、页面解析、数据保存或输出。虽然获取页面 html 以及数据保存都 已经封装为通用函数,但依然编写繁琐。使用爬虫框架可以很好的解决这些问题,让我们在 编写爬虫的过程中专注于页面解析,大大简化编写爬虫的工作量,并能提高爬虫运行的效率。

所谓的爬虫框架,是一个半成品的爬虫,已经实现了工作队列、下载器、保存处理数据 的逻辑以及日志、异常处理、反反爬虫等通用功能。对于使用者来说,更多的工作是通过更 改配置调整需要开启的通用功能,让我们更专注于分析页面,编写网站的爬取规则。

Scrapy 爬虫框架是 Python 中最著名、最受欢迎、社区最活跃的爬虫框架。是人们为了 爬取网站数据、提取结构性数据而编写,可以应用在包括数据挖掘、信息处理或存储历史数 据等一系列的程序中。

1、命令行安装
在命令行下安装 Scrapy 比较简单,只需要输入如下命令即可

pip install scrapy

由于 pip 安装会自动安装 scrapy 爬虫框架依赖的各种包,安装速度较慢,出错概率较 大,建议增加-i 参数,使用清华镜像安装

pip install scrapy -i https://pypi.tuna.tsinghua.edu.cn/simple

Scrapy 快速入门

1、创建爬虫项目

打开 pycharm,在底部状态栏中点击“Terminal”,输入“scrapy startproject doubanSpider”,其中 baiduSpier 为 Scrapy 项目名称。

2.创建爬虫文件

爬虫项目和爬虫的关系为 1 对多的关系。一个爬虫项目可以由多个爬虫共同组成。如创 建一个新闻类的爬虫项目,可能会爬取百度新闻、腾讯新闻等多个网站的新闻。就可以创建 多个爬虫文件。

上图的提示中已经指引了此步骤的操作方法。首先使用“cd doubanSpider” 命令进入 目录 doubanSpider,此目录为“创建爬虫项目”时通过模板自动生成的。然后使用命令“scrapy genspider douban douban.com” 生成爬虫文件。其中参数“douban”为爬虫名称,需要注意 的是爬虫文件的名称不能和爬虫项目 doubanSpider 重复。参数“douban.com”为域名。

在 doubanSpider/doubanSpider/spiders 目录下找到 douban.py 文件。

def parse(self, response):
        for row in response.xpath("//div[@class='item']"):
            item = Doubanspider2Item()
            url=row.xpath("div[2]/div/a/@href").get()
            # 电影名
            item["movie"] = row.xpath("div[2]/div[1]/a/span[1]/text()").extract()[0]
            # 评价人数
            item["number1"]=row.xpath("div[2]/div[2]/div/span[4]/text()").extract()[0].split('人评价')[0].strip()
            # 导演
            item["director"] = row.xpath("div[@class='info']/div[@class='bd']/p/text()").extract()[0].split(':')[1].split('主演')[0].strip()
            # 主演
            try:
                actor = row.xpath("div[@class='info']/div[@class='bd']/p/text()").extract()[0].split(':')[2].split('/')[0].strip()
            except Exception as e:
                actor = 'null'
            item["actor"]=actor
            # 年份
            item["date1"] = re.search(r'\d{4}',row.xpath("div[@class='info']/div[@class='bd']/p/text()").extract()[1]).group(0)
            # 产地
            item["area1"]= row.xpath("div[@class='info']/div[@class='bd']/p/text()").extract()[1].split('/')[1].strip()
            # 类型
            item["type1"] = row.xpath("div[@class='info']/div[@class='bd']/p/text()").extract()[1].split('/')[2].strip()
            # 评分
            item["score"]= row.xpath( "div[@class='info']/div[@class='bd']/div[@class='star']/span[@class='rating_num']/text()").extract()[0]
            yield item

使用 Scrapy 框架的爬虫程序使用面向对象的方式进行封装。继承自 scrapy.Spider 类。 name 属性定义的为爬虫的名称,是我们使用“scrapy genspider baidu baidu.com”命 令时定义的,在同一个项目中可以定义多个爬虫,但必须保证爬虫名称唯一。

属性 allowed_domains 定义过滤爬取的域名,不在范围内约定的域名将不会进行爬取。类型 为列表,表示可以有多个域名。

属性 start_urls 定义爬虫启动时的默认爬取的地址,在通常情况下,爬虫默认从此地址开始爬取。

parse 方法是解析网页数据的核心方法。parse 方法以 response 作为参数,内容是爬取到的 页面 html 内容。细心的读者会发现,使用 Scrapy 框架将会省略使用 requests 或 urllib 库获取 页面内容的步骤

3.定义爬取数据项

在编写爬虫前,我们需要先定义爬取的数据项,只是数据项的命名,不涉及具体的数据类 型。百度首页导航链接爬虫比较简单,需要爬取的数据只有导航标签名称以及 url 地址。定义爬 取数据项是为后续步骤输出做准备。 在doubanSpider/doubanSpider/spiders 文件夹下找到 items.py 文件。代码如下

import scrapy
class Doubanspider2Item(scrapy.Item):

    movie = scrapy.Field()  # 电影名
    number1 = scrapy.Field()
    director = scrapy.Field() #导演
    actor = scrapy.Field()  #主演
    score = scrapy.Field()   #评分
    type1 = scrapy.Field()  #类型
    area1 = scrapy.Field()   #地区
    date1 = scrapy.Field()  # 上映日期
4.定义爬虫解析

在编写解析 parse 方法前,需要优先考虑选择器的使用。Scrapy 爬虫框架是在 Lxml 基础上 构建了一套提取数据的机制,通过特定的 XPath 或 CSS 选择器来选择 HTML 页面中的某个部分。

Scrpay 选择器在速度和解析准确性上和 Lxml 非常相似。 前面章节已经讲解过 XPath 表达式,读者已有深入的了解,同时 XPath 提供了比 CSS 选择器 更强大的功能,所以推荐使用 XPath 来进行页面解析。实际上 Scrapy 的 CSS 选择器最终在运行 时也是转换为 XPath 的语法。

Scrapy 爬虫框架提供了选择器的快捷方式,response.xpath()和 response.css(),让用户直 接使用选择器。

5.运行爬虫

运行爬虫程序,需要使用命令“scrapy crawl 爬虫名”。在“Terminal”下执行命令 “Scrapy crawl douban”前,必须进入爬虫项目所在的目录,否则无法正常运行。当前项目 名为 doubanSpider,所以首先使用“cd doubanSpider”进入爬虫项目目录

爬虫运行后会打印输出非常多的日志信息,是因为缺省情况下日志等级为 info。可在 配置文件“doubanSpider/doubanSpider/settings.py”文件中进行调整。

ROBOTSTXT_OBEY = False #关闭 robots 协议,否则很多页面都无法爬取 LOG_LEVEL=“WARNING” #日志为警告以上才显示

调整后程序重新运行,发现没有任何提示,是因为 parse 函数中没有任何输出。增加-o
参数,将爬取的结果输出为文件。命令为“scrapy crawl douban -o douban.csv”。运行后 在 doubanSpider 目录下查看 douban.csv 文件。

完整代码

1.douban.py

# -*- coding: utf-8 -*-
import scrapy
import re
from doubanSpider2.items import Doubanspider2Item


class DoubanSpider2(scrapy.Spider):
    name = 'douban'
    allowed_domains = ['movie.douban.com','doubanio.com']
    start_urls = ['https://movie.douban.com/top250?start=' + str(i) for i in range(0, 250, 25)]

    def parse(self, response):
        for row in response.xpath("//div[@class='item']"):
            item = Doubanspider2Item()
            url=row.xpath("div[2]/div/a/@href").get()
            # 电影名
            item["movie"] = row.xpath("div[2]/div[1]/a/span[1]/text()").extract()[0]
            # 评价人数
            item["number1"]=row.xpath("div[2]/div[2]/div/span[4]/text()").extract()[0].split('人评价')[0].strip()
            # 导演
            item["director"] = row.xpath("div[@class='info']/div[@class='bd']/p/text()").extract()[0].split(':')[1].split('主演')[0].strip()
            # 主演
            try:
                actor = row.xpath("div[@class='info']/div[@class='bd']/p/text()").extract()[0].split(':')[2].split('/')[0].strip()
            except Exception as e:
                actor = 'null'
            item["actor"]=actor
            # 年份
            item["date1"] = re.search(r'\d{4}',row.xpath("div[@class='info']/div[@class='bd']/p/text()").extract()[1]).group(0)
            # 产地
            item["area1"]= row.xpath("div[@class='info']/div[@class='bd']/p/text()").extract()[1].split('/')[1].strip()
            # 类型
            item["type1"] = row.xpath("div[@class='info']/div[@class='bd']/p/text()").extract()[1].split('/')[2].strip()
            # 评分
            item["score"]= row.xpath( "div[@class='info']/div[@class='bd']/div[@class='star']/span[@class='rating_num']/text()").extract()[0]
            yield item

2.items.py

# -*- coding: utf-8 -*-

# Define here the models for your scraped items
#
# See documentation in:
# https://docs.scrapy.org/en/latest/topics/items.html

import scrapy
class Doubanspider2Item(scrapy.Item):

    movie = scrapy.Field()  # 电影名
    number1 = scrapy.Field()
    director = scrapy.Field() #导演
    actor = scrapy.Field()  #主演
    score = scrapy.Field()   #评分
    type1 = scrapy.Field()  #类型
    area1 = scrapy.Field()   #地区
    date1 = scrapy.Field()  # 上映日期

3.settings.py

BOT_NAME = 'doubanSpider2'

SPIDER_MODULES = ['doubanSpider2.spiders']
NEWSPIDER_MODULE = 'doubanSpider2.spiders'

ROBOTSTXT_OBEY = False
LOG_LEVEL="WARNING" #日志为警告以上才显示
# Configure maximum concurrent requests performed by Scrapy (default: 16)