Scrapy爬虫教程(新手)

1. Scrapy的核心组成

        引擎(engine):scrapy的核心,所有模块的衔接,数据流程梳理。

        调度器(scheduler):本质可以看成一个集合和队列,里面存放着一堆即将要发送的请求,可以看成是一个url容器,它决定了下一步要爬取哪一个url,通常我们在这里可以对url进行去重操作。

        下载器(downloader):本质是一个用来发动请求的模块,可以理解成是一个requests.get()的功能,只不过返回的是一个response对象。

        爬虫(spider):负载解析下载器返回的response对象,从中提取需要的数据。

        管道(pipeline):主要负责数据的存储和各种持久化操作。

2. 安装步骤

        这里安装的scrapy版本为2.5.1版,在pycharm命令行内输入pip install scrapy==2.5.1即可。

pip install scrapy==2.5.1

        但是要注意OpenSSL的版本,其查看命令为

scrapy version --verbose

       如果OpenSSL版本不为1.1版本的话,需要对其进行降级。

pip uninstall cryptography
pip install cryptography==36.0.2

        注:如果降级之后使用scrapy version --verbose出现错误:TypeError: deprecated() got an unexpected keyword argument 'name',可能是OpenSSL版本过低导致,这里需要根据自身情况,进行对应处理。

卸载cryptography:pip uninstall cryptography
重新安装cryptography 36.0.2:pip install cryptography==36.0.2
卸载pyOpenSSL:pip uninstall pyOpenSSL
重新安装pyOpenSSL 22.0.0:pip install pyOpenSSL==22.0.0

        如果查看时出现错误:AttributeError: 'SelectReactor' object has no attribute '_handleSignals'
可能是由于Twisted版本问题,进行卸载重新安装Twisted即可。

pip uninstall Twisted
pip install Twisted==22.10.0

3. 基础使用

1.创建项目scrapy startproject 项目名
2.进入项目目录cd 项目名
3.生成spiderscrapy genspider 爬虫名字 网站的域名
4.调整spider给出start_urls以及如何解析数据
5.调整setting配置文件配置user_agent,robotstxt_obey,pipeline取消日志信息,留下报错,需调整日志级别 LOG_LEVEL
6.允许scrapy程序scrapy crawl 爬虫的名字

4. 案例分析

        当使用 scrapy startproject csdn 之后,会出现csdn的文件夹

        当输入 scrapy genspider csdn_spider blog.csdn.net 之后,会出现

         我们这里以爬取自己csdn所发表的文章为例,在csdn_spider.py中编辑页面元素的定位方式

import scrapyclass CsdnSpiderSpider(scrapy.Spider):name = 'csdn_spider'allowed_domains = ['blog.csdn.net']start_urls = ['http://blog.csdn.net/mozixiao__']def parse(self, response):print('===>',response)infos = response.xpath('//*[@id="navList-box"]/div[2]/div/div/div') #这里的路径需要注意的是,最后一个div不需要加确定的值,这里是一个模糊匹配,不然infos就只有一个信息for info in infos:title = info.xpath('./article/a/div/div[1]/div[1]/h4/text()').extract_first().strip()date = info.xpath('./article/a/div/div[2]/div[1]/div[2]/text()').extract_first().strip().split()[1]view = info.xpath('./article/a/div/div[2]/div[1]/div[3]/span/text()').extract_first().strip()dianzan = info.xpath('./article/a/div/div[2]/div[1]/div[4]/span/text()').extract_first().strip()pinglun = info.xpath('./article/a/div/div[2]/div[1]/div[5]/span/text()').extract_first().strip()shouchang = info.xpath('./article/a/div/div[2]/div[1]/div[6]/span/text()').extract_first().strip()yield {'title':title,'date':date,'view':view,'dianzan':dianzan,'pinglun':pinglun,'shouchang':shouchang}# print(title,date,view,dianzan,pinglun,shouchang)

        通过yield返回的数据会传到piplines.py文件中,在pipelines.py文件中进行数据的保存。

