一、前言
近期工作遇到了一些和网络爬虫相关的内容,于是抽时间了解一下爬虫系统。这边文章是学习和使用Scrapy框架进行信息爬取的一篇学习笔记。
二、Scrapy的基本介绍
简介
Scrapy(/ˈskreɪpaɪ/)是一个用于爬取网站并提取结构化数据的应用程序框架,可用于各种有用的应用程序,例如数据挖掘、信息处理或历史档案。尽管Scrapy最初是为了网络抓取而设计的,但也可以用于使用API(如亚马逊联盟网络服务)提取数据或作为通用网络爬虫。
(摘自Scrapy官方文档:docs.scrapy.org/en/latest/i...
组件介绍
- Scrapy Engine(引擎) : 负责Spider、ItemPipeline、Downloader、Scheduler中间的通讯,信号、数据传递等。
- Scheduler(调度器) : 它负责接受引擎发送过来的Request请求,并按照一定的方式进行整理排列,入队,当引擎需要时,交还给引擎。
- Downloader(下载器) :负责下载Scrapy Engine(引擎)发送的所有Requests请求,并将其获取到的Responses交还给Scrapy Engine(引擎),由引擎交给Spider来处理,
- Spider(爬虫) :它负责处理所有Responses,从中分析提取数据,获取Item字段需要的数据,并将需要跟进的URL提交给引擎,再次进入Scheduler(调度器).
- Item Pipeline(管道) :它负责处理Spider中获取到的Item,并进行进行后期处理(详细分析、过滤、存储等)的地方。
- Downloader Middlewares(下载中间件) :你可以当作是一个可以自定义扩展下载功能的组件。
- Spider Middlewares(Spider中间件) :你可以理解为是一个可以自定扩展和操作引擎和Spider中间通信的功能组件(比如进入Spider的Responses;和从Spider出去的Requests)
数据流控制
在Scrapy中,数据流由执行引擎控制,流程如下:
- 引擎从Spider获取要爬取的初始请求。
- 引擎将请求安排到调度器中,并请求下一个要爬取的请求。
- 调度器将下一个要爬取的请求返回给引擎。
- 引擎将请求发送给下载器,经过下载器中间件。
- 页面下载完成后,下载器生成一个带有该页面的响应,并将其发送给引擎,此过程会经过下载器中间件。
- 引擎从下载器接收响应,并将其经过Spider中间件发送给Spider进行处理。
- Spider处理响应,经过Spider中间件返回抓取的数据项和新的请求。
- 引擎将处理后的数据项发送到数据管道,然后将处理后的请求发送给调度器,并请求下一个要爬取的请求。
- 重复上述过程(从步骤3)直到调度器没有更多的请求为止。
三、Scrapy实践
目标
从Foresight News网站上爬取Web3投融资信息并持久化存储
执行步骤
简单总结爬取数据的步骤,可以分为以下三步:
- 爬取目标网站
- 结构化数据选取
- 存储数据
爬取目标网站
首先,创建爬虫项目,可以使用如下命令
js
scrapy startproject foresight
其次,创建爬虫(genspider),进入foresight/spiders目录,执行命令,生成对应的爬虫程序代码fundrasing.py
js
scrapy genspider fundraising "https://foresightnews.pro/wiki/fundraising"
命令行会自动生成一个包含spider基本属性和方法的模板,先对parse函数进行简单修改:
js
def parse(self, response):
filename = "fr.html"
open(filename, 'wb').write(response.body)
然后运行爬虫程序,验证一下是否可以爬取到数据,运行命令如下:
js
scrapy crawl fundraising
运行后,在当前目录下生成了"fr.html"文件。
结构化数据选取
首先,定义一个想要提取的结构化数据类型,它需要包含:公司(项目)名称、融资金额,融资轮次和融资时间。
js
class ForesightItem(scrapy.Item):
# define the fields for your item here like:
name=scrapy.Field()
amount=scrapy.Field()
amount_unit=scrapy.Field()
amount_round=scrapy.Field()
date=scrapy.Field()
然后从爬取中的页面中,提取这些信息。修改刚才写好的fundrasing.py,把简单的保存整个HTML的逻辑改为从页面中提取相应的元素。
js
import scrapy
from foresight.items import ForesightItem
class FundraisingSpider(scrapy.Spider):
name = "fundraising"
allowed_domains = ["foresightnews.pro"]
start_urls = ["https://foresightnews.pro/wiki/fundraising"]
def parse(self, response):
elements=response.xpath('//*[@class="invest InvestCord"]')
for element in elements:
item = ForesightItem()
item_name = element.xpath('./div/div/span[@class="name"]/text()').extract()
item_amount=element.xpath('./div[1]/div[2]/div[1]/text()').extract()[0].strip()
item_amount_unit=element.xpath('./div[1]/div[2]/div[1]/span/text()').extract()
item_amount_round=element.xpath('./div[1]/div[2]/div[2]/text()').extract()
item_date=element.xpath('./div[1]/div[3]/text()').extract()
# print(f"名字:{item_name}, 融资金额: {item_amount},{item_amount_unit}融资轮次: {item_amount_round},日期: {item_date}")
item['name'] = item_name
item['amount'] = item_amount
item['amount_unit']=item_amount_unit
item['amount_round'] = item_amount_round
item['date'] = item_date
# return or yield ?
yield item
关于return和yield的区别:
注意:如果想要使用Scrapy的pipeline处理item数据,在parse()函数结尾处需要用yield关键字
数据持久化
有两种方式可以完成的数据持久化,简单的办法是通过命令行存储文件,支持的文件格式有:JSON、JSON lines、CSV和XML。另一种发放可以通过Pipeline实现数据的存储逻辑。
1.命令行存储文件:
js
scrapy crawl fundraising -O foresight.csv
可以看到在当前目录下,出现了foresight.csv文件,文件中存储了之前定义好的几项信息。
2.通过Pipeline存储数据
另一种存储数据的方式是通过pipeline接受每一个item数据,随后可以通过写入文件或者数据库等存储媒介。
以写入文件为例,自定义一个pipeline:
js
class ForesightPipeline:
def __init__(self):
self.file = open('./foresight2.csv', 'wb')
self.exporter = CsvItemExporter(self.file,fields_to_export=["name","amount","amount_unit","amount_round","date"])
self.exporter.start_exporting()
def process_item(self, item, spider):
if isinstance(item, ForesightItem):
self.exporter.export_item(item)
return item
def close_spider(self, spider):
self.exporter.finish_exporting()
self.file.close()
print(f"文件已保存至:{self.file.name}")
这段代码里使用了框架提供的CsvItemExporter类,使用时仅需要通过传入文件名和CSV首行名称,即可按顺序逐行写入文件。
另外,如果要pipeline生效,需要在此项目的setting文件里加入pipeline的配置:
js
ITEM_PIPELINES = {
"foresight.pipelines.ForesightPipeline": 300,
}
在这个设置中需要给不同的pipeline赋予整数值,这个整数在习惯上通常定义在0-1000的范围内,整数值决定pipeline的运行顺序,按照从小到大的顺序依次执行。
配置完成后,再执行
js
scrapy crawl fundraising
可以在代码目录下生成一个名为"foresight2.csv"的文件,里面存储了爬取的数据信息:
除了写文件之外,还经常通过pipeline进行数据去重、简单的数据处理、写入数据库等操作。
至此,一个简单的网页爬虫就完成了,可以在此基础上增加更多目标地址,或者根据当前页面的url进行递归爬取。另外Scrapy还提供了一套插件管理体系,支持开发人员扩展系统配置,增加额外功能,关于Scrapy的更多使用方式和技巧,还是需要在实践中逐渐探索和加深理解的。