Python爬虫之Scrapy框架基础入门

Scrapy 是一个用于Python的开源网络爬虫框架,它为编写网络爬虫来抓取网站数据并提取结构化信息提供了一种高效的方法。Scrapy可以用于各种目的的数据抓取,如数据挖掘、监控和自动化测试等。

【1】安装

pip install scrapy

安装成功如下所示:
在这里插入图片描述
如果安装过程出错,可以参考下面步骤解决:

# (1) pip install scrapy
# (2) 报错1: building 'twisted.test.raiser' extension
#              error: Microsoft Visual C++ 14.0 is required. Get it with "Microsoft Visual C++
#              Build Tools": http://landinghub.visualstudio.com/visual-cpp-build-tools
#     解决1
#       http://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted
#       Twisted‑20.3.0‑cp37‑cp37m‑win_amd64.whl
#       cp是你的python版本
#       amd是你的操作系统的版本
#       下载完成之后 使用pip install twisted的路径  安装
#       切记安装完twisted 再次安装scrapy# (3) 报错2  提示python -m pip install --upgrade pip
#      解决2   运行python -m pip install --upgrade pip# (4) 报错3   win32的错误
#      解决3   pip install pypiwin32# (5) anaconda

【2】基础入门

scrapy项目的结构

项目名字项目名字spiders文件夹 (存储的是爬虫文件)init自定义的爬虫文件    核心功能文件  ****************inititems        定义数据结构的地方 爬取的数据都包含哪些middleware   中间件    代理pipelines    管道   用来处理下载的数据settings     配置文件    robots协议  ua定义等

在这里插入图片描述

创建Scrapy项目

创建一个新的Scrapy项目,你可以在命令行中输入以下命令:

scrapy startproject myproject

这将在当前目录下创建一个名为myproject的新目录,其中包含了Scrapy项目的结构。

scrapy startproject jane

在这里插入图片描述

定义Item

在Scrapy中,Item是被用来保存抓取到的数据的容器。你可以定义自己的Item类,类似于Python字典,但是提供了额外保护机制和便利方法。Item通常定义在items.py文件中。

class ScrapyDangdangItem(scrapy.Item):# define the fields for your item here like:# name = scrapy.Field()# 通俗的说就是你要下载的数据都有什么# 图片src = scrapy.Field()# 名字name = scrapy.Field()# 价格price = scrapy.Field()# 详情URLdetail_url = scrapy.Field()

编写Spider

创建爬虫文件, 要在spiders文件夹中去创建爬虫文件: cd 项目的名字\项目的名字\spiders

scrapy genspider 爬虫文件的名字  要爬取网页# 示例如下
scrapy genspider baidu  http://www.baidu.com

一般情况下不需要添加http协议 因为start_urls的值是根据allowed_domains修改的 所以添加了http的话 那么start_urls就需要我们手动去修改了

Spiders是定义如何抓取某个(或某些)网站的类。每个Spider负责处理一个特定的网站,或者一组相关的网页。Spiders通常位于spiders目录下,并且以.py文件的形式存在。

class BaiduSpider(scrapy.Spider):name = "baidu"allowed_domains = ["www.baidu.com"]start_urls = ["http://www.baidu.com"]# 是执行了start_urls之后 执行的方法   方法中的response 就是返回的那个对象# 相当于 response = urllib.request.urlopen()#       response  = requests.get()def parse(self, response):# 可以直接使用xpath或BS4span = response.xpath('//div[@id="filter"]/div[@class="tabs"]/a/span')[0]print('=======================')print(span.extract())

response的属性和方法

response.text   获取的是响应的字符串
response.body   获取的是二进制数据
response.xpath  可以直接是xpath方法来解析response中的内容
response.extract()   提取seletor对象的data属性值
response.extract_first() 提取的seletor列表的第一个数据

管道 (Pipeline)

管道是用来处理由Spider抓取并返回的Items的地方。你可以在pipelines.py中定义如何处理这些Items,比如清洗、验证数据或者将它们存储到数据库中。

