初步搭建并使用Scrapy框架

目录

目标

版本

实战

搭建框架

获取图片链接、书名、价格

通过管道下载数据

通过多条管道下载数据

下载多页数据


目标

        掌握Scrapy框架的搭建及使用,本文以爬取当当网魔幻小说为案例做演示。


版本

        Scrapy 2.12.0


实战

搭建框架

第一步:在D:\pytharm_workspace位置创建爬虫Scrapy项目。通过cmd在该目录执行Scrapy创建项目命令。dangdang是我的项目名称。

scrapy startproject dangdang

第二步:进入项目目录,并创建爬虫类。其中magic_novels是我自定义的爬虫程序名称,permit.mee.gov.cn表示要爬取的网站域名。

第三步:注释在settings文件中掉OBOTSTXT_OBEY协议。

#ROBOTSTXT_OBEY = True

第四步:打开Pycharm控制台,进入项目目录。设置start_urls为我们要爬取的首页。parse表示项目启动后会自动请求start_urls中的URL。所以我们在parse方法中调试输出,并运行项目。

import scrapy


class MagicNovelsSpider(scrapy.Spider):
    name = "magic_novels"
    allowed_domains = ["category.dangdang.com"]
    start_urls = ["https://category.dangdang.com/cp01.03.40.00.00.00.html"]

    def parse(self, response):
        print(response.url)
        print(response.text)

 scrapy crawl magic_novels

第五步:此时会打印很多的无用信息,我们可以在settings.py文件中设置日志级别。再次启动项目后会发现页面干净了很多。

LOG_LEVEL = "WARNING"
scrapy crawl magic_novels
注意:如果多次请求导致可能会导致缓存出现,请使用以下命令:
scrapy crawl magic_novels --set HTTPCACHE_ENABLED=False

获取图片链接、书名、价格

第一步:通过xpath爬取价格、图片、书名,我们先来打印调试。此时发现图片的链接不对,思考是否是懒加载的一个反扒策略。

    def parse(self, response):
        '''
            图片的链接: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
            考虑到所有的数据都来源于//ul[@id='component_59']/li,所以我们可以复用li对象。
        '''
        li_list = response.xpath("//ul[@id='component_59']/li")
        for li in li_list:
            print(f'图片的链接:src={li.xpath(".//img/@src").extract_first()}')
            print(f'图片的名称:alt={li.xpath(".//img/@alt").extract_first()}')
            print(f'图书的价格:price={li.xpath(".//p[@class='price']/span[1]/text()").extract_first()}')
            print("\n")

第二步: 刷新页面,在浏览器检查中查看第一个和最后一个,发现图片链接的初始接收属性并不是src,而是data-original,src是加载以后才代替data-original的。

第三步:修改src获取的方法,并再次运行项目。发现除了第一个图书的src为None,其他src都正常获取了。猜测:是不是第一个图书打开时没有使用懒加载。

第四步: 通过调试发现,确实如刚才的猜想一般,第一个图书的src没有使用懒加载。修改代码后再次调试,发现可以获取到第一个图书的链接。

    def parse(self, response):
        '''
            图片的链接: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
            考虑到所有的数据都来源于//ul[@id='component_59']/li,所以我们可以复用li对象。
        '''
        li_list = response.xpath("//ul[@id='component_59']/li")
        for i , li in enumerate(li_list):
            print(f'第{i+1}本书。')
            src = li.xpath(".//img/@data-original").get()
            if src is None:
                src = li.xpath(".//img/@src").get()
            alt = li.xpath(".//img/@alt").get()
            price = li.xpath(".//p[@class='price']/span[1]/text()").get()
            print(f'图片的链接:src={src}')
            print(f'图片的名称:alt={alt}')
            print(f'图书的价格:price={price}')
            print("\n")


通过管道下载数据

第一步:打开items.py文件,配置字段。

# Define here the models for your scraped items
#
# See documentation in:
# https://docs.scrapy.org/en/latest/topics/items.html

