分布式爬虫(三):scrapy之中国网库

  距离上一篇博客时间过去了十几天,因学校毕业季以及考试的事情一直耽搁着。也在昨天小编成功收拾完宿舍的行李申请离校,跨出校门那一刻,挥手与舍友同学告别时,心头泛起说不清的感觉。但我知道“帷幕不会就此落下”,我们终将会有再“聚首”的时刻。在这里也预祝大家中秋国庆快乐!!! 回归正题,之前基本配置了虚拟机的环境,现在我们来认识了解scrapy框架爬虫的魅力。

操作环境: Windows10、Python3.6、Pycharm2019.3.1、谷歌浏览器、cmd、SQLyog

目标网址: http://www.99114.com/(中国网库)

相关文章: 分布式爬虫(一):配置虚拟机
      分布式爬虫(二):配置安装Python以及redis


一、Scrapy框架的介绍

  Scrapy框架是学习爬虫道路上必不可少的一环,许多人都说:“requests是一辆汽车的零件,而Scrapy是一辆汽车”。通过比较可知晓用requests模块写爬虫需要我们一点点的组合配置起来才能“运行”,而scrapy框架已经帮我们搭建好了一辆汽车模型,我们只需要“操控、运行”它即可。

1.1、简介

  Scrapy框架亦是现在大众最钟情的框架之一,它是一个开源的高级爬虫框架,用于爬取网页,提取结构性数据,并可将抓取得结构性数据较好的应用于数据分析和数据挖掘。scrapy框架有如下特点:

  • scrapy基于事件的机制,利用twisted的设计实现了非阻塞的异步操作。这相比于传统的阻塞式请求,极大的提高了CPU的使用率,以及爬取效率。(自带多线程)

  • 配置简单,可以简单的通过设置一行代码实现复杂功能。

  • 可拓展,插件丰富,比如分布式scrapy-redis、爬虫可视化等插件。

  • 解析方便易用,scrapy封装了xpath、css等解析器,提供了更方便更高级的Selector对象构造器,可有效的处理破损的HTML代码和编码。

Scrapy框架的官方流程架构图:
在这里插入图片描述

  1. Scrapy Engine(引擎):负责Spider、ItemPipeline、Downloader、Scheduler中间的通讯,传递信号、数据等。
  2. Scheduler(调度器):负责接受引擎发送过来的Request请求,并按照一定的方式进行整理排列,入队,当引擎需要时,交还给引擎。
  3. Downloader(下载器):负责下载Scrapy Engine(引擎)发送的所有Requests请求,并将其获取到的Responses交还给Scrapy Engine(引擎),由引擎交给Spider来处理;
  4. Spider(爬虫):它负责处理所有Responses,从中分析提取数据,获取Item字段需要的数据,并将需要跟进的URL提交给引擎,再次进入Scheduler。
  5. Item Pipeline(管道):它负责处理Spider中获取到的Item,并进行进行后期处理(详细分析、过滤、存储等)的地方。
  6. Downloader Middlewares(下载中间件):自定义扩展引擎和下载中间的组件。
  7. Spider Middlewares(爬虫中间件):自定义扩展、操作引擎和爬虫中间通信的功能组件。

1.2、安装与创建

  在Windows系统下,使用scrapy框架前先安装两个库:scrapy、pypiwin32,否则运行scrapy项目会报错。

pip install scrapy
pip install pypiwin32

 创建scrapy项目:(注:打开终端,将路径切换到你所放置爬虫的目录下即可)
  scrapy startproject [项目的名字]
 创建scrapy爬虫:(注:先cd切换到刚刚创建的项目名称下)
  scrapy genspider [爬虫名字] [目标网址的域名] (注意爬虫的名字和项目不可重复!)

  scrapy项目创建完成效果如下:
在这里插入图片描述

1.3、简单配置

  打开settings.py配置文件

  1. 加入LOG_LEVEL = “WARNING”,设置日志级别,把低于warning的日志全部屏蔽不显示。
  2. ROBOTSTXT_OBEY = False,将True改成False,将robots君子协议关掉。
  3. DEFAULT_REQUEST_HEADERS,将注释取消,打开请求头,添加User-gent等信息。

  运行爬虫文件有两种方法:

  1. 终端cd切换到项目文件下,输入scrapy crawl spider_library 命令即可运行,注:spider_library为爬虫文件名;
  2. 在项目文件路径下新建run_spider.py文件,直接运行此文件即可。
# -*- coding = utf-8 -*-
from scrapy import cmdline

cmdline.execute("scrapy crawl spider_library".split())

在这里插入图片描述


二、中国网库

  目标网址:http://www.99114.com/

  中国网库为静态网站,直接请求获取即可,并不存在加密反爬措施。
