Scrapy爬取豆瓣电影Top250

互联网 51 2017-11-08 00:26

这两天摸索了下scrapy,刚看文档的时候觉得有点生无可恋,scrapy框架个人还是觉得比较难懂的,需要学习的地方非常多,之前用beautifulsoup4爬过top250,比scrapy简单更容易理解!!

Scrapy简介

Scrapy,Python开发的一个快速、高层次的屏幕抓取和web抓取框架,用于抓取web站点并从页面中提取结构化的数据。Scrapy用途广泛,可以用于数据挖掘、监测和自动化测试。 下面对每个组件都做了简单介绍,数据流如下所描述。


Scrapy爬取豆瓣电影Top250-微网络
image
  • Scrapy Engine
    引擎负责控制数据流在系统中所有组件中流动,并在相应动作发生时触发事件。 详细内容查看下面的数据流(Data Flow)部分
  • 调度器(Scheduler)
    调度器从引擎接受request并将他们入队,以便之后引擎请求他们时提供给引擎
  • 下载器(Downloader)
    下载器负责获取页面数据并提供给引擎,而后提供给spider
  • Spiders
    Spider是Scrapy用户编写用于分析response并提取item(即获取到的item)或额外跟进的URL的类。 每 个spider负责处理一个特定(或一些)网站
  • Item Pipeline
    Item Pipeline负责处理被spider提取出来的item。典型的处理有清理、 验证及持久化(例如存取到数 据库中)
  • 下载器中间件(Downloader middlewares)
    下载器中间件是在引擎及下载器之间的特定钩子(specific hook),处理Downloader传递给引擎的 response。 其提供了一个简便的机制,通过插入自定义代码来扩展Scrapy功能
  • Spider中间件(Spider middlewares)
    Spider中间件是在引擎及Spider之间的特定钩子(specific hook),处理spider的输入(response)和输出 (items及requests)。 其提供了一个简便的机制,通过插入自定义代码来扩展Scrapy功能
  • 数据流(Data flow)
    Scrapy中的数据流由执行引擎控制,其过程如下:

引擎打开一个网站(open a domain),找到处理该网站的Spider并向该spider请求第一个要爬取的 URL(s)。
引擎从Spider中获取到第一个要爬取的URL并在调度器(Scheduler)以Request调度。
引擎向调度器请求下一个要爬取的URL。
调度器返回下一个要爬取的URL给引擎,引擎将URL通过下载中间件(请求(request)方向)转发给下载 器(Downloader)。
一旦页面下载完毕,下载器生成一个该页面的Response,并将其通过下载中间件(返回(response)方 向)发送给引擎。
引擎从下载器中接收到Response并通过Spider中间件(输入方向)发送给Spider处理。
Spider处理Response并返回爬取到的Item及(跟进的)新的Request给引擎。
引擎将(Spider返回的)爬取到的Item给Item Pipeline,将(Spider返回的)Request给调度器。
(从第二步)重复直到调度器中没有更多地request,引擎关闭该网站

scrapy的流程如图,并且可归纳如下

  • 首先下载器下载request回执的html等的response
  • 然后下载器传给爬虫解析
  • 接着爬虫解析后交给调度器过滤,查重等等
  • 最后交给管道,进行爬取数据的处理

建议大家参考下中文版的Scrapy文档,看文档还是比较枯燥的,Scrapy又比较难懂(大神忽略),务必要有耐心!!!!!!

实战应用

首先下载Scrapy包

pip install scrapy

这样安装,windows平台应该是会报错的,我当时装Scrapy时废了很大劲才弄完。安装过程中Pycharm或者官网上找不到的模块可以上这个网址找Unofficial Windows Binaries for Python Extension Packages
Pywin32

接着,我们打开CMD,新建一个爬虫文件

scrapy startproject douban

Scrapy爬取豆瓣电影Top250-微网络
image

C:\Users\ssaw\douban>tree /f
C:.
│ scrapy.cfg

└─douban
│ items.py
│ middlewares.py
│ pipelines.py
│ settings.py
init.py

└─spiders
init.py

简单介绍下这些文件

  • scrapy.cfg: 项目的配置文件
  • douban/: 该项目的python模块。之后您将在此加入代码
  • douban/items.py: 项目中的item文件
  • douban/pipelines.py: 项目中的pipelines文件
  • douban/settings.py: 项目的设置文件
  • douban/spiders/:放置spider代码的目录

编辑items.py文件

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

# Define here the models for your scraped items
#
# See documentation in:
# http://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()
    movie_name = scrapy.Field()
    movie_star = scrapy.Field()
    movie_quote = scrapy.Field()
  • 首先,引入Scrapy
  • 接着,创建一个类,继承自scrapy.item,这个是用来储存要爬下来的数据的存放容器,类似orm的写法
  • 我们要记录的是:电影的名字、电影的评分、电影的引述(quote)

现在,我们在spiders文件夹下创建douban_spider.py
在我们编写爬虫之前,先了解一下scrapy的爬取机制,scrapy提取数据有自己的一套机制。它们被称作选择器(seletors),因为他们通过特定的 XPath 或者 CSS 表达式来“选择” HTML文件中的某个部分。
之前我在博客上也总结过一篇使用Xpath模拟登陆GitHub有兴趣可以看一下
附上Xpath学习教程Xpath

获取网页数据

打开Chrome(F12),查找元素
豆瓣电影TOP250

Scrapy爬取豆瓣电影Top250-微网络
image

红框圈出来的分别代表

movie_name = div[@class="hd"]/a/span/
movie_star = div[@class="bd"]/div[@class="star"]/span[@class="rating_num"]
movie_quote = div[@class="bd"]/p[@class="quote"]/span[@class="inq"]