import scrapy


class DangdangItem(scrapy.Item):
    # 图片
    src = scrapy.Field()
    # 书名
    name = scrapy.Field()
    # 价格
    price = scrapy.Field()

第二步:将item类导入到爬虫程序。

import scrapy

from dangdang.items import DangdangItem

class MagicNovelsSpider(scrapy.Spider):
    name = "magic_novels"
    allowed_domains = ["category.dangdang.com"]
    start_urls = ["https://category.dangdang.com/cp01.03.40.00.00.00.html"]

    def parse(self, response):
        '''
            图片的链接: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
            考虑到所有的数据都来源于//ul[@id='component_59']/li,所以我们可以复用li对象。
        '''
        li_list = response.xpath("//ul[@id='component_59']/li")
        for i , li in enumerate(li_list):
            print(f'第{i+1}本书。')
            src = li.xpath(".//img/@data-original").get()
            if src is None:
                src = li.xpath(".//img/@src").get()
            alt = li.xpath(".//img/@alt").get()
            price = li.xpath(".//p[@class='price']/span[1]/text()").get()
            print(f'图片的链接:src={src}')
            print(f'图书的名称:alt={alt}')
            print(f'图书的价格:price={price}')
            print("\n")
            #该对象要通过管道去下载,通过yield可以在每次获得book后立刻返回book给管道。
            book=DangdangItem(src=src, alt=alt, price=price);
            yield book

第三步:在settings.py中开启管道配置。管道可以有很多个并且有优先级,300是默认值,值越大优先级越小。

ITEM_PIPELINES = {
    "dangdang.pipelines.DangdangPipeline": 300,
}

第四步:来到pipelines.py文件,其中process_item方法中的item就是我们刚才在爬虫程序配置的boot对象。我们可以打印测试效果。

class DangdangPipeline:
    def process_item(self, item, spider):
        print(type(item))
        print(str(item))
        return item
scrapy crawl magic_novels

思考:我们通过process_item可以获取到数据,但是每次循环获取数据再重新打开文件、写入数据,关闭文件明显不符合开发规范。

第五步:在pipelines.py文件中配置open_spider和close_spider方法,分别表示在爬虫程序执行前执行的方法和在爬虫程序执行之后执行的方法。我们可以打印日志测试。

class DangdangPipeline:
    #在爬虫文件开始之前就执行的方法
    def open_spider(self, spider):
        print("++++")
    def process_item(self, item, spider):
        print(type(item))
        print(str(item))
        return item
    #在爬虫文件执行之后再执行的方法
    def close_spider(self, spider):
        print("----")
scrapy crawl magic_novels

第六步: 下载JSON数据。

# 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
import json

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


class DangdangPipeline:
    #在爬虫文件开始之前就执行的方法
    def open_spider(self, spider):
        self.fp=open("book.json","w",encoding="utf-8")
        self.fp.write("[")
    def process_item(self, item, spider):
        line = json.dumps(dict(item), ensure_ascii=False) + ",\n"
        self.fp.write(line)
        return item
    #在爬虫文件执行之后再执行的方法
    def close_spider(self, spider):
        # 删除最后一个多余的逗号,并关闭 JSON 数组
        self.fp.seek(self.fp.tell() - 3, 0)  
        self.fp.write("\n]")
        self.fp.close()
scrapy crawl magic_novels

 


通过多条管道下载数据

第一步:在pipelines.py文件中定义新的管道类。

#下载图片
class DangdangDownloadImgPipeline:
    # 在爬虫文件开始之前就执行的方法
    def open_spider(self, spider):
        pass
    def process_item(self, item, spider):
        print(item.get('src'))
        url="http:"+item.get('src')
        filename='C:/Users/Administrator/Desktop/test/'+sanitize_filename(item.get("alt"))+'.jpg'
        urllib.request.urlretrieve(url=url,filename=filename)
        return item
    # 在爬虫文件执行之后再执行的方法
    def close_spider(self, spider):
        pass

