爬虫综合案例-使用Scrapy爬取当当网的图片信息

目标

本节将继续讲解 Scrapy 框架的使用。具体包括 Scrapy 爬虫框架以及内部每个组件的使用(Selector 选择器、Spider 爬虫类、Downloader 和 Spider 中间件、ItemPipeline 管道类等)。

本例目标是爬取当当图书网站中所有关于 “python” 关键字的图片信息,网址http://search.dangdang.com/?key=python&act=input,要求将图书图片下载存储到指定目录,而图书信息写入到数据库中。

通过本例练习,要掌握 Scrapy 框架结构、运行原理、以及框架内部各个组件的使用。通过 Scrapy 框架的深入学习,学会自定义 Spider类爬取处理信息。

操作

运行爬虫之前,请导入 pythonbook.sql 到 MySQL。

  • 第1步,创建工程

新建文件夹,用于存放项目。然后在命令行窗口中使用cd命令切换到当前目录,再输入下面命令创建Scrapy项目。

scrapy startproject dangdang
  • 第2步,创建爬虫程序

使用cd命令切换到dangdang目录,再输入下面命令创建Scrapy程序。

cd dangdang
scrapy genspider pythonbook search.dangdang.com
  • 第3步,自动创建目录及文件

完成前面2步操作,Scrapy会自动在指定文件夹中创建一个项目,并初始化爬虫程序文件的模板,如下图所示。
在这里插入图片描述
注意,一般创建爬虫文件时,以网站域名命名。

  • 第4步,设置数据存储模板

打开items.py文件,然后输入下面代码,设置数据存储的模板。

import scrapy


class DangdangItem(scrapy.Item):
    '''
      当当图书的Item 类,包含所有要爬取的信息
    '''

    # define the fields for your item here like:
    # name = scrapy.Field()

    name        = scrapy.Field() # 书名
    price       = scrapy.Field() # 价格
    pic         = scrapy.Field() # 图片链接
    author      = scrapy.Field() # 作者
    publisher   = scrapy.Field() # 出版商
    comments    = scrapy.Field() # 评论数量
    pubdate     = scrapy.Field() # 发行日期
    description = scrapy.Field() # 描述
  • 第5步,编写爬虫程序

在spiders子目录中打开pythonbook.py文件,然后输入下面代码,设置下载器开始下载的页面URL。以及爬虫要爬取的HTML结构片段。最后,使用for循环和迭代器,把每一个项目结构片段传递给items.py定义的字段模板。

完成本步操作之前,读者应该先熟悉目标页面的结构,以及要抓取的HTML片段,同时熟悉XPath基本语法,可以先使用浏览器访问该页面,使用F12键,查看一下HTML结构。

import scrapy, re
from dangdang.items import DangdangItem


class PythonbookPySpider(scrapy.Spider):
    name = 'pythonbook'
    allowed_domains = ['search.dangdang.com']
    start_urls = ['http://search.dangdang.com/?key=python&act=input']

    p = 1 # 爬取页数变量

    def parse(self, response):
        '''
          递归解析响应数据
        '''

        print('*'*64)

        dlist = response.selector.xpath(".//ul[@class='bigimg']/li")

        for dd in dlist:
            item = DangdangItem()
            item['name'] = dd.xpath("./a/@title").extract_first() #good
            price = dd.xpath(".//span[@class='search_now_price']").extract_first()
            price = re.findall(".*?([0-9]*\.[0-9]*)",price)
            if(price[0]):
                item['price'] = price[0]
            else:
                item['price'] = None
            item['pic'] = dd.xpath(".//img/@data-original|.//img/@src").extract_first()
            item['author'] = dd.xpath(".//a[@name='itemlist-author']/@title").extract_first()
            item['publisher'] = dd.xpath(".//a[@name='P_cbs']/text()").extract_first() #good
            item['comments'] = dd.xpath(".//a[@class='search_comment_num']/text()").extract_first() #wrong
            item['pubdate'] = dd.re_first("(([0-9]{4})-([0-9]{2})-([0-9]{2}))") #good
            item['description'] = dd.xpath(".//p[@class='detail']/text()").extract_first() # good

            yield item

        self.p += 1

        # 想爬取多少页?
        if(self.p<=10):
            next_url = "http://search.dangdang.com/?key=python&act=input&page_index=" + str(self.p)
            url = response.urljoin(next_url)
            yield scrapy.Request(url=url, callback=self.parse)
  • 第6步,设置配置文件