设置 (Settings)

Scrapy的行为可以通过修改settings.py文件来定制,例如设置下载延迟、启用/禁用中间件、更改用户代理等。

运行 Spider

最后,你可以通过命令行运行你的Spider:

scrapy crawl baidu

【3】管道的使用

pipelines管道就是用来处理数据的,如数据清洗、处理、校验、修正以及存储。

如果想使用管道的话 那么就必须在settings中开启管道,可以定义多个管道通过优先级数值来决定执行次序。

from itemadapter import ItemAdapter
class ScrapyDangdangPipeline:# 在爬虫文件开始的之前就执行的一个方法def open_spider(self,spider):self.fp = open('book.json','w',encoding='utf-8')# item就是yield后面的book对象def process_item(self, item, spider):# 以下这种模式不推荐  因为每传递过来一个对象 那么就打开一次文件  对文件的操作过于频繁# # (1) write方法必须要写一个字符串 而不能是其他的对象# # (2) w模式 会每一个对象都打开一次文件 覆盖之前的内容# with open('book.json','a',encoding='utf-8')as fp:#     fp.write(str(item))self.fp.write(str(item))return item# 在爬虫文件执行完之后  执行的方法def close_spider(self,spider):self.fp.close()import urllib.request# 多条管道开启
#    (1) 定义管道类
#   (2) 在settings中开启管道
# 'scrapy_dangdang_.pipelines.DangDangDownloadPipeline':301
class DangDangDownloadPipeline:def process_item(self, item, spider):url = 'http:' + item.get('src')filename = './books/' + item.get('name') + '.jpg'urllib.request.urlretrieve(url = url, filename= filename)return item

settings.py中开启管道:

ITEM_PIPELINES = {#  管道可以有很多个  那么管道是有优先级的  优先级的范围是1到1000   值越小优先级越高'scrapy_dangdang_.pipelines.ScrapyDangdangPipeline': 300,#    DangDangDownloadPipeline'scrapy_dangdang_.pipelines.DangDangDownloadPipeline':301
}

【4】Scrapy中yield的使用

在 Scrapy 中,yield 有着特别重要的作用,尤其是在 Spider 类中。Scrapy 使用 yield 来返回请求(Request)和项目(Item),而不需要将它们全部加载到内存中。这使得 Scrapy 可以高效地处理大量的页面和数据。

在 Scrapy 中,yield 主要用于以下两个场景:

1. 返回 Request 对象

当您需要从一个页面抓取多个链接并发送请求时,可以使用 yield 来逐个返回 Request 对象。Scrapy 会自动处理这些请求,并将响应传递给指定的回调函数。

class DangSpider(scrapy.Spider):name = 'dang'start_urls = ['http://category.dangdang.com/cp01.01.02.00.00.00.html']def parse(self, response):li_list = response.xpath('//ul[@id="component_59"]/li')for li in li_list:detail_url = 'http:' + li.xpath('./a/@href').get()if detail_url:yield scrapy.Request(detail_url, callback=self.parse_detail)def parse_detail(self, response):review_count = response.xpath('//a[@id="comm_num_down"]/@dd_name').get()if review_count is None:review_count = "评论数未找到"else:review_count = review_count.strip()self.logger.info(f"当前图书评论数为: {review_count}")

在这个例子中,parse 方法会遍历列表页中的每个书籍链接,并使用 yield 逐个返回 Request 对象。Scrapy 会依次处理这些请求,并将详情页的响应传递给 parse_detail 方法。

2. 返回 Item 对象

当您从页面中提取数据并构建 Item 时,可以使用 yieldItem 返回给 Scrapy 的管道进行进一步处理(如保存到数据库、导出为文件等)。