def sanitize_filename(filename):
    """
    替换 Windows 文件名中不合法的字符为下划线。
    """
    # 定义 Windows 文件名不允许的字符
    invalid_chars = r'[\\/:*?"<>|]'
    # 使用正则表达式将非法字符替换为下划线
    return re.sub(invalid_chars, '_', filename)

第二步:在settings.py中定义该管道类的优先级。

ITEM_PIPELINES = {
    "dangdang.pipelines.DangdangPipeline": 300,
    "dangdang.pipelines.DangdangDownloadImgPipeline": 300,
}

第三步:执行下载操作,可以看到JSON数据和图片都下载成功了。

scrapy crawl magic_novels


下载多页数据

思考:目前我们只是下载了第一页的数据,能否通过配置页码下载多个页面的数据呢?

第一步:去页面点击下一页,发现链接都差不多,区别在于pg后面的跟的页码。

https://category.dangdang.com/pg2-cp01.03.40.00.00.00.html
https://category.dangdang.com/pg3-cp01.03.40.00.00.00.html

第二步:在爬虫程序中,设置基础的url和页码,页码初始化为第一页。

class MagicNovelsSpider(scrapy.Spider):
    name = "magic_novels"
    allowed_domains = ["category.dangdang.com"]
    start_urls = ["https://category.dangdang.com/cp01.03.40.00.00.00.html"]
    base_url="https://category.dangdang.com/pg"
    page_num=1;

第三步:在parse方法中递归请求当当网,每次请求都将url的页码改变。注意:递归逻辑写在循环之外。

import scrapy

from dangdang.items import DangdangItem

class MagicNovelsSpider(scrapy.Spider):
    name = "magic_novels"
    allowed_domains = ["category.dangdang.com"]
    start_urls = ["https://category.dangdang.com/cp01.03.40.00.00.00.html"]
    base_url="https://category.dangdang.com/pg"
    page_num=1;
    def parse(self, response):
        '''
            图片的链接: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
            考虑到所有的数据都来源于//ul[@id='component_59']/li,所以我们可以复用li对象。
        '''
        li_list = response.xpath("//ul[@id='component_59']/li")
        for i , li in enumerate(li_list):
            print(f'第{i+1}本书。')
            src = li.xpath(".//img/@data-original").get()
            if src is None:
                src = li.xpath(".//img/@src").get()
            alt = li.xpath(".//img/@alt").get()
            price = li.xpath(".//p[@class='price']/span[1]/text()").get()
            print(f'图片的链接:src={src}')
            print(f'图书的名称:alt={alt}')
            print(f'图书的价格:price={price}')
            print("\n")
            #该对象要通过管道去下载,通过yield可以在每次获得book后立刻返回book给管道。
            book=DangdangItem(src=src, alt=alt, price=price);
            yield book
        if self.page_num<3:
            self.page_num+=1
            url=self.base_url+str(self.page_num)+"-cp01.03.40.00.00.00.html";
            #GET请求
            yield scrapy.Request(url=url, callback=self.parse)

第四步:运行项目。发现可以正常下载前三页的数据。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/957823.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Python - itertools- pairwise函数的详解

前言&#xff1a; 最近在leetcode刷题时用到了重叠对pairwise,这里就讲解一下迭代工具函数pairwise,既介绍给大家&#xff0c;同时也提醒一下自己&#xff0c;这个pairwise其实在刷题中十分有用&#xff0c;相信能帮助到你。 参考官方讲解&#xff1a;itertools --- 为高效循…

YOLO-cls训练及踩坑记录

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言 一、模型训练 二、测试 三、踩坑记录 1、推理时设置的imgsz不生效 方法一&#xff1a; 方法二&#xff1a; 2、Windows下torchvision版本问题导致报错 总结 前…