#管道想要使用要在setting开启
class CsdnPipeline:def process_item(self, item, spider):# print(type(item['title']),type(item['date']),type(item['view']),type(item['dianzan']),type(item['pinglun']),type(item['shouchang']))with open('data.csv',mode='a+',encoding='utf-8') as f:# line =f.write('标题:{} 更新日期:{} 浏览量:{} 点赞:{} 评论:{} 收藏:{} \n'.format(
item['title'],item['date'],item['view'],item['dianzan'],item['pinglun'],item['shouchang']))# f.write(f"标题:{item['title']} 更新日期:{item['date']} 浏览量:{item['view']} 点赞:{item['dianzan']} 评论:{item['pinglun']} 收藏:{item['shouchang']} \n")return item

5. pipelines.py改进

        上面的pipelines.py文件中对于文件的open次数与爬取的信息数量有关,为了减少文件的读取关闭操作,采用全局操作的方式。

class CsdnPipeline:def open_spider(self,spider):self.f = open('data.csv',mode='a+',encoding='utf-8')def close_spider(self,spider):self.f.close()def process_item(self, item, spider):self.f.write('标题:{} 更新日期:{} 浏览量:{} 点赞:{} 评论:{} 收藏:{} \n'.format(
item['title'],item['date'],item['view'],item['dianzan'],item['pinglun'],item['shouchang']))# f.write(f"标题:{item['title']} 更新日期:{item['date']} 浏览量:{item['view']} 点赞:{item['dianzan']} 评论:{item['pinglun']} 收藏:{item['shouchang']} \n")return item

6. 爬虫时,当前页面爬取信息时,需要跳转到其他url

        爬取当前页面时,爬取到的信息是一个url信息,这是需要将其与之前的url进行拼接。

        以https://desk.zol.com.cn/dongman/为主url,/bizhi/123.html为跳转url为例。如果链接以 / 开头,需要拼接的是域名,最前面的 / 是根目录。结果为https://desk.zol.com.cn/bizhi/123.html。如果不是以 / 开头,需要冥界的是当前目录,同级文件夹中找到改内容。结果为https://desk.zol.com.cn/dongman/bizhi/123.html。

        为了方便url的跳转,可以使用python中urllib库或者scrapy封装好的函数。

class PicSpiderSpider(scrapy.Spider):name = 'pic_spider'allowed_domains = ['blog.csdn.net']start_urls = ['http://blog.csdn.net/mozixiao__']def parse(self, response):infos = response.xpath('')for info in infos:if info.endswith(''):continue#方法1from urllib.parse import urljoinchild_url = urljoin(response.url,info)#方法2child_url = response.urljoin(info)

        为了更好地处理跳转之后的链接(不需要用requests库写图片的提取),同时为了方式新的url继续跳转到parse,我们可以重写一个new_parse来处理跳转url。

import scrapy
from scrapy import Requestclass PicSpiderSpider(scrapy.Spider):name = 'pic_spider'allowed_domains = ['blog.csdn.net']start_urls = ['http://blog.csdn.net/mozixiao__']def parse(self, response):infos = response.xpath('')for info in infos:if info.endswith(''):continue#方法1# from urllib.parse import urljoin# child_url = urljoin(response.url,info)#方法2child_url = response.urljoin(info)yield Request(child_url,callback=self.new_parse)def new_parse(self,response):img_src = response.xpath('')yield {"src":img_src}

7. pipelines.py保存对象是图片或者文件等

from itemadapter import ItemAdapterfrom scrapy.pipelines.images import ImagesPipeline
from scrapy.pipelines.files import FilesPipeline
from scrapy import Requestclass PicPipeline(ImagesPipeline):def get_media_requests(self,item,info):srcs = item['src']for src in srcs:yield Request(src,meta={'path':src})def file_path(self,request,response=None,info=None,*,item=None):path = request.meta['path']file_name = path.split('/')[-1]return '***/***/***/{}'.format(file_name)def item_completed(self, results, item,info):return item

注:为了使图片可以成功的保存,需要在settings.py文件中设置一个IMAGES_STORE的路径。同时,如果在下载图片时,出现了302的问题,需要设置MEDIA_ALLOW_REDIRECTS。

