一、简介
Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架。它集成高性能异步下载,队列,分布式,解析,持久化等。
Scrapy 是基于twisted框架开发而来,twisted是一个流行的事件驱动的python网络框架。因此Scrapy使用了一种非阻塞(又名异步)的代码来实现并发。它是爬虫界最知名的框架。就好比web框架中的django。Scrapy之所以能实现异步,得益于twisted框架。twisted有事件队列,哪一个事件有活动,就会执行!
1. 安装
Linux:pip3 install scrapy
Windows:
a. pip3 install wheel
b. 下载twisted http://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted
c. shift右击进入下载目录,执行 pip3 install typed_ast-1.4.0-cp36-cp36m-win32.whl
d. pip3 install pywin32
e. pip3 install scrapy
2.工作过程:
- 用户编写爬虫主程序将需要下载的页面请求requests递交给引擎
- 引擎将请求转发给调度(调度实现了优先级、去重等策略)
- 调度从队列中取出一个请求,交给引擎转发给下载器(引擎和下载器中间有中间件,作用是对请求加工如:对requests添加代理、ua、cookie,response进行过滤等)
- 下载器取回页面后,交由引擎转发给爬虫主程序解析,这个时候解析函数将产生两类数据,一种是items、一种是requests(新请求),其中requests按上面步骤交给调度器;items交给数据管道(数据管道实现数据的最终处理)
3.scrapy基本命令行
(1)创建一个新的项目 scrapy startproject ProjectName (2).生成爬虫 scrapy genspider +SpiderName+website (3)运行(crawl) # -o output scrapy crawl +SpiderName scrapy crawl SpiderName -o file.json scrapy crawl SpiderName-o file.csv (4)check检查错误 scrapy check (5)list返回项目所有spider名称 scrapy list (6). view 存储、打开网页 scrapy view https://www.baidu.com (7). scrapy shell,进入终端 scrapy shell https://www.baidu.com (8). scrapy runspider scrapy runspider zufang_spider.py
官方使用文档:https://docs.scrapy.org/en/latest/
二、基础使用
以麦田租房信息爬取为例,网站http://bj.maitian.cn/zfall/PG1
1.创建项目
scrapy startproject houseinfo
生成项目结构:
scrapy.cfg 项目的主配置信息。(真正爬虫相关的配置信息在settings.py文件中)
items.py 设置数据存储模板,用于结构化数据,如:Django的Model
pipelines 数据持久化处理
settings.py 配置文件
spiders 爬虫目录
2.创建爬虫应用程序
cd houseinfo scrapy genspider maitian maitian.com
然后就可以在spiders目录下看到我们的爬虫主程序
3.编写爬虫文件
步骤2执行完毕后,会在项目的spiders中生成一个应用名的py爬虫文件,文件源码如下:
1 # -*- coding: utf-8 -*- 2 import scrapy 3 4 5 class MaitianSpider(scrapy.Spider): 6 name = ‘maitian‘ # 应用名称 7 allowed_domains = [‘maitian.com‘] #一般注释掉,允许爬取的域名(如果遇到非该域名的url则爬取不到数据) 8 start_urls = [‘http://maitian.com/‘] #起始爬取的url列表,该列表中存在的url,都会被parse进行请求的发送 9 10 #解析函数 11 def parse(self, response): 12 pass
我们可以在此基础上,根据需求进行编写
1 # -*- coding: utf-8 -*- 2 import scrapy 3 4 class MaitianSpider(scrapy.Spider): 5 name = ‘maitian‘ 6 start_urls = [‘http://bj.maitian.cn/zfall/PG100‘] 7 8 9 #解析函数 10 def parse(self, response): 11 12 li_list = response.xpath(‘//div[@class="list_wrap"]/ul/li‘) 13 results = [] 14 for li in li_list: 15 title = li.xpath(‘./div[2]/h1/a/text()‘).extract_first().strip() 16 price = li.xpath(‘./div[2]/div/ol/strong/span/text()‘).extract_first().strip() 17 square = li.xpath(‘./div[2]/p[1]/span[1]/text()‘).extract_first().replace(‘㎡‘,‘‘) # 将面积的单位去掉 18 area = li.xpath(‘./div[2]/p[2]/span/text()[2]‘).extract_first().strip().split(‘\xa0‘)[0] # 以空格分隔 19 adress = li.xpath(‘./div[2]/p[2]/span/text()[2]‘).extract_first().strip().split(‘\xa0‘)[2] 20 21 dict = { 22 "标题":title, 23 "月租金":price, 24 "面积":square, 25 "区域":area, 26 "地址":adress 27 } 28 results.append(dict) 29 30 print(title,price,square,area,adress) 31 return results
须知:
- xpath为scrapy中的解析方式
- xpath函数返回的为列表,列表中存放的数据为Selector类型数据。解析到的内容被封装在Selector对象中,需要调用extract()函数将解析的内容从Selector中取出。
- 如果可以保证xpath返回的列表中只有一个列表元素,则可以使用extract_first(), 否则必须使用extract()
两者等同,都是将列表中的内容提取出来
title = li.xpath(‘./div[2]/h1/a/text()‘).extract_first().strip()
title = li.xpath(‘./div[2]/h1/a/text()‘)[0].extract().strip()
4. 设置修改settings.py配置文件相关配置:
1 #伪装请求载体身份 2 USER_AGENT = ‘Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36‘ 3 4 #可以忽略或者不遵守robots协议 5 ROBOTSTXT_OBEY = False
5.执行爬虫程序:scrapy crawl maitain
三、数据持久化存储
- 基于终端指令的持久化存储
- 基于管道的持久化存储
1. 基于终端指令的持久化存储
将parse方法的返回值持久化存储到本地的文本中(此方法parse必须有返回值,也就是return后的内容)
执行输出指定格式进行存储:将爬取到的数据写入不同格式的文件中进行存储,windows终端不能使用txt格式
- scrapy crawl 爬虫名称 -o xxx.json
- scrapy crawl 爬虫名称 -o xxx.xml
- scrapy crawl 爬虫名称 -o xxx.csv
以麦田为例,spider中的代码不变,将返回值写到qiubai.csv中。本地没有,就会自己创建一个。本地有就会追加
scrapy crawl maitian -o maitian.csv
就会在项目目录下看到,生成的文件
查看文件内容
2.基于管道的持久化存储
scrapy框架中已经为我们专门集成好了高效、便捷的持久化操作功能,我们直接使用即可。要想使用scrapy的持久化操作功能,我们首先来认识如下两个文件:
- items.py:数据结构模板文件。定义数据属性。
- pipelines.py:管道文件。接收数据(items),进行持久化操作。
持久化流程:
① 爬虫文件爬取到数据解析后,需要将数据封装到items对象中。
② 使用yield关键字将items对象提交给pipelines管道,进行持久化操作。
③ 在管道文件中的process_item方法中接收爬虫文件提交过来的item对象,然后编写持久化存储的代码,将item对象中存储的数据进行持久化存储(在管道的process_item方法中执行io操作,进行持久化存储)
④ settings.py配置文件中开启管道
2.1保存到本地的持久化存储
爬虫文件:maitian.py
1 import scrapy 2 from houseinfo.items import HouseinfoItem # 将item导入 3 4 class MaitianSpider(scrapy.Spider): 5 name = ‘maitian‘ 6 start_urls = [‘http://bj.maitian.cn/zfall/PG100‘] 7 8 #解析函数 9 def parse(self, response): 10 11 li_list = response.xpath(‘//div[@class="list_wrap"]/ul/li‘) 12 13 for li in li_list: 14 item = HouseinfoItem( 15 title = li.xpath(‘./div[2]/h1/a/text()‘).extract_first().strip(), 16 price = li.xpath(‘./div[2]/div/ol/strong/span/text()‘).extract_first().strip(), 17 square = li.xpath(‘./div[2]/p[1]/span[1]/text()‘).extract_first().replace(‘㎡‘,‘‘), 18 area = li.xpath(‘./div[2]/p[2]/span/text()[2]‘).extract_first().strip().split(‘\xa0‘)[0], 19 adress = li.xpath(‘./div[2]/p[2]/span/text()[2]‘).extract_first().strip().split(‘\xa0‘)[2] 20 ) 21 22 yield item # 提交给管道,然后管道定义存储方式
items文件:items.py
1 import scrapy 2 3 class HouseinfoItem(scrapy.Item): 4 title = scrapy.Field() #存储标题,里面可以存储任意类型的数据 5 price = scrapy.Field() 6 square = scrapy.Field() 7 area = scrapy.Field() 8 adress = scrapy.Field()
管道文件:pipelines.py
1 class HouseinfoPipeline(object): 2 def __init__(self): 3 self.file = None 4 5 #开始爬虫时,执行一次 6 def open_spider(self,spider): 7 self.file = open(‘maitian.csv‘,‘a‘,encoding=‘utf-8‘) # 选用了追加模式 8 self.file.write(",".join(["标题","月租金","面积","区域","地址","\n"])) 9 print("开始爬虫") 10 11 # 因为该方法会被执行调用多次,所以文件的开启和关闭操作写在了另外两个只会各自执行一次的方法中。 12 def process_item(self, item, spider): 13 content = [item["title"], item["price"], item["square"], item["area"], item["adress"], "\n"] 14 self.file.write(",".join(content)) 15 return item 16 17 # 结束爬虫时,执行一次 18 def close_spider(self,spider): 19 self.file.close() 20 print("结束爬虫")
配置文件:settings.py
1 #伪装请求载体身份 2 USER_AGENT = ‘Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36‘ 3 4 #可以忽略或者不遵守robots协议 5 ROBOTSTXT_OBEY = False 6 7 #开启管道 8 ITEM_PIPELINES = { 9 ‘houseinfo.pipelines.HouseinfoPipeline‘: 300, #数值300表示为优先级,值越小优先级越高 10 }
未完待续!
原文地址:https://www.cnblogs.com/Summer-skr--blog/p/11477117.html