在这里插入图片描述

2.1、分析网页

  我们接下来要获取的数据在网页左侧的分类类别中:
在这里插入图片描述
  由图片可看出需要获取的二级数据链接共有608个!
在这里插入图片描述
执行代码为:
contains: xpath语法中的指定一个class属性值;

import scrapy

class SpiderLibrarySpider(scrapy.Spider):  # 继承Spider类
    name = 'spider_library'     # 爬虫的唯一标识,不能重复,启动爬虫文件的时候使用到
    allowed_domains = ['99114.com']  # 限定域名,只能爬取该域名下的网页
    start_urls = ['http://www.99114.com/']  # 开始爬取的链接url

    def parse(self, response):
        href_list = []
        # 定义一级分类节点
        lis = response.xpath('//div[contains(@class,"float-layer")]/div[contains(@class,"text-content")]/div[@class="content-left"]/div[@class="item-ctn"]/ul/li')
        for li in lis:
            # 获取二级分类详情链接
            href_url = li.xpath('./a/@href').extract_first()
            href_list.append(href_url)

        print(len(href_list))

验证输出长度结果为608,与之前网页查看的一致,数据链接提取无误!
在这里插入图片描述
  定义一个get_commodity_url函数,用于获取商品的详情链接,使用yield生成器将商品链接传给指定的函数进行解析。详细的yield生成器解析就不多介绍,大家可自行百度解答。

  url: 请求的链接
  callback: 回调函数,指定传输的函数名

class SpiderLibrarySpider(scrapy.Spider):  # 继承Spider类
    name = 'spider_library'     # 爬虫的唯一标识,不能重复,启动爬虫文件的时候使用到
    allowed_domains = ['99114.com']  # 限定域名,只能爬取该域名下的网页
    start_urls = ['http://www.99114.com/']  # 开始爬取的链接url

    def parse(self, response):
        # 定义一级分类节点
        lis = response.xpath('//div[contains(@class,"float-layer")]/div[contains(@class,"text-content")]/div[@class="content-left"]/div[@class="item-ctn"]/ul/li')
        for li in lis:
            # 获取二级分类详情链接
            href_url = li.xpath('./a/@href').extract_first()

            yield scrapy.Request(
                url=href_url,callback=self.get_commodity_url
            )

    '''获取商品的详情链接'''
    def get_commodity_url(self,response):
        pass

2.2、列表页

 这里以饼干商品为例解析:
  每一个item属性的div标签为商品标签。
在这里插入图片描述


  提取每个商品的详情页链接href_url,并将其传给get_detail_data函数进行数据提取;

  获取下一页的链接,回调给自身函数,实现翻页效果。

    '''获取商品的详情链接'''
    def get_commodity_url(self,response):
        divs = response.xpath('//div[@id="J_itemlistCont"]/div')
        for div in divs:
            # 商品的详情链接
            href_url = div.xpath('.//div[@class="row row-2"]/a/@href').extract_first()
            # print(href_url)

            yield scrapy.Request(
                url=href_url,callback=self.get_detail_data
            )

        # 翻页:
        next_url = response.xpath('//div[@class="wraper"]//ul[@class="items"]/li[last()]/a/@href').extract_first()
        if next_url:
            next_url = 'http://gongying.99114.com' + next_url  # 补全连接
	
            yield scrapy.Request(
                url=next_url,callback=self.get_commodity_url
            )

2.3、详情页

  使用红色框框括起来的字段皆为需要获取数据:
在这里插入图片描述

  使用xpath语法提取数据以及正则re.sub替换清理数据。(获取的字段数据:标题、现价、市场价、累积成交量、发货期、发货地、库存、公司名、卖家电话、卖家名称、经营模式、主营业务)