8. Scrapy爬虫遇到分页跳转的时候

1.普通分页表现为:上一页  1,2,3,4,5,6  下一页类型1:观察页面源代码发现url直接在页面源代码里体现解决方案:1.访问第一页->提取下一个url,访问下一页2.直接观察最多大少爷,然后观察每一页url的变化类型2:观察页面源代码发现url不在页面源代码中体现解决方案:通过抓包找规律(可能在url上体现,也可能在参数上体现)
2.特殊分页类型1:显示为加载更多的图标,点击之后出来一推新的信息解决方案:通过抓包找规律类型2:滚动刷新,滑倒数据结束的时候会再次加载新数据这种通常的逻辑是:这一次更新时获得的参数会附加到下一次更新的请求中

        情况1:如果遇到分页跳转信息在url中体现,可以通过重写start_request的方式来进行

import scrapy
from scrapy import Requestclass FenyeSpiderSpider(scrapy.Spider):name = 'fenye_spider'allowed_domains = ['blog.csdn.net']start_urls = ['http://blog.csdn.net/']def start_requests(self):num = int(input())for i in range(1,num):url = "https://***.com/page_{}.html".format(i)yield Request(url)def parse(self, response):pass

        情况2:分页跳转信息的url体现在的页面源代码中

import scrapy
from scrapy import Requestclass FenyeSpiderSpider(scrapy.Spider):name = 'fenye_spider'allowed_domains = ['blog.csdn.net']start_urls = ['http://blog.csdn.net/page_1.html']def parse(self, response):infos = response.xpath('')for info in infos:if info.startswith('***'):continuechild_info = response.urljoin(info)#这里无需考虑死循环的问题,scrapy中的调度器会自动去重yield Request(child_info,callback=self.parse)

9. Scrapy面对带有cookie的信息页面时的登陆操作

1.常规登录网站会在cookie中写入登录信息,在登陆成功之后,返回的响应头里面会带着set-cookie字样,后续的请求会在请求头中加入cookie内容可以用session来自动围护响应头中的set-cookie
2. ajax登陆登陆后,从浏览器中可能发现响应头没有set-cookie信息,但是在后续的请求中存在明显的cookie信息该情况90%的概率是:cookie通过JavaScript脚本语言动态设置,seesion就不能自动维护了,需要通过程序手工去完成cookie的拼接
3. 依然是ajax请求,也没有响应头,也是js和2的区别是,该方式不会把登录信息放在cookie中,而是放在storage里面。每次请求时从storage中拿出登录信息放在请求参数中。这种方式则必须要做逆向。该方式有一个统一的解决方案,去找公共拦截器。

        方法1,直接在settings.py文件中设置请求头信息。但是由于scrapy(引擎和下载器之间的中间件)会自动管理cookie,因此设置时,也需要将COOKIES_ENABLED设置为False

                方法2,重写start_requests函数,将cookie作为参数传入

import scrapy
from scrapy import Requestclass LoginSpiderSpider(scrapy.Spider):name = 'login_spider'allowed_domains = ['blog.csdn.net']start_urls = ['http://blog.csdn.net/']def start_requests(self):cookie_info = ""cookie_dic = {}for item in cookie_info.split(';'):item = item.strip()k,v = item.split('=',1)cookie_dic[k]=v#需要注意的是,这里的cookie要以自己的参数传入,而不是字符串yield Request(self.start_urls[0],cookies=cookie_dic)def parse(self, response):pass

        方法3,自己走一个登录流程,登录之后,由于scrapy(引擎和下载器之间的中间件)会自己管理cookie信息,所以直接执行start_urls即可。

import scrapy
from scrapy import Requestclass LoginSpiderSpider(scrapy.Spider):name = 'login_spider'allowed_domains = ['blog.csdn.net']start_urls = ['http://blog.csdn.net/']def start_requests(self):login_url = "https://blog.csdn.net/login"data = {'login':'123456','password':'123456'}#但是这里要注意,Request中的body需要传入的是字符串信息,而不是字典#方法1login_info = []for k,v in data.items():login_info.append(k+"="+v)login_info = '&'.join(login_info)#方法2from urllib.parse import urlencodelogin_info = urlencode(data)yield Request(login_url,method='POST',body=login_info)def parse(self, response):pass

