Scrapy,Python开发的一个快速、高层次的屏幕抓取和web抓取框架
用于抓取web站点并从页面中提取结构化的数据
Scrapy用途广泛,可以用于数据挖掘、监测和自动化测试
Scrapy吸引人的地方在于它是一个框架,任何人都可以根据需求方便的修改
它也提供了多种类型爬虫的基类
如BaseSpider、sitemap爬虫等,最新版本又提供了web2.0爬虫的支持
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向网址提交请求并获取responses
Downloader发送获取的responses ------------------>Spider分析并提取Item所需信息和需要跟进的url
Spider发送Item所需信息 ----------------->pipelines分析,筛选,存储信息
Spider发送需要跟进的url -----------------> Scheduler整理请求并入队(Engine发起请求)
pip install scarpy
1.新建项目 (scrapy startproject projectname)
2.确定目标 (编写items.py)(即编写需要获取的Item字段)
3.制作爬虫 (编写spiders/xxspider.py)(分析responses并提取数据)
4.存储内容 (编写pipelines.py)(分析筛选数据并储存)
命令:scrapy startproject projectname
projectname为需要指定的项目名
进入项目并利用tree命令输出项目结构
scrapy.cfg: 项目的配置文件。
TestSpider/: 项目的Python模块,将会从这里引用代码。
TestSpider/items.py: 项目的目标文件。
TestSpider/pipelines.py: 项目的管道文件。
TestSpider/settings.py: 项目的设置文件。
TestSpider/spiders/: 存储爬虫代码目录。
我们以爬取菜鸟教程为例,网址: http://www.runoob.com/
需要的数据为 教程名 图片url 简要描述 教程url
编辑items.py如下:
Item定义了一个结构化数据字段,类似于字典,用于保存爬取到的数据
import scrapy
class 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() # 教程链接
在项目目录中输入命令
命令:scrapy genspider spidername 'start_url'
spidername 为需要指定的爬虫名称
start_url为初始爬取地址
此时会在spiders目录中创建spidername.py文件,并添加必须的代码
import scrapy
class 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中的数据
scrapy crawl spidername -o spidername.(json|jsonl|csv|xml)
以json / json lines / csv / xml格式存储在当前路径下
存储的csv文件,默认按照ASCII码编码顺序排列
定义一个管道类,完成写入操作
>>>>>>>>
保存至文件,保存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为爬虫文件名
文件
数据库
图片
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。