4. scrapy框架基础

 

 

scrapy框架基础

1.安装

Linux安装:
    pip install scrapy

Windows安装:
    1.pip install wheel -- 可以安装 .whl文件
    2.下载twisted <http://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted>
        - 找到对应自己电脑python版本
    3.进入下载目录,执行 pip install Twisted‑17.1.0‑cp35‑cp35m‑win_amd64.whl(下载的文件)
    4.pip install pywin32
    5.pip install scrapy  -- 安装scrapy爬虫框架

2.基本操作

1.创建一个工程:scrapy startproject 工程名
        - 工程目录中:
            - spiders:爬虫包
            - settings:工程的配置文件
2.创建一个爬虫文件:
	cd 工程名 -- 进入工程目录
	scrapy genspider 爬虫文件名 www.xxx.com(随意网站,文件里能改)
    -数据的爬取和解析是需要编写在爬虫文件中
3.执行工程:scrapy crawl 文件名
        - 程序会输出各种日志信息
            - 指定输入日志的类型:settings配置文件:LOG_LEVEL= 'ERROR'
        - robots.txt协议:君子协议,限制爬虫。
            - 如何忽略该协议:settings配置文件:ROBOTSTXT_OBEY = False

简单使用

import scrapy

class FirstSpider(scrapy.Spider):
    #爬虫文件的名称:表示当前爬虫文件的唯一标识
    name = 'first'
    #允许的域名
    # allowed_domains = ['www.baidu.com']
    #起始url列表:列表中存放的url可以被scrapy进行get请求发送
    start_urls = ['https://www.baidu.com/','https://www.jd.com']
    #数据解析:response响应对象
    def parse(self, response):
        print(response)

3.示例 -- 糗事百科 - 段子

解析数据:

settings配置上User-Agent
多页解析时:
- 手动请求发送:
1.get请求:
    yield scrapy.Request(url=new_url,callback=self.parse)
2.post请求:
    yield scrapy.FormRequest(url=new_url,callback=self.parse,formdata={})

spiders/qiubai.py

import scrapy

class QiubaiSpider(scrapy.Spider):
    name = 'qiubai'
    # allowed_domains = ['www.xxx.com']
    start_urls = ['https://www.qiushibaike.com/text/']

    # 1. 数据解析:解析第一页
    # def parse(self, response):
    #     div_list = response.xpath('//*[@id="content"]/div/div[2]/div')
    #     for div in div_list:
    #         #extract()可以将Selector对象中的data值取出
    #         # author = div.xpath('./div[1]/a[2]/h2/text()')[0].extract()
    #         author = div.xpath('./div[1]/a[2]/h2/text()').extract_first()
    #         #extract()返回的是列表
    #         content = div.xpath('./a[1]/div/span//text()').extract()
    #         content = ''.join(content)
    #         print(author,content)

    # 1.1 解析多页
    # 点击下一页通用的url模板
    url = 'https://www.qiushibaike.com/text/page/%d/'
    page_num = 2
    def parse(self, response):

        div_list = response.xpath('//*[@id="content"]/div/div[2]/div')
        for div in div_list:
            #extract()可以将Selector对象中的data值取出
            # author = div.xpath('./div[1]/a[2]/h2/text()')[0].extract()
            author = div.xpath('./div[1]/a[2]/h2/text()').extract_first()
            #extract()返回的是列表
            content = div.xpath('./a[1]/div/span//text()').extract()
            content = ''.join(content)
            print(author,content)
        # 手动请求发送
        if self.page_num < 6: #
            new_url = format(self.url%self.page_num)
            self.page_num += 1
            yield scrapy.Request(url=new_url,callback=self.parse)

持久化存储

- 方案:
	1.基于终端指令的持久化存储
        - 只可以将parase方法的返回值存储到指定后缀的文本文件中
        - 存储指令:scrapy crwal 爬虫文件名 -o 储存文件路径
	2.基于管道的持久化存储(重点)
        - 在爬虫文件中进行数据解析
        - 在items文件中声明数据解析出的字段属性
        - 在爬虫文件中将解析出的字段存储封装到items类型的对象中
        - 将item对象提交给管道
        - 在管道文件的类中实现任意形式的持久化存储操作
- 需要在配置文件中开启管道机制
    - 什么时候需要创建多个管道类?
    - 数据备份。一个管道类负责将数据存储到一种平台种。
- 注意:爬虫文件提交过来的item只会给优先级最高的那一个管道类
    - 如果保证其他的管道类都可以获取item对象:
    - 每个管道类都return item:将item提交给下一个即将被执行的管道类

1.基于终端指令的持久化存储

1.基于终端指令的持久化存储
    - 只可以将parase方法的返回值存储到指定后缀的文本文件中
    - 存储指令:scrapy crwal 爬虫文件名 -o 储存文件路径

spiders/qiubai.py

import scrapy

