Python爬虫入门 ~ scrapy数据结构与管道的使用

178 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第32天,点击查看活动详情

事前准备

该案例主要用来学习items.pypipelines.py的使用。还是老方法,先创建项目框架,然后创建自定义的爬虫文件。

scrapy startproject scrapy_dang
cd .\scrapy_dang\scrapy_dang\spiders\
 scrapy genspider dang http://category.dangdang.com/cp01.54.06.19.00.00.html

image.png

创建完成之后,先修改下目标地址,还有定位到我们需要的数据标签。

import scrapy

class DangSpider(scrapy.Spider):
    name = 'dang'
    allowed_domains = ['category.dangdang.com']
    start_urls = ['http://category.dangdang.com/cp01.54.06.19.00.00.html']

    def parse(self, response):
        li_list = response.xpath('.//ul[@class="bigimg"]/li')

        for li in li_list:
            src = li.xpath('.//img/@data-original').extract_first()
            if src is None:
                src = li.xpath('.//img/@src').extract_first()
            name = li.xpath('./a/@title').extract_first()
            price = li.xpath('.//span[@class="search_now_price"]/text()').extract_first()
            print(src, name, price)

image.png

items

数据拿到了,我们就需要使用items来自定义所需的一个数据格式了。通过scrapy.Field()将我们自定义的字段添加上即可。

class ScrapyDangItem(scrapy.Item):
    src = scrapy.Field()
    name = scrapy.Field()
    price = scrapy.Field()

image.png

定义完成之后,我们在自定义的爬虫文件中传入获取到的数据。

  1. 引入items,这里由报错不用管它,编译器显示错误,实际可以运行的
from scrapy_dang.items import ScrapyDangItem
  1. 传入参数
ScrapyDangItem(src=src, name=name, price=price)

image.png

pipelines

数据格式定义好了,那么就到了保存环节了。我们可以直接在pipelines文件中写保存操作。

class ScrapyDangPipeline:
    def process_item(self, item, spider):
        
        fp = open('books.json', 'a', encoding='utf-8')
        fp.write(str(item))
        
        return item

对了,这里记得一定要去settings文件中开启pipelines的启动开关并设置优先级。

image.png

将注释放开即可。

yield

目前到这里还不行,我们还少了最重要的一步,将数据交给pipelines。这就需要用到yield关键字了,该关键字主要有:

  1. yield的函数是一个generator生成器,可用于迭代
  2. 其类似于return关键字,它返回一个值,并且记住返回的位置,下次就从该位置后面开始。
book = ScrapyDangItem(src=src, name=name, price=price)
yield book

image.png

scrapy crawl dang

image.png

pipelines的前置/后置

运行之后可以看到多出来一个json文件,里面就有我们所需的数据了。但是这样的方式有很大问题,频繁的开启输入输出流,影响效率。我们可通过pipelines的前置函数与后置函数来实现一次开启,多次写入操作。

class ScrapyDangPipeline:
    def open_spider(self, spider):
        self.fp = open('books.json', 'w', encoding='utf-8')

    def process_item(self, item, spider):
        self.fp.write(str(item))

        return item


    def close_spider(self, spider):
        self.fp.close()

image.png

多页数据爬取

通过srcapy.Request()函数,我们可以重新发起请求,在请求中替换掉url属性即可实现翻页爬取。

import scrapy

from scrapy_dang.items import ScrapyDangItem

class DangSpider(scrapy.Spider):
    name = 'dang'
    allowed_domains = ['category.dangdang.com']
    start_urls = ['http://category.dangdang.com/cp01.54.06.19.00.00.html']
    head_url = 'http://category.dangdang.com/pg'
    page = 1
    tail_url = '-cp01.54.06.19.00.00.html'

    def parse(self, response):
        li_list = response.xpath('.//ul[@class="bigimg"]/li')

        for li in li_list:
            src = li.xpath('.//img/@data-original').extract_first()
            if src is None:
                src = li.xpath('.//img/@src').extract_first()
            name = li.xpath('./a/@title').extract_first()
            price = li.xpath('.//span[@class="search_now_price"]/text()').extract_first()
            print(src, name, price)
            book = ScrapyDangItem(src=src, name=name, price=price)
            yield book

        if self.page < 5:
            self.page = self.page + 1
            url = self.head_url + str(self.page) + self.tail_url
            yield scrapy.Request(url=url, callback=self.parse)

原先一页60条数据大概是240行左右,现在爬取了5页,1200左右可以匹配上。 image.png