云计算、AI与国产化浪潮下DBA职业之路风云变幻,如何谋破局启新途?

引言 在近日举办的一场「云和恩墨大讲堂」直播栏目中&#xff0c;云和恩墨联合创始人李轶楠、副总经理熊军和欧冶云商数据库首席薛晓刚共同探讨了DBA的现状与未来发展。三位专家从云计算、人工智能、国产化替代等多个角度进行了深入的分析和探讨&#xff0c;为从业者提供了宝贵…

PAT甲级-1017 Queueing at Bank

题目 题目大意 银行有k个窗口&#xff0c;每个窗口只能服务1个人。如果3个窗口已满&#xff0c;就需要等待。给出n个人到达银行的时间和服务时间&#xff0c;要求计算每个人的平均等待时间。如果某个人的到达时间超过17:00:00&#xff0c;则不被服务&#xff0c;等待时间也不计…

从零安装 LLaMA-Factory 微调 Qwen 大模型成功及所有的坑

文章目录 从零安装 LLaMA-Factory 微调 Qwen 大模型成功及所有的坑一 参考二 安装三 启动准备大模型文件 四 数据集&#xff08;关键&#xff09;&#xff01;4.1 Alapaca格式4.2 sharegpt4.3 在 dataset_info.json 中注册4.4 官方 alpaca_zh_demo 例子 999条数据, 本机微调 5分…

AI刷题-策略大师:小I与小W的数字猜谜挑战

问题描述 有 1, 2,..., n &#xff0c;n 个数字&#xff0c;其中有且仅有一个数字是中奖的&#xff0c;这个数字是等概率随机生成的。 Alice 和 Bob 进行一个游戏&#xff1a; 两人轮流猜一个 1 到 n 的数字&#xff0c;Alice 先猜。 每完成一次猜测&#xff0c;主持会大声…

【数据分享】1929-2024年全球站点的逐年最低气温数据(Shp\Excel\免费获取)

气象数据是在各项研究中都经常使用的数据&#xff0c;气象指标包括气温、风速、降水、湿度等指标&#xff01;说到气象数据&#xff0c;最详细的气象数据是具体到气象监测站点的数据&#xff01; 有关气象指标的监测站点数据&#xff0c;之前我们分享过1929-2024年全球气象站点…

CSDN 博客之星 2024:默语的技术进阶与社区耕耘之旅

CSDN 博客之星 2024&#xff1a;默语的技术进阶与社区耕耘之旅 &#x1f31f; 默语&#xff0c;是一位在技术分享与社区建设中坚持深耕的博客作者。今年&#xff0c;我有幸再次入围成为 CSDN 博客之星TOP300 的一员&#xff0c;这既是对过往努力的肯定&#xff0c;也是对未来探…

计算机网络 (56)交互式音频/视频

一、定义与特点 定义&#xff1a;交互式音频/视频是指用户使用互联网和其他人进行实时交互式通信的技术&#xff0c;包括语音、视频图像等多媒体实时通信。 特点&#xff1a; 实时性&#xff1a;音频和视频数据是实时传输和播放的&#xff0c;用户之间可以进行即时的交流。交互…

Node.js——express中间件(全局中间件、路由中间件、静态资源中间件)

个人简介 &#x1f440;个人主页&#xff1a; 前端杂货铺 &#x1f64b;‍♂️学习方向&#xff1a; 主攻前端方向&#xff0c;正逐渐往全干发展 &#x1f4c3;个人状态&#xff1a; 研发工程师&#xff0c;现效力于中国工业软件事业 &#x1f680;人生格言&#xff1a; 积跬步…

嵌入式知识点总结 ARM体系与架构 专题提升(一)-硬件基础

嵌入式知识点总结 ARM体系与架构 专题提升(一)-硬件基础 目录 1.NAND FLASH 和NOR FLASH异同 ? 2.CPU,MPU,MCU,SOC,SOPC联系与差别? 3.什么是交叉编译&#xff1f; 4.为什么要交叉编译&#xff1f; 5.描述一下嵌入式基于ROM的运行方式和基于RAM的运行方式有什么区别? 1…