10. Scrapy中间件

        中间件位于middlewares.py文件中,

11. Scrapy之链接url提取器

        上面提到当爬虫需要跳转url时,需要使用urljoin的函数来进行url的凭借,这个操作可以使用LinkExtractor来简化。

from urllib.request import Request
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy import Request
import reclass LinkSpiderSpider(scrapy.Spider):name = 'link_spider'allowed_domains = ['4399.com']start_urls = ['https://www.4399.com/flash_fl/5_1.htm']def parse(self, response):# print(response.text)game_le = LinkExtractor(restrict_xpaths=("//ul[@class='list affix cf']/li/a",))game_links = game_le.extract_links(response)for game_link in game_links:# print(game_link.url)yield Request(url=game_link.url,callback=self.game_name_date)if '5_1.htm' in response.url:page_le = LinkExtractor(restrict_xpaths=("//div[@class='bre m15']//div[@class='pag']/a",))else:page_le = LinkExtractor(restrict_xpaths=("//div[@class='pag']/a",))page_links = page_le.extract_links(response)for page_link in page_links:# print(page_link.url)yield Request(url=page_link.url,callback=self.parse)def game_name_date(self,response):try:name = response.xpath('//*[@id="skinbody"]/div[7]/div[1]/div[1]/div[2]/div[1]/h1/a/text()')info = response.xpath('//*[@id="skinbody"]/div[7]/div[1]/div[1]/div[2]/div[2]/text()')if not info:info = response.xpath('//*[@id="skinbody"]/div[6]/div[1]/div[1]/div[2]/div[2]/text()')# print(name,info)# print(1)name = name.extract_first()infos = info.extract()[1].strip()size = re.search(r'大小:(.*?)M',infos).group(1)date = re.search(r'日期:(\d{4}-\d{2}-\d{2})',infos).group(1)yield {'name':name,'size':size+'M','date':date}except Exception as e:print(e,info,response.url)

12. 增量式爬虫

        当爬取的数据中包含之前访问过的数据时,需要对url进行判断,以保证不重复爬取。增量式爬虫不能将中间数据存储在内存级别的存储,只能选择硬盘上的存储。

import scrapy
from redis import Redis
from scrapy import Request,signalsclass ZengliangSpiderSpider(scrapy.Spider):name = 'zengliang_spider'allowed_domains = ['4399.com']start_urls = ['http://4399.com/']#观察到middlewares中间间中的写法,想要减少程序连接redis数据库的次数@classmethoddef from_crawler(cls, crawler):# This method is used by Scrapy to create your spiders.s = cls()#如果遇到Crawler中找不到当前spider时,可以参考父类中的写法,将去copy过来#s._set_crawler(crawler)crawler.signals.connect(s.spider_opened, signal=signals.spider_opened)crawler.signals.connect(s.spider_closed, signal=signals.spider_closed)return sdef spider_opened(self, spider):self.red = Redis(host='',port=123,db=3,password='')def spider_closed(self,spider):self.red.save()self.red.close()def parse(self, response):hrefs = response.xpath('').extract()for href in hrefs:href = response.urljoin(href)if self.red.sismember('search_path',href):continueyield Request(url=href,callback=self.new_parse,meta={'href':href} #防止url重定向)def new_parse(self,response):href = response.meta.get('href')self.red.sadd('save_path',href)pass

13. 分布式爬虫

        scrapy可以借助scrapy-redis插件来进行分布式爬虫,但要注意两个库的版本问题。

        与普通的scrapy不同,redis版本的在spider文件中继承时采用redis的继承。

from scrapy_redis.spiders import RedisSpiderclass FbSpider(RedisSpider):name = 'fb'allowed_domains = ['4399.com']redis_key = "path"def parse(self, response):pass

        同时,需要在settings.py中设置redis相关的信息。

