Python爬虫框架【Scrapy】
Scrapy,Python开发的一个快速、高层次的屏幕抓取和web抓取框架用于抓取web站点并从页面中提取结构化的数据Scrapy用途广泛,可以用于数据挖掘、监测和自动化测试Scrapy吸引人的地方在于它是一个框架,任何人都可以根据需求方便的修改它也提供了多种类型爬虫的基类如BaseSpider、sitemap爬虫等,最新版本又提供了web2.0爬虫的支持
Scrapy 架构
Scrapy Engine(引擎): 分配任务给其他模块,负责其它模块之间的通信,数据传递等Scheduler(调度器): 接受引擎发送的Request请求,整理入队,当需要时返回给引擎Downloader(下载器): 从引擎处接收并下载调度器整理后返回的Requests请求,并将获取的Responses返回给引擎Spider(爬虫): 提供初始网址,接收并处理从引擎处接收下载器返回的Responses分析并提取Item需要的数据返回给管道,并将需要跟进的网址url提交给引擎Item Pipeline(管道):它负责处理Spider中获取到的Item,并进行进行后期处理(详细分析、过滤、存储等)的地方。Downloader Middlewares(下载中间件): 你可以当作是一个可以自定义扩展下载功能的组件Spider Middlewares(Spider中间件): 你可以理解为是一个可以自定扩展和操作引擎和Spider中间通信的功能组件(比如进入Spider的Responses;和从Spider出去的Requests)
流程:
->Spider 提交初始爬取网址相关信息给Engine->Engine根据Spider提交的数据发起Requests给Scheduler->Scheduler将接收到的Requests进行整理入队,再返还给Engine->Engine将整理后的Requests请求发送给Downloader->Downloader将Requests请求提交给网站服务器并将服务器返回的Responses交给Engine->Engine将Responses交给Spider进行处理->Spider将从Responses中提取Item字段需要的信息和需要跟进的url 信息交给pipelines,url则提交给Engine,进行下一次爬取->pipelines将完成对信息的分析,筛选和存储等工作。在Scheduler整理的Requests请求队列全部执行并处理完毕后,程序结束。
简化流程:
由于在Engine主要用于个模块之间的信息传递,可以简化工作流程如下:Spider发送初始url ---------------> Scheduler整理请求并入队(Engine发起请求)Scheduler 发送整理后的请求 ----------------->Downloader向网址提交请求并获取responsesDownloader发送获取的responses ------------------>Spider分析并提取Item所需信息和需要跟进的urlSpider发送Item所需信息 ----------------->pipelines分析,筛选,存储信息Spider发送需要跟进的url -----------------> Scheduler整理请求并入队(Engine发起请求)
利用Scrapy制作爬虫安装Scrapy
pip install scarpy
实现步骤
1.新建项目 (scrapy startproject projectname)2.确定目标 (编写items.py)(即编写需要获取的Item字段)3.制作爬虫 (编写spiders/xxspider.py)(分析responses并提取数据)4.存储内容 (编写pipelines.py)(分析筛选数据并储存)
1.新建项目
命令:scrapy startproject projectnameprojectname为需要指定的项目名
进入项目并利用tree命令输出项目结构
scrapy.cfg: 项目的配置文件。TestSpider/: 项目的Python模块,将会从这里引用代码。TestSpider/items.py: 项目的目标文件。TestSpider/pipelines.py: 项目的管道文件。TestSpider/settings.py: 项目的设置文件。TestSpider/spiders/: 存储爬虫代码目录。
2.确定爬取目标(编写items.py)
我们以爬取菜鸟教程为例,网址: http://www.runoob.com/需要的数据为 教程名 图片url 简要描述 教程url
编辑items.py如下:Item定义了一个结构化数据字段,类似于字典,用于保存爬取到的数据
import scrapyclass TestspiderItem(scrapy.Item): # define the fields for your item here like: # name = scrapy.Field() name = scrapy.Field() # 教程名 img_url = scrapy.Field() # 图片地址 desc = scrapy.Field() # 描述 url = scrapy.Field() # 教程链接
3.制作爬虫 (编写spiders/xxspider.py)
在项目目录中输入命令命令:scrapy genspider spidername 'start_url' spidername 为需要指定的爬虫名称 start_url为初始爬取地址此时会在spiders目录中创建spidername.py文件,并添加必须的代码
import scrapyclass RunoobSpider(scrapy.Spider): name = 'runoob' allowed_domains = ['www.runoob.com'] start_urls = ['http://www.runoob.com/'] def parse(self, response): pass
当然,使用命令不是必需的,也可以选择自己创建和编写但使用命令帮我们免去了写一些必须代码的麻烦在此基础上,根据我们的需求编写爬虫代码编写代码如下:
import scrapy# 导入在items中写好的类from TestSpider.items import TestspiderItem # 编写爬虫class RunoobSpider(scrapy.Spider): name = 'runoob' # 文件名 allowed_domains = ['www.runoob.com'] # 允许访问的网址 start_urls = ['http://www.runoob.com/'] # 开始访问的网址 def parse(self, response): course = TestspiderItem() # 实例化一个Item数据对象 # 获取class为"item-top item-1"的节点 courseInfos = response.xpath('//a[@class="item-top item-1"]') # 遍历节点 for courseInfo in courseInfos: # 根据需求提取指定数据并存入Item的对象中 course['url'] = courseInfo.xpath('@href')[0].extract() course['name'] = courseInfo.xpath('.//h5/text()')[0].extract() course['img_url'] = courseInfo.xpath('.//img/@src')[0].extract() course['desc'] = courseInfo.xpath('.//strong/text()')[0].extract() # 输出测试文件观察获取数据是否正确 #open('test.log','w').write('%s\n%s\n%s\n%s'%(type(course['url']),course['name'],type(course['img_url']),type(course['desc']))) # 返回数据 yield course
查看test.log中的数据
4.存储内容 (编写pipelines.py)(1)使用命令存储:
scrapy crawl spidername -o spidername.(json|jsonl|csv|xml) 以json / json lines / csv / xml格式存储在当前路径下
存储的csv文件,默认按照ASCII码编码顺序排列
(2)编写pipelines.py(需要设置setting)自定义存储
定义一个管道类,完成写入操作>>>>>>>>保存至文件,保存json格式数据,文件名为runoob.txt
class TestspiderPipeline(object): # 以‘只写’方式打开runoob.txt文件 def __init__(self): self.f = open('runoob.txt','w') # pipeline中执行的程序 def process_item(self, item, spider): # 测试语句,item返回的是获取到的Item数据类型(前面定义过的类型) # open('runoob.log','w').write(str(type(item))) # 存储为json格式,不使用ascii编码,缩进为4 import json line = json.dumps(dict(item),ensure_ascii=False,indent=4) self.f.write(line+'\n') return item # 关闭文件 def close_spider(self): self.f.close()
>>>>>>>>保存至mysql数据库创建数据库runoob并指定utf8编码格式(create database runoob default charset=utf8;)
class MysqlPipeline(object): def __init__(self): # 构造时链接数据库 import pymysql self.conn =pymysql.connect( host='localhost', user='root', password ='redhat', database ='runoob', charset ='utf8', autocommit = True ) # 创建游标 self.cur = self.conn.cursor() # 创建数据表 create_sqli = 'create table if not exists course(教程名称 varchar(50),链接 varchar(300),教程简介 varchar(200))' self.cur.execute(create_sqli) def process_item(self, item, spider): # 插入数据 insert_sqli = 'insert into course values("%s","%s","%s") '%(item['name'],item['url'],item['desc']) self.cur.execute(insert_sqli) return item def close_spider(self): # 关闭游标和连接 self.cur.close() self.conn.close()
>>>>>>>>保存媒体图片
# 图片存储class ImagePipeline(ImagesPipeline): # 获取媒体请求 def get_media_requests(self, item, info): # 测试语句 # open('mooc.log','w').write(item['img_url']) # 返回图片 yield scrapy.Request(item['img_url']) # results是返回的一个元组(True ,{'url':xxx,'path':xxx,'checksum':xxx}) # info返回的是一个对象scrapy.pipelines.media.MediaPipeline.SpiderInfo def item_completed(self, results, item, info): # 测试语句 # for i in results: # open('ni.txt', 'w').write(str(i)+'\n'+str(info)) # 获取results中的path image_path = [x['path'] for ok,x in results if ok] # path为None,则不包含图片,否则返回item if not image_path: raise Exception('不包含图片') else: return item
保存图片还需要在settings.py中设置图片保存的路径管道默认不执行,需要在settings.py中修改设置后面的数字设定优先级,数字越小,优先级越高
执行爬虫并查看保存的数据执行爬虫
在工程路径中输入命令命令: scrapy crawl spidername spidername为爬虫文件名
查看数据
文件
数据库
图片
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。