class DangSpider(scrapy.Spider):name = 'dang'start_urls = ['http://category.dangdang.com/cp01.01.02.00.00.00.html']def parse(self, response):li_list = response.xpath('//ul[@id="component_59"]/li')for li in li_list:src = li.xpath('.//img/@data-original').get() or li.xpath('.//img/@src').get()name = li.xpath('.//img/@alt').get()price = li.xpath('.//p[@class="price"]/span[1]/text()').get()detail_url = 'http:' + li.xpath('./a/@href').get()if not src or not name or not price or not detail_url:self.logger.warning("缺少关键信息,跳过此条目")continuebook_info = {'src': src,'name': name,'price': price,'detail_url': detail_url}yield scrapy.Request(detail_url, callback=self.parse_detail, cb_kwargs={'book_info': book_info})def parse_detail(self, response, book_info):review_count = response.xpath('//a[@id="comm_num_down"]/@dd_name').get()if review_count is None:review_count = "评论数未找到"else:review_count = review_count.strip()book_info['review_count'] = review_countbook_item = ScrapyDangdangItem(**book_info)self.logger.info(f"抓取到完整图书信息: {book_item}")yield book_item

在这个例子中,parse_detail 方法会从详情页提取评论数,并将其添加到 book_info 字典中。然后,它会创建一个 ScrapyDangdangItem 实例,并使用 yield 将其返回给 Scrapy 的管道。

【5】parse方法之间如何传参?

比如,需要先获取分类列表,然后获取每一个详情,最后整合获取得到book信息。

在 Scrapy 中,通常情况下,您会希望将从详情页获取的数据(如评论数)与列表页获取的数据(如书名、价格等)结合起来,形成一个完整的 Item。为了实现这一点,您可以使用 Requestmeta 参数来传递数据,或者使用 cb_kwargs 参数(Scrapy 1.7+)来传递关键字参数。

方法 1: 使用 meta 参数

meta 参数允许您在请求之间传递数据。您可以在 parse 方法中将书籍的基本信息(如书名、价格、图片链接等)通过 meta 传递给 parse_detail 方法,然后在 parse_detail 中提取评论数并返回一个完整的 Item。

修改后的代码:

import scrapy
from ..items import ScrapyDangdangItem  # 确保这里正确导入了Itemclass DangSpider(scrapy.Spider):name = 'dang'allowed_domains = ['dangdang.com']  # 放宽域名限制start_urls = ['http://category.dangdang.com/cp01.01.02.00.00.00.html']base_url = 'http://category.dangdang.com/pg'page = 1def parse(self, response):li_list = response.xpath('//ul[@id="component_59"]/li')for li in li_list:src = li.xpath('.//img/@data-original').get() or li.xpath('.//img/@src').get()name = li.xpath('.//img/@alt').get()price = li.xpath('.//p[@class="price"]/span[1]/text()').get()detail_url = 'http:' + li.xpath('./a/@href').get()if not src or not name or not price or not detail_url:self.logger.warning("缺少关键信息,跳过此条目")continue# 构建基础的图书信息book_info = {'src': src,'name': name,'price': price,'detail_url': detail_url}# 发送详情页请求,并通过 meta 传递图书信息yield scrapy.Request(detail_url, callback=self.parse_detail, meta={'book_info': book_info})def parse_detail(self, response):# 从 meta 中获取图书信息book_info = response.meta['book_info']# 提取评论数review_count = response.xpath('//a[@id="comm_num_down"]/@dd_name').get()if review_count is None:review_count = "评论数未找到"else:review_count = review_count.strip()# 将评论数添加到图书信息中book_info['review_count'] = review_count# 创建并返回完整的 Itembook_item = ScrapyDangdangItem(**book_info)self.logger.info(f"抓取到完整图书信息: {book_item}")yield book_item

方法 2: 使用 cb_kwargs 参数 (Scrapy 1.7+)

cb_kwargs 是 Scrapy 1.7 版本引入的一个新特性,它允许您直接在 Request 中传递关键字参数,而不需要通过 meta。这种方式更加直观和简洁。

修改后的代码:

import scrapy
from ..items import ScrapyDangdangItem  # 确保这里正确导入了Itemclass DangSpider(scrapy.Spider):name = 'dang'allowed_domains = ['dangdang.com']  # 放宽域名限制start_urls = ['http://category.dangdang.com/cp01.01.02.00.00.00.html']base_url = 'http://category.dangdang.com/pg'page = 1def parse(self, response):li_list = response.xpath('//ul[@id="component_59"]/li')for li in li_list:src = li.xpath('.//img/@data-original').get() or li.xpath('.//img/@src').get()name = li.xpath('.//img/@alt').get()price = li.xpath('.//p[@class="price"]/span[1]/text()').get()detail_url = 'http:' + li.xpath('./a/@href').get()if not src or not name or not price or not detail_url:self.logger.warning("缺少关键信息,跳过此条目")continue# 构建基础的图书信息book_info = {'src': src,'name': name,'price': price,'detail_url': detail_url}# 发送详情页请求,并通过 cb_kwargs 传递图书信息yield scrapy.Request(detail_url, callback=self.parse_detail, cb_kwargs={'book_info': book_info})def parse_detail(self, response, book_info):# 提取评论数review_count = response.xpath('//a[@id="comm_num_down"]/@dd_name').get()if review_count is None:review_count = "评论数未找到"else:review_count = review_count.strip()# 将评论数添加到图书信息中book_info['review_count'] = review_count# 创建并返回完整的 Itembook_item = ScrapyDangdangItem(**book_info)self.logger.info(f"抓取到完整图书信息: {book_item}")yield book_item

关键点解释

  1. meta 参数

    • parse 方法中,我们构建了一个包含图书基本信息的字典 book_info
    • 使用 meta 参数将 book_info 传递给 parse_detail 方法。
    • parse_detail 中,通过 response.meta['book_info'] 获取传递过来的图书信息。
  2. cb_kwargs 参数

    • parse 方法中,我们同样构建了一个包含图书基本信息的字典 book_info
    • 使用 cb_kwargs 参数将 book_info 作为关键字参数传递给 parse_detail 方法。
    • parse_detail 中,直接通过函数参数 book_info 获取传递过来的图书信息。
  3. 合并数据

    • parse_detail 中,我们提取了评论数,并将其添加到 book_info 字典中。
    • 最后,我们创建了一个 ScrapyDangdangItem 实例,并将其返回给 Scrapy 的管道进行处理。

【6】管道中使用pymysql存储数据

from itemadapter import ItemAdapterclass ScrapyReadbookPipeline:def open_spider(self,spider):self.fp = open('book.json','w',encoding='utf-8')def process_item(self, item, spider):self.fp.write(str(item))return itemdef close_spider(self,spider):self.fp.close()# 加载settings文件
from scrapy.utils.project import get_project_settings
import pymysqlclass MysqlPipeline:def open_spider(self,spider):settings = get_project_settings()self.host = settings['DB_HOST']self.port =settings['DB_PORT']self.user =settings['DB_USER']self.password =settings['DB_PASSWROD']self.name =settings['DB_NAME']self.charset =settings['DB_CHARSET']self.connect()def connect(self):self.conn = pymysql.connect(host=self.host,port=self.port,user=self.user,password=self.password,db=self.name,charset=self.charset)self.cursor = self.conn.cursor()def process_item(self, item, spider):sql = 'insert into book(name,src) values("{}","{}")'.format(item['name'],item['src'])# 执行sql语句self.cursor.execute(sql)# 提交self.conn.commit()return itemdef close_spider(self,spider):self.cursor.close()self.conn.close()

数据库配置信息在settings.py中:

在这里插入图片描述

【7】日志级别与存储路径

settings.py中配置日志级别与路径即可:

# 指定日志的级别
# LOG_LEVEL='WARNING'LOG_FILE = 'logdemo.log'

【8】POST请求

如下所示是GET请求:

yield scrapy.Request(url=detail_url, callback=self.parse_detail)

重写start_requests方法使用FormRequest发送POST请求

