scrapy:当当网案例

1. 创建爬虫项目

image-20230525105251508

image-20230525105456836

2. 创建爬虫文件

image-20230525105632909

image-20230525111314629

3. 运行测试是否目标网站反爬

image-20230525112117177

image-20230525112320300

测试ok没反爬

4. 定义数据结构&yield&实现爬虫&管道封装

image-20230525113747199

image-20230525134919042

import scrapy
from scrapy_dangdang_4.items import ScrapyDangdang4Item  # 这里编译报错没有关系,下面调用的地方不报错就行


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

    def parse(self, response):
        # print('=================')  # 先打印一下,若没输出打印则反爬了,需要特殊处理

        # pipelines.py 下载数据
        # items.py     定义数据结构

        # src = //ul[@id="component_59"]/li//img/@src
        # alt = //ul[@id="component_59"]/li//img/@alt
        # price = //ul[@id="component_59"]/li//p[@class="price"]/span[1]/text()

        # 所有的seletor的对象 都可以再次调用xpath方法
        li_list = response.xpath('//ul[@id="component_59"]/li')
        for li in li_list:
            # 第一张图片和其他的图片的标签的属性是不一样的(懒加载)
            # 第一张图片的src是可以使用的,其他图片的地址是data-original(加载到之后会自动赋值给src)
            src = li.xpath('.//img/@data-original').extract_first()
            if src:
                src = src
            else:  # src==None (第一张图片img没有data-original属性)
                src = li.xpath('.//img/@src').extract_first()
            name = li.xpath('.//img/@alt').extract_first()
            price = li.xpath('.//p[@class="price"]/span[1]/text()').extract_first()
            book = ScrapyDangdang4Item(src=src, name=name, price=price)
            # 每获取到一个book就将book交给pipelines用于下载
            yield book
            # 带有 yield 的函数不再是一个普通函数,而是一个生成器generator,可用于迭代
            # yield就是 return 返回一个值,并且记住这个返回的位置,下次迭代就从这个位置后(下一行)开始

image-20230525135545815

image-20230525135006867

image-20230525135329894

image-20230525135921670

image-20230525142359703

5. 优化管道封装

# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://docs.scrapy.org/en/latest/topics/item-pipeline.html


# useful for handling different item types with a single interface
from itemadapter import ItemAdapter

# 如果想使用管道的话 那么就必须在settings中开启管道
class ScrapyDangdang4Pipeline:
    # 在爬虫文件开始之前执行的方法
    def open_spider(self, spider):
        print("++++++++++++++++++++++++++++++++++++++++++++++++")
        self.fp = open('book.json', 'w', encoding='utf-8')  # 这里可以用'w',因为打开后在爬虫结束完之前没有关闭

    def process_item(self, item, spider):  # item即parse()中yield传过来的book对象
        '''
        # (1) write方法必须要写一个字符串 而不能是其他的类型,比如对象item
        # (2) 'w'模式 会每一个对象都打开一次文件 覆盖之前的内容;所以要用'a'追加模式
        with open('book.json', 'a', encoding='utf-8') as fp:
            # ctrl+alt+L 格式化代码格式化json文件
            fp.write(str(item))
         '''
        # 以上这种模式不推荐,因为每传递过来一个对象,那么就打开一次文件,对文件的操作过于频繁
        self.fp.write(str(item))
        return item

    # 在爬虫文件执行完之后执行的方法
    def close_spider(self, spider):
        print("--------------------------------------------------")
        self.fp.close()

6. 开启多管道下载

#    (1) 定义管道类 DangDangDownloadPipeline
#   (2) 在settings中开启管道 'scrapy_dangdang_4.pipelines.DangDangDownloadPipeline': 301

image-20230525144123564

image-20230525144138225

scrapy crawl dang

image-20230525144201406

7. 多页下载

import scrapy
from scrapy_dangdang_4.items import ScrapyDangdang4Item  # 这里编译报错没有关系,下面调用的地方不报错就行


class DangSpider(scrapy.Spider):
    name = "dang"
    # allowed_domains = ['http://category.dangdang.com/cp01.01.02.00.00.00.html']
    # 如果是多页下载的话 那么必须要调整的是allowed_domains的范围 一般情况下只写域名
    allowed_domains = ['category.dangdang.com']
    start_urls = ['http://category.dangdang.com/cp01.01.02.00.00.00.html']

    base_url = 'http://category.dangdang.com/pg'
    page = 1

    def parse(self, response):
        # print('=================')  # 先打印一下,若没输出打印则反爬了,需要特殊处理
        # pipelines.py 下载数据
        # items.py     定义数据结构
        # src = //ul[@id="component_59"]/li//img/@src
        # alt = //ul[@id="component_59"]/li//img/@alt
        # price = //ul[@id="component_59"]/li//p[@class="price"]/span[1]/text()
        # 所有的seletor的对象 都可以再次调用xpath方法
        li_list = response.xpath('//ul[@id="component_59"]/li')
        for li in li_list:
            # 第一张图片和其他的图片的标签的属性是不一样的(懒加载)
            # 第一张图片的src是可以使用的,其他图片的地址是data-original(加载到之后会自动赋值给src)
            src = li.xpath('.//img/@data-original').extract_first()
            if src:
                src = src
            else:  # src==None (第一张图片img没有data-original属性)
                src = li.xpath('.//img/@src').extract_first()
            name = li.xpath('.//img/@alt').extract_first()
            price = li.xpath('.//p[@class="price"]/span[1]/text()').extract_first()
            book = ScrapyDangdang4Item(src=src, name=name, price=price)
            # 每获取到一个book就将book交给pipelines用于下载
            yield book
            # 带有 yield 的函数不再是一个普通函数,而是一个生成器generator,可用于迭代
            # yield就是 return 返回一个值,并且记住这个返回的位置,下次迭代就从这个位置后(下一行)开始

        '''
        多页下载:
            每一页的爬取的业务逻辑全都是一样的,所以我们只需要将执行的那个页的请求再次调用parse方法即可
            http://category.dangdang.com/pg2-cp01.01.02.00.00.00.html
            http://category.dangdang.com/pg3-cp01.01.02.00.00.00.html
            http://category.dangdang.com/pg4-cp01.01.02.00.00.00.html
        '''
        if self.page < 100:
            self.page = self.page + 1
            url = self.base_url + str(self.page) + '-cp01.01.02.00.00.00.html'
            # 怎么去调用parse方法
            # scrapy.Request就是scrpay的get请求
            # url就是请求地址
            # callback是你要执行的那个函数  注意不需要加()
            yield scrapy.Request(url=url, callback=self.parse)

scrapy crawl dang

耗时太长,控制台ctrl+c暂停爬虫程序了,只要多于一页60条就成功了;测试完后要删掉数据,因为上传git时数据量较大

image-20230525145739555

image-20230525145753909

posted @ 2023-05-25 15:02  yub4by  阅读(26)  评论(0编辑  收藏  举报