'''获取详情数据'''
def get_detail_data(self,response):
    title = response.xpath('//div[@class="proTitle textC"]/h1/text()').extract_first().strip()  # 标题
    # 现价
    Current_price = ''.join(response.xpath('//tr[@class="tr-first"]/td[2]//text()').extract())
    Current_price = re.sub(r'[\n\t\s]','',Current_price)

    tr1 = response.xpath('//div[@class="dp-table2 xunpanT"]/table//tr[1]')
    # 市场价
    market_price = ''.join(tr1.xpath('./td[1]//text()').extract())
    market_price = re.sub(r'[市场价:\n\t\s]','',market_price)
    # 累积成交量
    Cumulative_volume = tr1.xpath('./td[2]//span/text()').extract_first()

    tr4 = response.xpath('//div[@class="dp-table2 xunpanT"]/table//tr[4]')
    # 发货期
    Delivery_date = ''.join(tr4.xpath('./td[1]//text()').extract())
    Delivery_date = re.sub(r'[发货期:\n\t\s]','',Delivery_date)
    # 发货地
    Delivery_place = tr4.xpath('./td[2]/span/text()').extract_first()
    Delivery_place = '' if not Delivery_place else re.sub(r'[\n\t\s]','',Delivery_place)
    # 库存
    stock = response.xpath('//dl[@class="clearfix interval_bean"]/dd[2]/text()').extract_first()
    # 公司
    company = response.xpath('//p[@class="companyname"]/span/a/text()').extract_first()
    # 卖家电话、名称
    seller_phone = response.xpath('//div[@class="hotline"]/em/text()').extract_first()
    seller_name = response.xpath('//i[@class="bold"]/text()').extract_first()
    # 经营模式
    Business_model = response.xpath('//div[@class="sj-line sjDiv2"]/p[2]/span[2]/text()').extract_first()
    # 主营业务
    Main_business = ''.join(response.xpath('//div[@class="sj-line sjDiv2"]/p[3]/span[2]//text()').extract())

输出的部位结果展示:
在这里插入图片描述

三、Item Pipeline(管道)

3.1、Item

 itmes.py:用来存放各种爬虫获取下来字段数据的模型。
在这里插入图片描述
还需要在爬虫文件spider_library.py文件中导入items.py文件中定义的类ChinaLibraryItem

from ..items import ChinaLibraryItem

item = ChinaLibraryItem(
    title=title,Current_price=Current_price,market_price=market_price,Cumulative_volume=Cumulative_volume,
    Delivery_date=Delivery_date,Delivery_place=Delivery_place,stock=stock,company=company,
    seller_phone=seller_phone,seller_name=seller_name,Business_model=Business_model,
    Main_business=Main_business
)
print(item)
yield item

3.2、Pipeline

 pipelines.py:用来将items的模型存储到本地磁盘中。(持久化存储:csv、excel、mysql等等)

 使用pipelines.py存储数据前,首先将settings.py配置文件里的ITEM_PIPELINES注释打开:
在这里插入图片描述
 pipelines.py文件,存入mysql数据库。

import pymysql
class MySQLPipeline:
    def __init__(self):
        # 建立MySQL链接对象
        self.connect = pymysql.connect(
            host='localhost',           # ip
            port=3306,                  # 端口
            user='root',                # 用户名
            password='cjs122374',       # 密码
            charset='utf8'              # 编码格式
        )
        self.cursor = self.connect.cursor()  # 执行命令游标
        # 判断是否存在数据库,不存在则创建,并进入数据库
        self.cursor.execute("drop database if exists China_spider")
        self.cursor.execute("create database if not exists China_spider character set 'utf8'")
        self.cursor.execute("use China_spider")

        # 判断是否存在数据表,不存在则创建
        self.cursor.execute("drop table if exists spider_library;")
        china_sql = '''CREATE TABLE spider_library(title varchar(250),Current_price varchar(50),market_price varchar(50),
        Cumulative_volume varchar(20),Delivery_date varchar(20),Delivery_place varchar(150),stock varchar(50),
        company varchar(150),seller_phone varchar(11),seller_name varchar(50),Business_model varchar(150),
        Main_business varchar(255));'''
        self.cursor.execute(china_sql)

    def process_item(self, item, spider):
        try:
            self.cursor.execute("insert into spider_library values (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)",
                                list(dict(item).values()))  # 插入代码语句
            print('插入成功')
        except Exception as e:
            print('插入错误:', e)  # 打印插入错误原因
            self.connect.rollback()  # 回滚事务,不插入数据
        else:
            self.connect.commit()  # 提交事务,插入成功数据
        return item

    def close_spider(self, spider):
        self.cursor.close()  # 关闭游标
        self.connect.close()  # 关闭数据库链接
        print('爬虫已结束')

 执行爬虫文件run_spider.py;等待半小时,使用SQLyog可视化端查看获取的数据量:12386条数据。

# 查询spider_library表
SELECT * FROM spider_library; 

在这里插入图片描述

四、项目总结

  本次爬虫项目只为分布式爬虫写个基础框架代码,方便大家了解框架爬虫的运行步骤文件的搭配使用。下一篇博客将以此份代码为基础,修改为scrapy-redis分布式爬虫,部署到虚拟机上进行双系统同时进行爬取!!!

  “赠人玫瑰,手有余香”,看完的小伙伴记得点赞收藏,感谢!

  若有小伙伴有疑惑的地方,可在评论区留言,小编看到会尽快一一回复;此项目有需要改进的地方,也请大佬不吝赐教,感谢!

  注:本项目仅用于学习用途,若用于商业用途,请自行负责!!

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值