class QiubaiSpider(scrapy.Spider):
    name = 'qiubai'
    # allowed_domains = ['www.xxx.com']
    start_urls = ['https://www.qiushibaike.com/text/']
    all_list = []
    
    # 基于终端指令的持久化存储
    def parse(self, response):
        
        div_list = response.xpath('//*[@id="content"]/div/div[2]/div')
        for div in div_list:
            #extract()可以将Selector对象中的data值取出
            # author = div.xpath('./div[1]/a[2]/h2/text()')[0].extract()
            author = div.xpath('./div[1]/a[2]/h2/text()').extract_first()
            #extract()返回的是列表
            content = div.xpath('./a[1]/div/span//text()').extract()
            content = ''.join(content)
            print(author,content)
            dic = {
                'author':author,
                'content':content
            }
            self.all_list.append(dic)
        return self.all_list

执行项目

scrapy crawl qiubai -o 1.csv

2.基于管道的持久化存储(重点)

2.基于管道的持久化存储(重点)
    - 在爬虫文件中进行数据解析
    - 在items文件中声明数据解析出的字段属性
    - 在爬虫文件中将解析出的字段存储封装到items类型的对象中
    - 将item对象提交给管道
    - 在管道文件pipelines.py的类中实现任意形式的持久化存储操作
- 需要在配置文件中开启管道机制
    - 什么时候需要创建多个管道类?
    - 数据备份。一个管道类负责将数据存储到一种平台种。
- 注意:爬虫文件提交过来的item只会给优先级最高的那一个管道类
    - 如果保证其他的管道类都可以获取item对象:
    - 每个管道类都return item:将item提交给下一个即将被执行的管道类
    
redis-Windows安装:
    下载地址:https://github.com/tporadowski/redis/releases
     解压->cd到文件夹下:redis-server.exe redis.windows.conf

spiders/qiubai.py

import scrapy
from qiubaiPro.items import QiubaiproItem # 引入items类

class QiubaiSpider(scrapy.Spider):
    name = 'qiubai'
    # allowed_domains = ['www.xxx.com']
    start_urls = ['https://www.qiushibaike.com/text/']

	# 基于管道持久化存储
    def parse(self, response):
        div_list = response.xpath('//*[@id="content"]/div/div[2]/div')
        for div in div_list:
            #extract()可以将Selector对象中的data值取出
            # author = div.xpath('./div[1]/a[2]/h2/text()')[0].extract()
            author = div.xpath('./div[1]/a[2]/h2/text()').extract_first()
            #extract()返回的是列表
            content = div.xpath('./a[1]/div/span//text()').extract()
            content = ''.join(content)

            item = QiubaiproItem() # 实例化item对象,将解析出的值赋给item对象
            item['author']  = author
            item['content'] = content

            yield item # 将item对象提交给管道

items.py

import scrapy

class QiubaiproItem(scrapy.Item):
    # define the fields for your item here like:
    # 声明两个字段
    author = scrapy.Field()
    content = scrapy.Field()


settings.py

ITEM_PIPELINES = {
    #300表示的是管道类的优先级,数值越小表示优先级越高
   'qiubaiPro.pipelines.QiubaiproPipeline': 300,
   'qiubaiPro.pipelines.MySqlPipeLine': 301,
   'qiubaiPro.pipelines.RedisPipeLine': 302,
}

pipelines.py

import pymysql
from redis import Redis

# 将数据储存到本地文件
class QiubaiproPipeline:
    fp = None
    def open_spider(self,spider):#在开始爬取数据的时候被调用一次
        print('i am open_spider()')
        self.fp = open('./qiubai.txt','w',encoding='utf-8')

    # 参数item就是管道接收到的item对象
    # 该方法的调用次数取决于爬虫文件提交item的次数
    def process_item(self, item, spider):
        self.fp.write(item['author']+':'+item['content']+'\n')
        return item #将item提交给下一个即将被执行的管道类

    def close_spider(self,spider):#只会在爬虫结束时调用一次
        print('i am close_spider()')
        self.fp.close()

# 定义管道类,负责将数据存储到mysql
class MySqlPipeLine(object):
    conn =None
    cursor = None
    def open_spider(self,spider):
        # 创建连接
        self.conn = pymysql.Connect(host='127.0.0.1',port=3306,user='root',password='123456',db='qiushi',charset='utf8')

    def process_item(self,item,spider):
        # 创建游标对象
        self.cursor = self.conn.cursor()
        # sql语句插入数据
        sql = 'insert into qiubai values("%s","%s")'%(item['author'],item['content'])
        try:
            self.cursor.execute(sql) # 执行sql语句
            self.conn.commit() # 没有错误提交
        except Exception as e:
            print(e)
            self.conn.rollback() # 出错回滚
        return item

    def close_spider(self,spider):
        self.cursor.close() # 关闭游标
        self.conn.close() # 关闭连接

# 定义管道类,负责将数据存储到redis
# redis模块的版本2.10.6
class RedisPipeLine(object):
    conn = None
    def open_spider(self,spider):
        # 建立连接
        self.conn = Redis(host='127.0.0.1',port=6379)
    def process_item(self,item,spider):
        self.conn.lpush('qiubaiQueue',item)
        return item