# _*_ coding=utf-8 _*_

from scrapy.spiders import Spider
from scrapy.selector import Selector

class DouBanSpider(Spider):
    name = 'db'
    start_urls = ['https://movie.douban.com/top250']

    def parse(self, response):
        # print(response.body)
        selector = Selector(response)

        # print(selector)
        movies = selector.xpath('//div[@class="info"]')
        for movie in movies:
            movie_name = movie.xpath('div[@class="hd"]/a/span/text()').extract()
            movie_star = movie.xpath('div[@class="bd"]/div[@class="star"]/span[@class="rating_num"]/text()').extract()
            movie_quote = movie.xpath('div[@class="bd"]/p[@class="quote"]/span[@class="inq"]/text()').extract()


            print(movie_name)
            print(movie_star)
            print(movie_quote)

我们打开setting.py,加上U-A

USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36'

在CMD中输入scrapy crawl db,运行如下:


Scrapy爬取豆瓣电影Top250-微网络
image

我们还可以在douban文件根目录创建一个main.py,这样就可以在Pycharm中运行了

from scrapy import cmdline
cmdline.execute("scrapy crawl db".split())

使用Item

Item对象是自定义的python字典。 您可以使用标准的字典语法来获取到其每个字段的值。(字段即是我们之前用Field赋值的属性),Spider将会将爬取到的数据以 Item 对象返回。

item = DoubanItem()

item['movie_name'] = movie_name
item['movie_star'] = movie_star
item['movie_quote'] = movie_quote

好了,现在我们先试着爬取单页面,查看下结果后,再去爬取多页面

from scrapy.spiders import Spider
from scrapy.selector import Selector
from douban.items import DoubanItem



class DouBanSpider(Spider):
    name = 'db'
    start_urls = ['https://movie.douban.com/top250']

    def parse(self, response):
        # print(response.body)
        selector = Selector(response)

        # print(selector)
        movies = selector.xpath('//div[@class="info"]')
        for movie in movies:
            movie_name = movie.xpath('div[@class="hd"]/a/span/text()').extract()
            movie_star = movie.xpath('div[@class="bd"]/div[@class="star"]/span[@class="rating_num"]/text()').extract()
            movie_quote = movie.xpath('div[@class="bd"]/p[@class="quote"]/span[@class="inq"]/text()').extract()

            #print(movie_name)
            #print(movie_star)
            #print(movie_quote)

            item = DoubanItem()

            item['movie_name'] = movie_name
            item['movie_star'] = movie_star
            item['movie_quote'] = movie_quote
            yield item
            print(movie_name)
            print(movie_star)
            print(movie_quote)
  • 首先,我们先从scrapy中获得所需要的通用的 spider和 selector
  • 接着,我们使用Item将爬取的数据返回
  • 创建了一个DouBanSpider,继承了 scrapy.Spider 类, 且定义以下三个属性:
  1. name: 用于区别Spider。 该名字必须是唯一的,您不可以为不同的Spider设定相同的名字
  2. start_urls: 包含了Spider在启动时进行爬取的url列表。 因此,第一个被获取到的页面将是其中之一, 后续的URL则从初始的URL获取到的数据中提取。
  3. parse() 是spider的一个方法。 被调用时,每个初始URL完成下载后生成的 Response 对象将会作为唯一的参数传递给该函数。 该方法负责解析返回的数据(response data),提取数据(生成item)以及生成需要进一步处理的URL的 Request 对象
  • seletor的方法返回后一定要用它的 extract()方法,来返回一个列表 ;extract()文档的定义:串行化并将匹配到的节点返回一个unicode字符串列表。 结尾是编码内容的百分比
  • 接着,我们把得到的数据保存在Item中
  • 最后,我们使用Feed exports来保存数据
  • 这里使用了yield生成器函数,生成器函数和迭代器有密切关系,也并不是很容易理解,这一点需要多多学习
#看一个yield函数的示例
#函数在每次循环时都会产生一个值,之后将其返回给它的调用者
#函数不断的生成数字的平方

def gensquares(N):
    for i in range(N):
        yield i ** 2
        
for i in gensquares(5):
    print(i, end=' ')

0 1 4 9 16 

好了,spider暂时写完了,我们试着运行下

scrapy crawl db -o douban.json -t json

-o 后面是导出文件名,-t 后面是导出类型。
然后来看一下导出的结果,Pycharm打开json文件即可


Scrapy爬取豆瓣电影Top250-微网络
image

打印出来的内容需要编码
我们换种方式,把文件格式保存为CSV,使用EXCEL打开

scrapy crawl db -o douban.csv -t csv

Scrapy爬取豆瓣电影Top250-微网络
image

用excel打开后假如是一堆乱码,就使用记事本打开,把它“另存为”时,编码选择ANSI


Scrapy爬取豆瓣电影Top250-微网络
image

好了,现在我们添加多页面链接,完整地把TOP250爬取下来
我们从Elements中找到翻页lianjie


Scrapy爬取豆瓣电影Top250-微网络
image
next_page =response.selector.xpath('//span[@class="next"]/link/@href').extract()
if next_page:
    next_page = next_page[0]
    print(next_page)
    yield Request(self.url + next_page, callback=self.parse)

CMD输入scrapy crawl db -o douban.csv -t csv ,开始运行


Scrapy爬取豆瓣电影Top250-微网络
image

学习Scrapy需要反复查看文档、资料,这是个简单的学习总结,这两天准备再去学习MongoDB数据库,大家一起加油!!

参考链接
参考链接
Scrapy文档
GitHub
微网络
最后,欢迎大家访问我的博客Treehl的博客

文章评论