Python爬虫框架【Scrapy】

认识Scrapy

Scrapy,Python开发的一个快速、高层次的屏幕抓取和web抓取框架
用于抓取web站点并从页面中提取结构化的数据
Scrapy用途广泛,可以用于数据挖掘、监测和自动化测试

Scrapy吸引人的地方在于它是一个框架,任何人都可以根据需求方便的修改
它也提供了多种类型爬虫的基类
如BaseSpider、sitemap爬虫等,最新版本又提供了web2.0爬虫的支持

Scrapy 架构

Python爬虫框架【Scrapy】

创新互联建站是一家专注于成都做网站、成都网站建设与策划设计,珠海网站建设哪家好?创新互联建站做网站,专注于网站建设十年,网设计领域的专业建站公司;建站业务涵盖:珠海等地区。珠海做网站价格咨询:028-86922220

Scrapy Engine(引擎): 分配任务给其他模块,负责其它模块之间的通信,数据传递等

Scheduler(调度器): 接受引擎发送的Request请求,整理入队,当需要时返回给引擎

Downloader(下载器): 从引擎处接收并下载调度器整理后返回的Requests请求,并将获取的Responses返回给引擎

Spider(爬虫): 提供初始网址,接收并处理从引擎处接收下载器返回的Responses
分析并提取Item需要的数据返回给管道,并将需要跟进的网址url提交给引擎

Item Pipeline(管道):它负责处理Spider中获取到的Item,并进行进行后期处理(详细分析、过滤、存储等)的地方。

Downloader Middlewares(下载中间件): 你可以当作是一个可以自定义扩展下载功能的组件

Spider Middlewares(Spider中间件): 你可以理解为是一个可以自定扩展和操作引擎和Spider中间通信的功能组件
(比如进入Spider的Responses;和从Spider出去的Requests)
流程:
->Spider 提交初始爬取网址相关信息给Engine

->Engine根据Spider提交的数据发起Requests给Scheduler

->Scheduler将接收到的Requests进行整理入队,再返还给Engine

->Engine将整理后的Requests请求发送给Downloader

->Downloader将Requests请求提交给网站服务器并将服务器返回的Responses交给Engine

->Engine将Responses交给Spider进行处理

->Spider将从Responses中提取Item字段需要的信息和需要跟进的url
   信息交给pipelines,url则提交给Engine,进行下一次爬取

->pipelines将完成对信息的分析,筛选和存储等工作。

在Scheduler整理的Requests请求队列全部执行并处理完毕后,程序结束。
简化流程:
由于在Engine主要用于个模块之间的信息传递,可以简化工作流程如下:

Spider发送初始url ---------------> Scheduler整理请求并入队(Engine发起请求)

Scheduler 发送整理后的请求 ----------------->Downloader向网址提交请求并获取responses

Downloader发送获取的responses ------------------>Spider分析并提取Item所需信息和需要跟进的url

Spider发送Item所需信息 ----------------->pipelines分析,筛选,存储信息

Spider发送需要跟进的url -----------------> Scheduler整理请求并入队(Engine发起请求)

利用Scrapy制作爬虫

安装Scrapy

pip install scarpy

实现步骤

1.新建项目 (scrapy startproject projectname)
2.确定目标 (编写items.py)(即编写需要获取的Item字段)
3.制作爬虫 (编写spiders/xxspider.py)(分析responses并提取数据)
4.存储内容 (编写pipelines.py)(分析筛选数据并储存)

1.新建项目
命令:scrapy startproject projectname
projectname为需要指定的项目名

Python爬虫框架【Scrapy】

进入项目并利用tree命令输出项目结构

Python爬虫框架【Scrapy】

各文件作用
scrapy.cfg: 项目的配置文件。
TestSpider/: 项目的Python模块,将会从这里引用代码。
TestSpider/items.py: 项目的目标文件。
TestSpider/pipelines.py: 项目的管道文件。
TestSpider/settings.py: 项目的设置文件。
TestSpider/spiders/: 存储爬虫代码目录。

2.确定爬取目标(编写items.py)
我们以爬取菜鸟教程为例,网址: http://www.runoob.com/
需要的数据为 教程名 图片url 简要描述 教程url

Python爬虫框架【Scrapy】

编辑items.py如下:
Item定义了一个结构化数据字段,类似于字典,用于保存爬取到的数据
import scrapy
class TestspiderItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    name = scrapy.Field() # 教程名
    img_url = scrapy.Field() # 图片地址
    desc = scrapy.Field() # 描述
    url = scrapy.Field() # 教程链接

3.制作爬虫 (编写spiders/xxspider.py)
在项目目录中输入命令
命令:scrapy genspider spidername 'start_url'
            spidername 为需要指定的爬虫名称
            start_url为初始爬取地址
此时会在spiders目录中创建spidername.py文件,并添加必须的代码

Python爬虫框架【Scrapy】

import scrapy

class RunoobSpider(scrapy.Spider):
    name = 'runoob'
    allowed_domains = ['www.runoob.com']
    start_urls = ['http://www.runoob.com/']

    def parse(self, response):
        pass