打开settings.py文件,然后添加下面代码。

           
BOT_NAME = 'dangdang'

SPIDER_MODULES = ['dangdang.spiders']
NEWSPIDER_MODULE = 'dangdang.spiders'

USER_AGENT = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36'

ITEM_PIPELINES = {
    'dangdang.pipelines.DangdangPipeline': 300, # 处理item的类
    'dangdang.pipelines.MysqlPipeline'   : 301, # 把item写入数据库的类
    'dangdang.pipelines.ImagePipeline'   : 302, # 下载图片的类
}
MYSQL_HOST = 'localhost'
MYSQL_DATABASE = 'dangdang'
MYSQL_USER = 'root'
MYSQL_PASS = '11111111'
MYSQL_PORT = 3306
IMAGES_STORE = "./dangdang_images" # 存储图片的文件夹
  • 第7步,编写数据处理脚本

打开pipelines.py文件,输入代码。设计图片下载和数据库存储。

import pymysql
from scrapy.exceptions import DropItem
from scrapy import Request
from scrapy.pipelines.images import ImagesPipeline


class DangdangPipeline(object):
    '''处理item的类'''

    def process_item(self, item, spider):
        '''
        处理爬取数据,如果爬取的书名没有,就把这条记录剔除。
        :param item: 爬虫item类
        :param spider: 爬虫超类
        :return: 剔除条目或者item
        '''
        if item['name'] == None:
            raise DropItem("Drop item found: %s" % item)
        else:
            return item


class MysqlPipeline(object):
    '''处理item写入数据库的类'''

    def __init__(self, host, database, user, password, port):
        '''
        构造类,创建全局变量
        :param host: 数据库主机路径
        :param database: 数据库名称
        :param user: 数据库用户名
        :param password: 数据库密码
        :param port: 数据库端口
        '''
        self.host = host
        self.database = database
        self.user = user
        self.password = password
        self.port = port
        self.db = None
        self.cursor = None

    @classmethod
    def from_crawler(cls, crawler):
        '''
        类方法,用此方法获取数据库相应信息来连接数据库
        :param crawler: crawler类
        :return: 带有数据库信息的类。在这里调用类构造方法
        '''
        return cls(
            host=crawler.settings.get("MYSQL_HOST"),
            database=crawler.settings.get("MYSQL_DATABASE"),
            user=crawler.settings.get("MYSQL_USER"),
            password=crawler.settings.get("MYSQL_PASS"),
            port=crawler.settings.get("MYSQL_PORT")
        )

    def open_spider(self, spider):
        '''
        通过设置文件里的信息链接到数据库,并准备好游标以便后面使用
        :param spider:
        :return:
        '''
        self.db = pymysql.connect(self.host, self.user, self.password, self.database, charset='utf8', port=self.port)
        self.cursor = self.db.cursor()

    def process_item(self, item, spider):
        '''
        执行插入操作,将item相应信息插入数据库并保存
        :param item: 爬虫item类
        :param spider: spider超类
        :return: 爬虫item类
        '''
        sql = "insert into pythonbook(name,price,pic,author,publisher,comments, pubdate, description) values('%s','%s','%s','%s','%s','%s', '%s', '%s')"%(item['name'],item['price'],item['pic'],item['author'],item['publisher'],item['comments'], item['pubdate'],item['description'])
        self.cursor.execute(sql)
        self.db.commit()
        return item

    def close_spider(self, spider):
        '''
        关闭数据库连接
        '''
        self.db.close()


class ImagePipeline(ImagesPipeline):
    '''处理图像的类'''

    def get_media_requests(self, item, info):
        '''
        从item内拿到图片url信息,创建Request等待调度执行
        :param item: 爬虫item类
        :param info: 消息
        :return: None, yield一个带图片URL的Request
        '''
        yield Request(item['pic'])

    def item_completed(self, results, item, info):
        '''
        下载完成后,如果url不是有效的,就筛选掉这个数据。
        :param results:
        :param item:
        :param info:
        :return: 爬虫item类
        '''
        image_paths = [x['path'] for ok, x in results if ok]
        if not image_paths:
            raise DropItem("Item contains no images")

        return item
  • 第8步,执行爬虫

到上面一步,已经完成了爬虫程序的全部设计,下面就可以测试爬虫的工作状态了,在命令行窗口,使用cd命令进入dangdang目录,然后使用scrapy crawl命令进行测试。

           
scrapy crawl pythonbook

执行结果如下图:
在这里插入图片描述
在这里插入图片描述

  • 10
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Token_w

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值