python爬虫框架scrapy学习记录
一 爬虫简介
爬虫这种技术听说好多年了,知道它从互联网抓取数据非常厉害,但由于不是专门从事相关工作,了解也就是听听。最近有些空闲,打算实际学习一下,这里做个小小记录。
二 常用框架介绍
- 通用性框架
类型 | 说明 |
---|---|
scrapy | 最流行的爬虫框架,功能全面,扩展性强,社区支持完善,适用于中大型爬虫项目 |
pySpider | 国产爬虫框架,自带web界面,方便监控和管理 |
-
轻量级框架
beautifulSoup+Requests 经典的轻量级组合,适合小型爬虫任务 -
浏览器自动化/动态页面处理框架
Selenium 或 playwright -
分布式爬虫框架
scrapy-Redis 继承scrapy所有功能,是scrapy的分布式扩展
PS:从学习的角度和通用性来说,入门scrapy是最佳选择
三 scrapy框架学习
scrapy是一个快速的高级web爬虫和网页抓取框架,用于爬取网站并从其页面中提取结构化数据,它可用于从数据挖掘到监控和自动化测试等各种用途。以下内容是在linux虚拟机上操作
- 安装scrapy
sudo apt-get install python3 python3-dev python3-pip libxml2-dev libxslt1-dev zlib1g-dev libffi-dev libssl-dev
pip install scrapy
安装完成后,可以使用 scrapy --version 查看版本信息
- 创建scrapy项目
scrapy startproject quotes_scraper #创建项目quotes_scraper
3 目录结构
quotes_scraper/ #项目包目录├── quotes_scraper/│ ├── __init__.py #使当前文件夹成为一个python包,通常为空│ ├── items.py #定义抓取数据的数据结构(类似数据库字段模型)│ ├── middlewares.py #定义中间件逻辑,拦截和修改scrapy请求或响应,类似浏览器插件│ ├── pipelines.py #定义爬取数据后续怎么处理,比如保存还是清洗│ ├── settings.py #scrapy项目的全局配置文件│ └── spiders/ #放置所有爬虫的地方(核心爬虫逻辑)│ └── __init__.py #使spiders/成为一个python包,通常为空| |___quotes_spider.py #自己创建的爬虫文件,每个.py文件定义一个spider类,负责抓取某一类网页| # 每个spider类可以认为是一个爬虫(爬取单元)└── scrapy.cfg #项目配置入口文件,可以认为执行爬虫时,会从这里进入然后加载到项目里面的配置模块 settings.py ps:经过实践,简单的项目其实主要是对quotes_spider.py进行实现就行了,其他py文件不用动
四 项目实践1 :爬取Quotes to Scrape 网站上的名人名言、作者、标签
1.scrapy startproject quotes_spider -------------创建项目
2.cd quotes_spider;
scrapy genspider quotes quotes.toscrape.com-----创建一个初始爬虫quotes.py,用来爬取域名为“quotes.toscrape.com”的网站
3.编辑quotes.py 爬虫内容实现
4.scrapy crawl quotes —运行爬虫
PS:quotes.py实现内容如下
import scrapy #引入scrapy模块,为定义爬虫类做准备;scrap是python写的爬虫框架,scrapy.Spider是它提供的基类class QuotesSpider(scrapy.Spider): #定义一个继承自scrapy.Spider名为QuotesSpider的爬虫类;前者是所有爬虫类的基类name = "quotes" #定义爬虫的名字,用来在命令行启动爬虫,名字不能重复,项目中唯一allowed_domains = ["quotes.toscrape.com"] #这是一个域名白名单,防止爬虫误爬start_urls = ["https://quotes.toscrape.com"]#指定爬虫的初始入口地址,这是爬虫开始抓取的第一个页面#scrapy会自动向这个地址发送请求,并将响应交给parse()方法处理def parse(self, response): #parse是scrapy中默认的,用于处理网页response响应的回调函数;pass这里是占位符,表示这个函数没有实现任何逻辑,依赖用户实现#response代表请求的网页对象所有内容及相关信息for quote in response.css("div.quote"): #通过css选择器选中html中所有class=quote的div标签 yield{ #yield返回一条提取到的数据记录;scrapy会把yield出来的字典当作一个item,最终保存或传给管道处理"text":quote.css("span.text::text").get(),#找到span标签里面class=text的span,::text提取文本内容"author":quote.css("small.author::text").get(), #提取 <small class="author"> 标签的文本内容"tags":quote.css("div.tags a.tag::text").getall(),#找出 <div class="tags"> 下面所有 <a class="tag"> 标签的文本} #.getall() 表示获取所有匹配项的文本,返回的是一个列表next_page = response.css("li.next a::attr(href)").get() #获取超链接地址if next_page:yield response.follow(next_page,self.parse)#是scrapy中翻页(抓取下一页)的核心写法之一,意思是根据next_page提供的链接地址,发起新的请求,并用#当前的parse方法处理返回的页面内容#response.follow是scrapy提供的简化方法,用于跟进链接并创建新的请求#这一句可以保证抓到最后一页
五 项目实践2:从东方财富网爬取股票信息
1.scrapy startproject stock_spider
2.cd stock_spider;
scrapy genspider dfcf quotes.eastmoney.com
3.编辑爬虫文件dfcf.py
4.运行并导出文件(临时测试,settings.py文件robotobey 改为false)
scrapy crawl dfcf -o stock.csv -s FEED_EXPORT_ENCODING=gbk
PS:dfcf.py实现内容如下
import scrapy
import json #json是一种轻量级的数据交换格式,本质是纯文本表示结构化数据,这句导入json库,提供了处理json数据的方法class DfcfSpider(scrapy.Spider):name = "dfcf"allowed_domains = ["eastmoney.com"]start_urls = ["https://79.push2.eastmoney.com/api/qt/clist/get?pn=1&pz=10&fid=f3&fs=m:1+t:2&fields=f12,f14,f2,f3,f4,f5,f6,f15,f16"]def parse(self, response):data = json.loads(response.text) #把json字符串转为python数据;可以先看接口文档确认原始数据是否是json格式# 打印结构用于调试print("=========原始数据===========")print(data)if 'data' in data and 'diff' in data['data']: #判断某个键是否在字典里if key in dict #索引字典元素 dict['key']stocks = data['data']['diff'] #从嵌套字典结构的JSON数据中提取data键下面的diff这部分内容,赋值给stocksfor _, stock in stocks.items(): # .items()是字典专用,用来获取键值对yield { #yield关键字会生成一条字典结构的爬取结果,scrapy会自动收集这些结果项item,后续可以导出为json或csv或传给处理管道"code": stock.get('f12'),"name": stock.get('f14'),"price": stock.get('f2'),"change_percent": stock.get('f3'),"change_amount": stock.get('f4'),"volume": stock.get('f5'),"turnover": stock.get('f6'),"high": stock.get('f15'),"low": stock.get('f16'),}else:self.logger.error("未找到 data.diff 字段,接口可能变了或数据为空")
六 总结
本文章只是简单介绍了下scrapy怎么创建项目,以及用两个小小的demo来测试,看下爬虫的效果。后续真的有了使用场景,我再深入研究下,更新相关内容