目录
一:安装
二:快速入门
三:开始爬取
四:存储数据
优化导出数据方式
window环境通过命令行安装: pip install scrapy
在winodw下使用这个框架还要安装一个它依赖的包,不然运行的时候会报错: pip install pypiwin32
安装成功之后可以通过:scrapy 命令查看相关命令。
我们使用startproject命令创建一个新项目。: scrapy startproject first_start
用pycharm打开这个项目看下生成的目录。
项目创建好之后,我们开始创建一个爬虫。创建一个爬虫需要用到一个命令: genspider
进入我们项目的spiders目录下用命令行创建: scrapy genspider qiushibaike "qiushibaike.com"
qiushibaike ---爬虫的名字 qiushibaike.com---爬虫需要的域名
自动创建的内容:
开始之前先设置一些东西。
1)settings.py中设置:
我们解释下自动生成的py文件中的一些数据的作用。
我们运行爬虫也是要命令行,进入到spiders目录下面执行:scrapy crawl qiushibaike--自定义爬虫的名字
我们主要使用response对象来过滤xpath。我们看下
返回的是个SelectorList类型。它是可以遍历,并且可以继续使用xpath函数进行提取的。
但是使用命令行执行爬虫不是很方便,我们可以使用python文件来启动。在项目的根目录下创建一个新文件,在里面使用:
from scrapy import cmdline #传入我们的启动命令 cmdline.execute("scrapy crawl qiushibaike".split())后面我们可以直接运行这个文件就可以启动爬虫程序了。
我们看到页面内容:
可以根据class='recmd-right'来定位
我们来得到作者:
分析页面,可以知道,在上面我们得到div之后,在div下面的span标签内存着作者,所以通过如下方式获取。
def parse(self, response): # response是一个HtmlResponse对象,可以用它获取返回的内容response.text,使用xpath获取内容response.xpath("..") print("*************************") responseContent = response.xpath("//div[@class='recmd-right']") for i in responseContent: print(i.xpath(".//span[@class='recmd-name']/text()").get()) print("******************************")我们现在试着把爬取到的内容存储到json文件。scrapy中爬取和存储是分开两个模块处理。我们的爬取程序是在spiders下面,但是对爬取下来的数据处理是在pipelines中的。
首页我们需要把在spiders中把爬取的数据yield出去,然后在pipelines中接收处理。
spiders中:
注意我们这里使用yield,也可以把所有的数据都准备好之后直接return出来。
def parse(self, response): # response是一个HtmlResponse对象,可以用它获取返回的内容response.text,使用xpath获取内容response.xpath("..") print("*************************") responseContent = response.xpath("//div[@class='recmd-right']") for i in responseContent: author=i.xpath(".//span[@class='recmd-name']/text()").get() title=i.xpath(".//a[@class='recmd-content']/text()").get() #把数据转为字典 data={"author": author,"title":title} #把数据转给pipelines,需要使用 yield, 代表把数据转给底层框架,然后框架会转给pipelines.py文件中 yield datapipelines中:
# Define your item pipelines here # # Don't forget to add your pipeline to the ITEM_PIPELINES setting # See: https://docs.scrapy.org/en/latest/topics/item-pipeline.html # useful for handling different item types with a single interface from itemadapter import ItemAdapter import json class FirstProjectPipeline: #初始化函数,打开一个文件,也可以在open_spider方法中 def __init__(self): self.fp=open("data.json","w",encoding="utf-8") #爬虫程序启动的时候执行这个函数 def open_spider(self,spider): print('爬虫开始') #我们在spiders中yield 的数据 会传递给 item这个参数,然后执行process_item中的逻辑 def process_item(self, item, spider): #在spider中yield是个字典型数据 我们转成json dumps不需要文件参数,ensure_ascii关闭掉可以存储中文 item_json=json.dumps(item,ensure_ascii=False) self.fp.write(item_json+'\n') return item #这个爬虫程序执行完成之后执行的方法 def close_spider(self,spider): print('爬虫结束')但是要让pipelines生效配置文件中还要有个内容放开注释:
默认是注释掉的。
# Configure item pipelines # See https://docs.scrapy.org/en/latest/topics/item-pipeline.html ITEM_PIPELINES = { #key是类路径,value是优先级,越小优先级越高 'first_project.pipelines.FirstProjectPipeline': 300, }运行程序看到出来的json文件:
上面我们是在爬虫程序里返回是个字典型数据给pipelines的,但是在scrapy中有更专业的写法,就是用包装类。
首先我们要在items.py中定义包装数据的类,items.py中就是专门放这些包装类的。
item.py:
import scrapy class FirstProjectItem(scrapy.Item): # define the fields for your item here like: # name = scrapy.Field() author=scrapy.Field() title=scrapy.Field()在spiders中引入使用:
注意引入的方式,从我们的项目名下的item引入。
from first_project.items import FirstProjectItem def parse(self, response): # response是一个HtmlResponse对象,可以用它获取返回的内容response.text,使用xpath获取内容response.xpath("..") print("*************************") responseContent = response.xpath("//div[@class='recmd-right']") for i in responseContent: author=i.xpath(".//span[@class='recmd-name']/text()").get() title=i.xpath(".//a[@class='recmd-content']/text()").get() #把数据转为字典 # data={"author": author,"title":title} data=FirstProjectItem(author=author,title=title) #把数据转给pipelines,需要使用 yield, 代表把数据转给底层框架,然后框架会转给pipelines.py文件中 yield datapipelines中我们要稍微改动下,因为传入的是个对象,我们存入json文件的时候,转为字典。
def process_item(self, item, spider): #在spider中yield是个字典型数据 我们转成json dumps不需要文件参数,ensure_ascii关闭掉可以存储中文 item_json=json.dumps(dict(item),ensure_ascii=False) self.fp.write(item_json+'\n') return item这样就可以继续使用了。
上面我们使用Json来导出爬取的数据,还要转换为字典型,不太方便,其实scrapy中给我们提供的有导出器可以使用更方便数据导出。
pipelines中的代码改为如下内容:
# useful for handling different item types with a single interface from itemadapter import ItemAdapter #引入Json导出器 from scrapy.exporters import JsonItemExporter class FirstProjectPipeline: #初始化函数,打开一个文件,也可以在open_spider方法中 def __init__(self): #同样时打开一个文件,但是这里要以wb字节的形式打开,因为导出器是处理字节数据的而且不用指定编码格式 self.fp=open("data.json","wb") #传入上面定义的文件对象,禁用ascii码 使用utf-8编码 self.export=JsonItemExporter(self.fp,ensure_ascii=False,encoding='utf-8') #开启导出 self.export.start_exporting() #爬虫程序启动的时候执行这个函数 def open_spider(self,spider): print('爬虫开始') #我们在spiders中yield 的数据 会传递给 item这个参数,然后执行process_item中的逻辑 def process_item(self, item, spider): #爬虫哪里得到的item可以直接使用,不用转换为字典 self.export.export_item(item) return item #这个爬虫程序执行完成之后执行的方法 def close_spider(self,spider): # 完成导入之后关闭导出器,才会真正的写入文件中取,存入文件的内容为一个列表,列表里是一个个字典 self.export.finish_exporting() print('爬虫结束')内容:
这种方式是会把爬取到的内容都先在内存中存储一个列表中,列表中存储爬取的item,最后在写入文件中,如果爬取的内容很多,会很占内存。
还有一种导出方式,按行来导出,而不是占用内存最后再导出。
#引入Json导出器 from scrapy.exporters import JsonLinesItemExporter class FirstProjectPipeline: #初始化函数,打开一个文件,也可以在open_spider方法中 def __init__(self): #同样时打开一个文件,但是这里要以wb字节的形式打开,因为导出器是处理字节数据的而且不用指定编码格式 self.fp=open("data.json","wb") #传入上面定义的文件对象,禁用ascii码 使用utf-8编码 self.export=JsonLinesItemExporter(self.fp,ensure_ascii=False,encoding='utf-8') #爬虫程序启动的时候执行这个函数 def open_spider(self,spider): print('爬虫开始') #我们在spiders中yield 的数据 会传递给 item这个参数,然后执行process_item中的逻辑 def process_item(self, item, spider): #爬虫哪里得到的item可以直接使用,不用转换为字典 self.export.export_item(item) return item #这个爬虫程序执行完成之后执行的方法 def close_spider(self,spider): print('爬虫结束')导入内容:
一个字典占用一行,而不是一个列表了。数量大的时候可以使用这个方式,而且不用start,和finish了。