Scrapy爬虫实战:升级版弹琴吧Spider

上回书咱们说道,利用python的urllib(网络请求)和BeautifulSoup(html数据筛选)和sqlite3(数据库)这三个库来实现一个简单的对弹琴吧4万曲谱信息的爬取,但是缺点是明显的,首先程序过于简陋,存在bug(遇到部分页面突然停止掉),其次程序运行过慢,因为是单线程运行,导致全部爬取完大概需要7-8个小时的时间。故对爬虫深入研究之后,决定利用Scrapy对程序进行升级,提高爬虫效率。

1. anaconda下安装Scrapy

命令行下输入安装命令即可:

conda install scrapy

2. 创建项目

使用PyCharm创建新的python项目,然后打开Terminal控制台,输入Scrapy创建项目命令:

scrapy startproject tanqinba

《Scrapy爬虫实战:升级版弹琴吧Spider》 image.png

3.项目目录分析

《Scrapy爬虫实战:升级版弹琴吧Spider》 image.png

在这里简单讲解一下Scrapy的流程,我们之后要在spiders目录下面建立自己的spider类用来编写爬虫代码,spider类会继承scrapy.Spider类并实现parse方法,我们在parse方法里面用xpath的方式获取到网页数据后生成数据类后用yield返回,此时就会通知pipelines类的process_item方法执行,我们在这个方法里面编写数据的存储操作即可。具体的流程还有待研究,可以参考官方的开发文档。

4. 编写代码

  1. 编写items类的代码:
    首先我们要明确我们要从网页中获取什么数据,上回书咱们也说了,我们要获取弹琴吧的钢琴谱的url,名称,歌手,描述,查看数,收藏数,难度级别,上传者和上传时间一共九个信息,用这些来创建数据类:
import scrapy

class TanqinbaItem(scrapy.Item):
    # define the fields for your item here like:
    name = scrapy.Field()
    url = scrapy.Field()
    des = scrapy.Field()
    singer = scrapy.Field()
    seeNum = scrapy.Field()
    collectNum = scrapy.Field()
    hard = scrapy.Field()
    user = scrapy.Field()
    time = scrapy.Field()
    pass
  1. 编写pipelines类的代码:
import sqlite3
conn = sqlite3.connect('tanqinba.db')
cursor = conn.cursor()
class TanqinbaPipeline(object):

    def __init__(self):
        cursor.execute('create table tanqinba (id INTEGER primary key AUTOINCREMENT, piano_url varchar(20),'
                      'piano_name varchar(20),piano_des varchar(800),piano_singer varchar(20),'
                      'piano_seeNum varchar(20),piano_collectNum varchar(20),piano_hard varchar(20),'
                      'piano_uploadUser varchar(20),piano_uploadTime varchar(20))')

    def process_item(self, item, spider):

        print(item)
        print('正在保存信息至数据库')
        sql = '''
            insert into tanqinba 
            (piano_url, piano_name,piano_des,piano_singer,piano_seeNum,piano_collectNum,piano_hard,piano_uploadUser,piano_uploadTime) 
            values 
            (:pi_url, :pi_name,:pi_des,:pi_singer,:pi_seeNum,:pi_collectNum,:pi_hard,:pi_uploadUser,:pi_uploadTime)
            '''
        cursor.execute(sql,{'pi_url':item['url'],'pi_name':item['name'],'pi_des':item['des'],'pi_singer':item['singer'],'pi_seeNum':item['seeNum'],'pi_collectNum':item['collectNum'],'pi_hard':item['hard'],'pi_uploadUser':item['user'],'pi_uploadTime':item['time']})

        conn.commit()

在这里我们首先在init方法里面创建数据库,如果是已经创建好了的,就将这个方法注释掉,不然会报错。
其次,在process_item方法里面编写插入数据的代码,这里没有关闭数据库连接的代码,因为测试都是用ctrl+c来结束程序运行的,所以我没有写关闭数据库的语句。

  1. 编写settings类
    在settings类中加入一条语句:
ITEM_PIPELINES = {'tanqinba.pipelines.TanqinbaPipeline':100}

指定用来处理数据的类以及优先级

  1. 编写爬虫类
    重点来了。在spiders目录下面新建tanqinba.py文件,并编写爬虫代码:
import scrapy

from ..items import TanqinbaItem

class TanqinbaSpider(scrapy.Spider):
    name = "tanqinba"
    allowed_domains = ["tan8.com"]
    start_urls = ['http://www.tan8.com/yuepu-%s.html' % x for x in range(0,70000)]


    def parse(self, response):
        # 获取所有图片的a标签
        print('---------parse--------')
        item = TanqinbaItem()
        item['url'] = response.url
        item['name'] = response.xpath('//div[@class="yuepu_name_0421"]/h1[@class="title_color"]/text()').extract()[0]
        item['singer'] = response.xpath('//div[@class="yuepu_name_0421"]//a/i/text()').extract()[0]
        item['seeNum'] = response.xpath('//div[@class="yuepu_name_0421"]//span[@class="brief_color eyes"]/text()').extract()[0]
        item['des'] = response.xpath('//p[@class="brief_0421 content_color"]/text()').extract()[0]
        item['collectNum'] = response.xpath('//div[@class="yuepu_name_0421"]//span[@class="brief_color xin c-num"]/text()').extract()[0]
        item['hard'] = response.xpath('//div[@class="yuepu_name_0421"]//span[@class="brief_color"]/text()').extract()[1]
        try:
            item['user'] = response.xpath('//div[@class="col_243"]//h3[@class="title_color"]/text()').extract()[0]
        except IndexError as e:
            item['user'] = '未定义'
        item['time'] = response.xpath('//div[@class="col_243"]//p[@class="brief_color"]/text()').extract()[1]

        # 返回爬取到的数据
        yield item

代码比较简单,这里不做详细描述,需要注意的是start_urls是定义了一个url集合,弹琴吧的曲谱的url都是有固定套路的,类似这种http://www.tan8.com/yuepu-150.html,中间的150数字代表乐谱的编号,测试过程中大概70000左右就会没有了,所以我们用列表生成式来生成0-70000这些链接地址。
另外xpath是比BeautifulSoup好用的一个html选择器(个人认为),建议深入学习。

5. 运行结果

测试中运行速度大概为4秒钟66首,全部完成大概需要1.1个小时,比上一篇的方法用的7-8个小时节省了大量的时间。

《Scrapy爬虫实战:升级版弹琴吧Spider》 image.png

6. 结语

Github:https://github.com/FlyMantou/tanqinba_scrapy

    原文作者:逍遥才子
    原文地址: https://www.jianshu.com/p/936f9e96254f
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