当然,使用命令不是必需的,也可以选择自己创建和编写
但使用命令帮我们免去了写一些必须代码的麻烦

在此基础上,根据我们的需求编写爬虫代码
编写代码如下:
import scrapy
# 导入在items中写好的类
from TestSpider.items import TestspiderItem 

# 编写爬虫
class RunoobSpider(scrapy.Spider):
    name = 'runoob'  # 文件名
    allowed_domains = ['www.runoob.com'] # 允许访问的网址
    start_urls = ['http://www.runoob.com/'] # 开始访问的网址

    def parse(self, response):
        course = TestspiderItem() # 实例化一个Item数据对象
        # 获取class为"item-top item-1"的节点
        courseInfos = response.xpath('//a[@class="item-top item-1"]') 
        # 遍历节点
        for courseInfo in courseInfos:
            # 根据需求提取指定数据并存入Item的对象中
            course['url'] = courseInfo.xpath('@href')[0].extract()
            course['name'] = courseInfo.xpath('.//h5/text()')[0].extract()
            course['img_url'] = courseInfo.xpath('.//img/@src')[0].extract()
            course['desc'] = courseInfo.xpath('.//strong/text()')[0].extract()
            # 输出测试文件观察获取数据是否正确
            #open('test.log','w').write('%s\n%s\n%s\n%s'%(type(course['url']),course['name'],type(course['img_url']),type(course['desc'])))
            # 返回数据
            yield course
查看test.log中的数据

Python爬虫框架【Scrapy】


4.存储内容 (编写pipelines.py)
(1)使用命令存储:
scrapy crawl spidername -o spidername.(json|jsonl|csv|xml) 
以json / json lines / csv / xml格式存储在当前路径下

Python爬虫框架【Scrapy】

存储的csv文件,默认按照ASCII码编码顺序排列

Python爬虫框架【Scrapy】


(2)编写pipelines.py(需要设置setting)自定义存储
定义一个管道类,完成写入操作
>>>>>>>>
保存至文件,保存json格式数据,文件名为runoob.txt
class TestspiderPipeline(object):
    # 以‘只写’方式打开runoob.txt文件
    def __init__(self):
        self.f = open('runoob.txt','w')

    # pipeline中执行的程序
    def process_item(self, item, spider):
        # 测试语句,item返回的是获取到的Item数据类型(前面定义过的类型)
        # open('runoob.log','w').write(str(type(item)))

        # 存储为json格式,不使用ascii编码,缩进为4
        import json
        line = json.dumps(dict(item),ensure_ascii=False,indent=4)
        self.f.write(line+'\n')
        return item

    # 关闭文件
    def close_spider(self):
        self.f.close()
>>>>>>>>
保存至MySQL数据库
创建数据库runoob并指定utf8编码格式(create database runoob default charset=utf8;)

Python爬虫框架【Scrapy】

class MysqlPipeline(object):

    def __init__(self):
        # 构造时链接数据库
        import pymysql
        self.conn =pymysql.connect(
            host='localhost',
            user='root',
            password ='redhat',
            database ='runoob',
            charset ='utf8',
            autocommit = True
        )

        # 创建游标
        self.cur = self.conn.cursor()

        # 创建数据表
        create_sqli = 'create table if not exists course(教程名称 varchar(50),链接 varchar(300),教程简介 varchar(200))'
        self.cur.execute(create_sqli)

    def process_item(self, item, spider):
        # 插入数据
        insert_sqli = 'insert into course values("%s","%s","%s") '%(item['name'],item['url'],item['desc'])
        self.cur.execute(insert_sqli)
        return item

    def close_spider(self):
        # 关闭游标和连接
        self.cur.close()
        self.conn.close()
>>>>>>>>
保存媒体图片
# 图片存储
class ImagePipeline(ImagesPipeline):
    # 获取媒体请求
    def get_media_requests(self, item, info):
        # 测试语句
        # open('mooc.log','w').write(item['img_url'])

        # 返回图片
        yield scrapy.Request(item['img_url'])

    # results是返回的一个元组(True ,{'url':xxx,'path':xxx,'checksum':xxx})
    # info返回的是一个对象scrapy.pipelines.media.MediaPipeline.SpiderInfo 
    def item_completed(self, results, item, info):
        # 测试语句
        # for i in results:
        #     open('ni.txt', 'w').write(str(i)+'\n'+str(info))

        # 获取results中的path
        image_path = [x['path'] for ok,x in results if ok]

        # path为None,则不包含图片,否则返回item
        if not image_path:
            raise  Exception('不包含图片')
        else:
            return item
保存图片还需要在settings.py中设置图片保存的路径
管道默认不执行,需要在settings.py中修改设置
后面的数字设定优先级,数字越小,优先级越高

Python爬虫框架【Scrapy】


执行爬虫并查看保存的数据

执行爬虫
在工程路径中输入命令
命令: scrapy crawl spidername
           spidername为爬虫文件名

查看数据
文件

Python爬虫框架【Scrapy】

数据库

Python爬虫框架【Scrapy】

图片

Python爬虫框架【Scrapy】


网站名称:Python爬虫框架【Scrapy】
浏览地址:http://myzitong.com/article/jhcpsd.html