SCHEDULER = "scrapy_redis.scheduler.Scheduler"
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
SCHEDULER_PERSIST = TrueITEM_PIPELINES = {'fenbu.pipelines.FenbuPipeline': 300,'scrapy_redis.pipelines.RedisPipeline':301
}
REDIS_HOST = ''
REDIS_PORT = ''
REDIS_DB = ''
REDIS_PARAMS = {'':''
}

以上这些就是我关于scrapy爬虫的基本学习,有疑问可以相互交流。

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

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

相关文章

Transformer-BiLSTM、Transformer、CNN-BiLSTM、BiLSTM、CNN五模型时序预测

Transformer-BiLSTM、Transformer、CNN-BiLSTM、BiLSTM、CNN五模型时序预测 目录 Transformer-BiLSTM、Transformer、CNN-BiLSTM、BiLSTM、CNN五模型时序预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 Transformer-BiLSTM、Transformer、CNN-BiLSTM、BiLSTM、CNN五…

历史数据分析——唐山港

个股简介 公司简介: 唐山港口投资有限公司、北京京泰投资管理中心、河北利丰燕山投资管理中心、国富投资公司、唐山市建设投资公司、河北省建设投资公司、国投交通实业公司7家发起人共同发起设立。 经营分析: 港口经营一般项目:港口货物装卸搬运活动;普通货物仓储服务(不含…

云端回声消除:让超低端硬件能玩实时打断

传统认知里“优质交互 高性能硬件”的等式正在被打破? 超低端开发板也能实现高配置硬件才有的实时打断语音交互? 网易云信推出的云端回声消除技术不仅解决了硬件配置对交互体验的限制,更以系统性解决方案重构了嵌入式设备的实时对话体验。 困…

堆排序的详细解读

一.堆的基本概念 1.什么是堆 堆是一种特殊的完全二叉树,满足一下性质: 最大堆:每个节点的值都大于或等于其子节点的值(堆顶元素最大)最小堆:每个节点的值都小于或等于其子节点的值(堆顶元素最小…

hmdp知识点

1. 前置知识 1.1 MyBatisPlus的基本使用 1.1.1 引入依赖 <dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.3</version> </dependency> 1.1.2 建立实体类和数…

分享5个免费5个在线工具网站:Docsmall、UIED Tool在线工具箱、草料二维码、图片在线压缩、表情符号

01. Docsmall 它是一个免费的在线图片与PDF处理工具&#xff0c;功能主要包含Ai图片处理工具&#xff0c;图片压缩工具&#xff0c;图片PDF格式转换工具等&#xff0c;如下图&#xff0c;我认为比较实用的是自动抠图、图片变高清、图片压缩和PDF压缩。 https://docsmall.com/…

打通印染车间“神经末梢”:DeviceNet转Ethernet/IP连接机器人的高效方案

在印染行业自动化升级中&#xff0c;设备联网需求迫切。老旧印染设备多采用Devicenet协议&#xff0c;而新型工业机器人普遍支持Ethernet/IP协议&#xff0c;协议不兼容导致数据交互困难&#xff0c;设备协同效率低、生产监控滞后&#xff0c;成了行业数字化转型的阻碍。本文将…

RSA加密算法:非对称密码学的基石

一、RSA算法概述 RSA&#xff08;Rivest-Shamir-Adleman&#xff09;是1977年由Ron Rivest、Adi Shamir和Leonard Adleman提出的非对称加密算法&#xff0c;它基于大数分解的数学难题&#xff0c;是当今应用最广泛的公钥密码系统。RSA的核心思想是使用一对密钥&#xff08;公钥…

杭州瑞盟 MS35774/MS35774A 低噪声256细分微步进电机驱动,用于空调风门电机驱动,香薰电机驱动

杭州瑞盟 MS35774/MS35774A 低噪声256细分微步进电机驱动&#xff0c;用于空调风门电机驱动&#xff0c;香薰电机驱动 简述 MS35774/MS35774A 是一款高精度、低噪声的两相步进 电机驱动芯片&#xff0c;芯片内置功率 MOSFET &#xff0c;长时间工作的平均电 流可以达到 1…

驶向智能未来:车载 MCP 服务与边缘计算驱动的驾驶数据交互新体验

引言 在人工智能技术与车载算力持续突破的驱动下&#xff0c;现代车辆的数字化进程正加速推进。车联网系统将突破传统云端架构的局限&#xff0c;依托边缘计算与 AI 融合技术&#xff0c;实现人车交互体验的范式重构‌。通过构建基于多源异构数据的自动化分析框架&#xff0c;…

Python数据可视化科技图表绘制系列教程(三)

目录 单一柱状图 分组柱状图 堆积柱状图 百分比柱状图 均值柱状图 不等宽柱状图 有序柱状图 条形图 发散条形图 在条上添加标签的发散条形图 基础棒棒糖图1 基础棒棒糖图2 【声明】&#xff1a;未经版权人书面许可&#xff0c;任何单位或个人不得以任何形式复制、发…

JavaScript 数组与流程控制:从基础操作到实战应用

在 JavaScript 编程的世界里&#xff0c;数组是一种极为重要的数据结构&#xff0c;它就像是一个有序的 “收纳盒”&#xff0c;能够将多个值整齐地存储起来。而流程控制语句则像是 “指挥官”&#xff0c;能够按照特定的逻辑对数组进行遍历和操作。接下来&#xff0c;就让我们…

十(1). 强制类型转换

继第十部分C强制类型转换的四种方式&#xff0c;再进行强化巩固一下知识点 static_cast 最常用的&#xff0c;在指针之间做转换 const_cast 去除常量属性 dynamic_cast 用在基类和派生类之间的转换 reinterpret_cast 在任意类型之间进行转 10.1 static_cast 常见的使用场景&am…

Git版本控制工具详解

如何区分开发环境和生产环境呢 答案就是写不同的配置文件&#xff0c;开发的设置成开发需要的&#xff0c;生产的设置成生产需要的&#xff0c;共同放到config这个配置文件夹下面&#xff0c;开发和生成的时候分别加载不同的配置文件 方式二就是使用相同的一个入口配置文件&a…

反向传播的核心是什么:计算损失函数对可训练参数的梯度=== 损失函数能通过计算图连接到可训练参数

反向传播的核心是什么:计算损失函数对可训练参数的梯度 损失函数能通过计算图连接到可训练参数 在深度学习中,反向传播的核心是计算损失函数对可训练参数的梯度,从而更新这些参数。对于LLM(大型语言模型)而言,是否需要“LLM输出的参数”才能进行反向传播 一、反向传播…

KINGCMS被入侵

现象会强制跳转到 一个异常网站,请掉截图代码. 代码中包含经过混淆处理的JavaScript&#xff0c;它使用了一种技术来隐藏其真实功能。代码中使用了eval函数来执行动态生成的代码&#xff0c;这是一种常见的技术&#xff0c;恶意脚本经常使用它来隐藏其真实目的。 这段脚本会检…

深入探索串的高级操作:从算法到 LeetCode 实战

串是编程中最常用的数据结构之一&#xff0c;从简单的文本处理到复杂的文本匹配算法&#xff0c;串的应用无处不在。在掌握了串的基本概念、存储结构以及KMP算法之后&#xff0c;现在让我们深入探索串的更多高级操作&#xff0c;例如求子串、串的替换等&#xff0c;并通过LeetC…

在rocky linux 9.5上在线安装 docker

前面是指南&#xff0c;后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …

OneNet + openssl + MTLL

1.OneNet 使用的教程 1.在网络上搜索onenet&#xff0c;注册并且登录账号。 2.产品服务-----物联网服务平台立即体验 3.在底下找到立即体验进去 4.产品开发------创建产品 5.关键是选择MQTT&#xff0c;其他的内容自己填写 6.这里产品以及开发完成&#xff0c;接下来就是添加设…

【Fiddler工具判断前后端Bug】

Fiddler工具判断前后端Bug的方法 使用Fiddler抓包工具可以高效定位问题是出在前端还是后端&#xff0c;主要通过分析请求和响应的内容、状态码、数据格式等关键信息。 分析请求是否成功发送 检查请求是否从客户端正确发出&#xff0c;观察Fiddler抓取的请求列表。若请求未出…