【JavaSE】(8) String 类

一、String 类常用方法 1、构造方法 常用的这4种构造方法&#xff1a;直接法&#xff0c;或者传参字符串字面量、字符数组、字节数组。 在 JDK1.8 中&#xff0c;String 类的字符串实际存储在 char 数组中&#xff1a; String 类也重写了 toString 方法&#xff0c;所以可以直…

JS(6)-数组

一.数组的基本使用 1.数组&#xff1a;把多个数据存到一组 每个数组都有编号&#xff0c;从零开始&#xff0c;数组的编号叫索引或下标&#xff0c;可以存放数字&#xff0c;字符串等。 2.取值 3.遍历数组&#xff1a;用循环的方法把每个数都访问到 a)练习 首先&#xff0c;定…

查看电脑或笔记本CPU的核心数方法及CPU详细信息

一、通过任务管理器查看 1.打开任务管理器 可以按下“Ctrl Shift Esc”组合键&#xff0c;或者按下“Ctrl Alt Delete”组合键后选择“任务管理器”来打开。 2.查看CPU信息 在任务管理器界面中&#xff0c;点击“性能”标签页&#xff0c;找到CPU使用记录区域&#xff0c…

Docker核心命令与Yocto项目的高效应用

随着软件开发逐渐向分布式和容器化方向演进&#xff0c;Docker 已成为主流的容器化技术之一。它通过标准化的环境配置、资源隔离和高效的部署流程&#xff0c;大幅提高了开发和构建效率。Yocto 项目作为嵌入式 Linux 系统构建工具&#xff0c;与 Docker 的结合进一步增强了开发…

08-Elasticsearch

黑马商城作为一个电商项目&#xff0c;商品的搜索肯定是访问频率最高的页面之一。目前搜索功能是基于数据库的模糊搜索来实现的&#xff0c;存在很多问题。 首先&#xff0c;查询效率较低。 由于数据库模糊查询不走索引&#xff0c;在数据量较大的时候&#xff0c;查询性能很…

MyBatis最佳实践:提升数据库交互效率的秘密武器

第一章&#xff1a;框架的概述&#xff1a; MyBatis 框架的概述&#xff1a; MyBatis 是一个优秀的基于 Java 的持久框架&#xff0c;内部对 JDBC 做了封装&#xff0c;使开发者只需要关注 SQL 语句&#xff0c;而不关注 JDBC 的代码&#xff0c;使开发变得更加的简单MyBatis 通…

Scratch全攻略:从入门到实践的编程之旅

目录 一、Scratch 基础入门1.1 Scratch 是什么1.2 安装与界面熟悉1.2.1 在线版1.2.2 离线版1.2.2.1 舞台区1.2.2.2 角色区1.2.2.3 脚本区1.2.2.4 背景区1.2.2.5 声音区 二、核心编程要素2.1 角色与舞台2.2 积木块详解2.2.1 运动类积木2.2.2 外观类积木2.2.3 声音类积木2.2.4 事…

STM32之CubeMX新建工程操作(十八)

STM32F407 系列文章 - STM32CubeMX&#xff08;十八&#xff09; 目录 前言 一、STM32CubeMX 二、新建工程 ​编辑 1.创建工程 2.选择芯片型号 3.Pinout引脚分配 1.SYS配置 2.RCC配置 3.定时器配置 4.GPIO引脚配置 5.中断配置 6.通讯接口配置 7.插件Middleware配…

Spark任务提交流程

当包含在application master中的spark-driver启动后&#xff0c;会与资源调度平台交互获取其他执行器资源&#xff0c;并通过反向注册通知对应的node节点启动执行容器。此外&#xff0c;还会根据程序的执行规划生成两个非常重要的东西&#xff0c;一个是根据spark任务执行计划生…