class TestpostSpider(scrapy.Spider):name = 'testpost'allowed_domains = ['https://fanyi.baidu.com/sug']# post请求 如果没有参数 那么这个请求将没有任何意义# 所以start_urls 也没有用了# parse方法也没有用了# start_urls = ['https://fanyi.baidu.com/sug/']## def parse(self, response):#     passdef start_requests(self):url = 'https://fanyi.baidu.com/sug'data = {'kw': 'final'}yield scrapy.FormRequest(url=url,formdata=data,callback=self.parse_second)def parse_second(self,response):content = response.textobj = json.loads(content,encoding='utf-8')print(obj)

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据结构_拓扑排序

拓扑排序 (所有点按照先后顺序排序) 1.先找到入度为0的点,记录之后,删除这个点和它的出边; 2.若有两个可选,随便选择一个 例 a的入度为0,选a [a] 随便选一个 [a,e] 再找入度为0的点 再选c 最后选d 拓…

又细又长的马尾:tail

英语里边有一个单词 tail,意为“尾巴”,这应当是众所周知的事情了。 不过,tail 这条尾巴,并不简单,因为它还是一个词根,也就是说 tail 其实是自由词素。 事实上,tail 最初来自 马尾 这样一个概…

ARM学习(35)单元测试框架以及MinGW GCC覆盖率报告

单元测试框架以及MinGW GCC覆盖率报告 1、单元测试与覆盖率简介 随着代码越写越多,越来越需要注意自测的重要性,基本可以提前解决90%的问题,所以就来介绍一下单元测试,单元测试是否测试充分,需要进行评价,覆盖率就是单元测试是否充分的评估工具。 例如跑过单元测试后,…

前后端分离的项目使用nginx 解决 Invalid CORS request

我是这样打算的,前端用nginx代理,使用80 转443 端口走https 前端的地址就是http://yumbo.top 或https://yumbo.top 后端服务地址是:http://yumbo.top:8081 下面是我的完整配置,功能是正常的,加了注释 user nginx; …

用 Python 格式化器重新定义用户体验

文章目录 摘要引言用户体验优化的核心原则代码格式化工具代码模块详解核心类:CodeFormatter代码格式化方法:format核心逻辑处理使用示例示例输出用户体验设计亮点 QA 环节总结参考资料 摘要 开发者工具的用户体验(UX)对其使用率和…

如何使mysql数据库ID从0开始编号——以BiCorpus为例

BiCorpus是北京语言大学韩林涛老师研制一款在线语料库网站,可以通过上传tmx文件,实现在线检索功能,程序在github上开源免费,深受广大网友的喜欢。 在使用过程中,我发现我上传的语言资产经历修改后,mysql的…

Tomcat项目本地部署

前言: 除了在idea中将项目启动之外,也可以将项目部署在本地tomcat或者云服务器上,本片文章主要介绍了怎样将项目部署在本地tomcat 下面介绍如何使用Tomcat部署本地项目: 1、本篇文章使用的项目案例为一个聚合项目,ha…

2024-12-14 学习人工智能的Day35 卷积神经网络.阶段项目

卷积神经网络项目实现 关于项目实现的文档说明书,三个要素:数据、模型、训练 1、项目简介。 1.1 项目名称 ​ 基于CNN实现扑克牌花色的小颗粒度分类 1.2 项目简介 ​ 该项目旨在通过卷积神经网络(CNN)实现扑克的小颗粒度分类…

LabVIEW汽车综合参数测量

系统基于LabVIEW虚拟仪器技术,专为汽车带轮生产中的质量控制而设计,自动化测量和检测带轮的关键参数。系统采用PCIe-6320数据采集卡与精密传感器结合,能够对带轮的直径、厚度等多个参数进行高精度测量,并通过比较测量法判定产品合…

C++编程: 基于cpp-httplib和nlohmann/json实现简单的HTTP Server

文章目录 0. 引言1. 完整实例代码2. 关键实现3. 运行与测试 0. 引言 本文基于 cpp-httplib 和 nlohmann/json 实现简单的 HTTPS Server 实例代码&#xff0c;这两个库均是head-only的。 1. 完整实例代码 如下实例程序修改自example/server.cc #include <httplib.h>#i…

