Python爬虫框架Scrapy的入门和实践

Github项目地址:https://github.com/xylon666/Scrapy

Scrapy框架,简单来说就是把爬虫各功能模块分割开来,分别负责相应的功能,让我们通过简单的学习和实践来使用他

框架示意图:

                   Scrapy架构图.png

架构分析

  • Scrapy Engine:Scrapy引擎。负责控制数据流在系统中所有组件中流动,并在相应动作发生时触发事件。
  • Scheduler:调度器。从Scrapy Engine接受请求(requests)并排序列入队列,并在引擎再次请求时返回。用它来决定下一个抓取的网址是什么,同时去除重复的网址。
  • Downloader:下载器。抓取网页并将网页内容返还给Spiders。建立在twisted异步模型。
  • Spiders:爬虫。用户自定义的类,主要用来解析网页,提取Items,发送url跟进等新请求等。
  • Item Pipelines:管道。主要用来处理Spider解析出来的Items,进行按规则过滤,验证,持久化存储(如数据库存储)等
  • Downloader Middlewares:下载中间件。位于Scrapy Engine和Downloader之间,主要是处理Scrapy引擎与下载器之间的请求及响应。
  • Spider Middlewares:爬虫中间件。位于Scrapy Engine和Spiders之间,主要工作是处理Spiders的响应输入和请求输出。
  • Scheduler Middlewares:调度中间件。位于Scrapy Engine和Scheduler之间。主要工作是处理从Scrapy Engine发送到Scheduler的请求和响应。

所需环境:

编译器:Pycharm

第三方库:scrapy

Scrapy相关依赖库:

lxml
parsel
w3lib
twisted
cryptography
pyOpenSSL

均可通过pip install 安装

实践目标:

使用Scrapy框架爬取豆瓣电影排行版Top250

创建项目:

选择创建项目的文件路径,如在D盘创建一个文件夹"Douban_Scrapy"

然后运行cmd,cd到该目录

d:
cd D:\Douban_Scrapy

创建项目:

scrapy startproject douban

运行后我们会发现在该目录下多了几个文件,在Pycharm中打开:

对比文章开头的框架示意图,简单介绍下他们的功能

spiders目录:编写爬虫代码的主体

items:存放获取数据的相关元素

middlewares:定义爬虫过程中的操作

pipelines:定义存储信息时的操作,例如将数据传入ManggoDB或MySQL

setting:顾名思义,用来定义我们的各种配置,比如请求头信息等


初始化爬虫:

运行cmd,cd到爬虫project的spiders目录,执行:

scrapy genspider douban_spider movie.douban.com

这样一个爬虫模板就自动建好了

由于需要多次运行cmd来执行scrapy命令,我们可以通过Pycharm直接在编译器内来实现这一过程

在spiders目录新建main.py:

from scrapy import cmdline
cmdline.execute('scrapy genspider douban_spider movie.douban.com'.split())

运行后无需通过cmd就能执行命令了 

再修改一下setting配置:

USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36'
#伪装头
ROBOTSTXT_OBEY = False
#忽略网页的爬虫规则
DOWNLOAD_DELAY = 0.5
#下载延时

再来看一下要爬的内容:

我们通过该页面可以获取到的信息有:排名,电影名,星级,评价人数,描述

 根据爬取对象编辑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 DoubanItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    # 排名
    movie_num = scrapy.Field()
    # 电影名称
    movie_name = scrapy.Field()
    # 星级
    star = scrapy.Field()
    # 评价人数
    value = scrapy.Field()
    # 描述
    describle = scrapy.Field()

 编辑爬虫代码douban_spider.py:

# -*- coding: utf-8 -*-
import scrapy


class DoubanSpiderSpider(scrapy.Spider):
    #爬虫名称
    name = 'douban_spider'
    #爬虫允许抓取的域名
    allowed_domains = ['movie.douban.com']
    #获取数据传给调度器的地址
    start_urls = ['http://movie.douban.com/top250']

    def parse(self, response):
        print(response.text)

执行命令:

在cmd中对应目录下

scrapy crawl douban_spider

 或在Pycharm中spiders目录下新建main.py

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

 执行结果,可以发现成功获取到了豆瓣网页源代码

分析页面:

网页源代码已获取,再来看要爬取的内容:

电影信息都在div class='"article"//ol class="grid_view"下的<li>标签内,通过xpath对其解析获取:

# -*- coding: utf-8 -*-
import scrapy


class DoubanSpiderSpider(scrapy.Spider):
    name = 'douban_spider'
    allowed_domains = ['movie.douban.com']
    start_urls = ['http://movie.douban.com/top250']

    def parse(self, response):
        movie_list = response.xpath("//div[@class='article']//ol[@class='grid_view']/li")
        for item in movie_list:
            print(item)

如果你不知道xpath,推荐阅读:xpath语法

获取该页面所有电影信息后,从中提取出我们需要的部分

导入模型文件:

from ..items import DoubanItem

 从我们刚刚获得的电影信息中,根据节点信息获取电影排名:

        for item in movie_list:
            douban_item = DoubanItem()    
            #模型初始化
            douban_item['movie_num'] = item.xpath(".//div[@class='item']//em/text()").get()
            #从当前标签起始,访问目标标签获取文本信息,将其写入movie_num

以此类推,获取后面的内容

        for item in movie_list:
            douban_item = DoubanItem()
            douban_item['movie_num'] = item.xpath(".//div[@class='item']//em/text()").get()
            douban_item['movie_name'] = item.xpath(".//div[@class='info']/div[@class='hd']/a/span[1]/text()").get()
            douban_item['star'] = item.xpath(".//div[@class='bd']/div[@class='star']/span[2]/text()").get()
            douban_item['value'] = item.xpath(".//div[@class='bd']/div[@class='star']/span[4]/text()").get()
            douban_item['describle'] = item.xpath(".//div[@class='bd']/p[@class='quote']/span/text()").get()
            print(douban_item)
            yield douban_item
            #将返回结果压入item Pipline进行处理

运行结果(红色信息是正常情况):

循环获取当前页面所有电影信息后,我们需要访问下一页继续获取数据,右键检查“后页”

根据标签信息,拼接前缀获取完整链接并访问下一页

next_link = response.xpath("//span[@class='next']/link/@href").get()
if next_link:
    yield scrapy.Request('http://movie.douban.com/top250' + next_link, callback=self.parse)

通过输出结果可以看到成功访问到了最后一页

完整代码:

# -*- coding: utf-8 -*-
import scrapy
from ..items import DoubanItem

class DoubanSpiderSpider(scrapy.Spider):
    #爬虫名称
    name = 'douban_spider'
    #爬虫允许抓取的域名
    allowed_domains = ['movie.douban.com']
    #获取数据传给调度器的地址
    start_urls = ['http://movie.douban.com/top250']

    def parse(self, response):
        movie_list = response.xpath("//div[@class='article']//ol[@class='grid_view']/li")
        for item in movie_list:
            douban_item = DoubanItem()
            douban_item['movie_num'] = item.xpath(".//div[@class='item']//em/text()").get()
            douban_item['movie_name'] = item.xpath(".//div[@class='info']/div[@class='hd']/a/span[1]/text()").get()
            douban_item['star'] = item.xpath(".//div[@class='bd']/div[@class='star']/span[2]/text()").get()
            douban_item['value'] = item.xpath(".//div[@class='bd']/div[@class='star']/span[4]/text()").get()
            douban_item['describle'] = item.xpath(".//div[@class='bd']/p[@class='quote']/span/text()").get()
            print(douban_item)
            yield douban_item
            #将返回结果压入item Pipline进行处理
        next_link = response.xpath("//span[@class='next']/link/@href").get()
        if next_link:
            yield scrapy.Request('http://movie.douban.com/top250' + next_link, callback=self.parse)

保存文件:

保存为csv文件:

scrapy crawl douban_spider -o movielist.csv

保存为json文件:

scrapy crawl douban_spider -o movielist.json

注意:使用excel打开csv文件时,常常会发生乱码,这是由于csv数据用逗号分隔,而excel通过ANSI解码导致的

解决方法:

在爬虫文件中添加以下代码,预先设置csv文件的编码格式为UTF8-BOM

import codecs
with codecs.open('movielist.csv','wb+') as f:
    f.write(codecs.BOM_UTF8)

结果展示: 

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值