arcGIS使用笔记(无人机tif合并、导出、去除黑边、重采样)

无人机航拍建图之后&#xff0c;通过大疆智图软件可以对所飞行的区域的进行拼图&#xff0c;但是如果需要对拼好的图再次合并&#xff0c;则需要利用到arcGIS软件。下面介绍arcGIS软件在这个过程中常用的操作。 1.导入tif文件并显示的方法&#xff1a;点击“”图标进行导入操作…

FPGA 第十四讲 分频器--偶分频

时间:2024.12.14 时钟对于 FPGA 是非常重要的,但板载晶振提供的时钟信号频率是固定的,不一定满足工程需求,所以使用分频或倍频产生需要的时钟是很有必要的。 一、学习内容 1.分频器 分频器是数字系统设计中最常见的基本电路之一。所谓“分频”,就是把输入信号的频率变成…

python爬虫--小白篇【爬取B站视频】

目录 一、任务分析 二、网页分析 三、任务实现 一、任务分析 将B站视频爬取并保存到本地&#xff0c;经过分析可知可以分为四个步骤&#xff0c;分别是&#xff1a; 爬取视频页的网页源代码&#xff1b;提取视频和音频的播放地址&#xff1b;下载并保存视频和音频&#x…

基于ArqMATH 数据集探索大语言模型在数学问题推理解答中的能力

概述 论文地址&#xff1a;https://arxiv.org/pdf/2404.00344 源码地址&#xff1a;https://github.com/gipplab/llm-investig-mathstackexchange 大规模语言模型&#xff08;LLMs&#xff09;因其解决自然语言任务的能力而备受关注&#xff0c;在某些任务中&#xff0c;其准…

基于ZYNQ 7z010开发板 oled点亮的实现

dc拉高的时候就是发送128字节数据的时候 发送指令dc拉低 模式是00 sck先置低再置高 复位是与开发板上的按键一样都是低有效 25位字节指令 加 3字节的 页地址加起始结束 b0,00,10, timescale 1ns / 1ps module top0(input wire clk ,input wire rst_n,// out…

360极速浏览器不支持看PDF

360安全浏览器采用的是基于IE内核和Chrome内核的双核浏览器。360极速浏览器是源自Chromium开源项目的浏览器&#xff0c;不但完美融合了IE内核引擎&#xff0c;而且实现了双核引擎的无缝切换。因此在速度上&#xff0c;360极速浏览器的极速体验感更佳。 展示自己的时候要在有优…

基于SpringBoot和PostGIS的全球城市信息管理实践

目录 前言 一、业务需求介绍 1、功能思维导图 二、业务系统后台实现 1、Model层实现 2、业务层的实现 3、控制层的实现 三、前端管理业务的实现 1、全球城市列表的实现 2、详情页面实现 3、实际城市定位 四、总结 前言 在全球化和信息化时代背景下&#xff0c;城市作…

《饕餮记》精彩片段(一)

也是无意中看到鲛人脍单元集片段&#xff0c;才去看了这个剧 整体略架空和部分逻辑不是很连贯和完美 精彩点不在于整体和走向和故事线 也不在于大牌明星撑场&#xff0c;因为全场只有安悦溪一个脸熟明星撑场子 而在于每个单元间离奇小故事 和华胥引差不多&#xff0c;属于逻…

如何在 ASP.NET Core 3.1 应用程序中使用 Log4Net

介绍 日志记录是应用程序的核心。它对于调试和故障排除以及应用程序的流畅性非常重要。 借助日志记录&#xff0c;我们可以对本地系统进行端到端的可视性&#xff0c;而对于基于云的系统&#xff0c;我们只能提供一小部分可视性。您可以将日志写入磁盘或数据库中的文件&#xf…

计算机毕业设计PySpark+PyFlink+Hive地震预测系统 地震数据分析可视化 地震爬虫 大数据毕业设计 Hadoop 机器学习 深度学习

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…