scrapy框架
具有高性能异步下载,队列,分布式,解析,持久化等具有很强通用性的项目模板
安装
a. pip3 install wheel
b. 下载twisted http://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted
c. 进入下载目录,执行 pip3 install Twisted-17.1.0-cp36-cp36m-win_amd64.whl
d. pip3 install pywin32
e. pip3 install scrapy
基本使用
1,创建项目 scrapy startproject 项目名称
2,创建爬虫应用程序
cd project_name(进入项目目录)
scrapy genspider 应用名称 爬取网页的起始url (例如:scrapy genspider qiubai www.qiushibaike.com,这个也可以先随便写一个,然后再在代码中改过来)
3.编写爬虫文件:在步骤2执行完毕后,会在项目的spiders中生成一个应用名的py爬虫文件,文件源码如下:
import scrapy
class QiubaiSpider(scrapy.Spider):
name = 'qiubai' #应用名称
#允许爬取的域名(如果遇到非该域名的url则爬取不到数据)
allowed_domains = ['https://www.qiushibaike.com/']
#起始爬取的url
start_urls = ['https://www.qiushibaike.com/']
#访问起始URL并获取结果后的回调函数,该函数的response参数就是向起始的url发送请求后,获取的响应对象.该函数返回值必须为可迭代对象或者NUll
def parse(self, response):
print(response.text) #获取字符串类型的响应内容
print(response.body)#获取字节类型的相应内容
4.设置修改settings.py配置文件相关配置:
修改内容及其结果如下:
19行: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' #伪装请求载体身份
22行:ROBOTSTXT_OBEY = False #可以忽略或者不遵守robots协议
5.执行爬虫程序:scrapy crawl 应用名称,注意这里不是项目名称,而是spiders文件夹下爬虫应用程序的名称 (crawl就行爬行的意思)
scrapy crawl 爬虫名称 --nolog:该种执行形式不会显示执行的日志信息,报错后也不会显示报错信息
项目结构:
project_name/
scrapy.cfg:
project_name/
__init__.py
items.py
pipelines.py
settings.py
spiders/
__init__.py
scrapy.cfg 项目的主配置信息。(真正爬虫相关的配置信息在settings.py文件中)
items.py 设置数据存储模板,用于结构化数据,如:Django的Model
pipelines 数据持久化处理
settings.py 配置文件,如:递归的层数、并发数,延迟下载等
spiders 爬虫目录,如:创建文件,编写爬虫解析规则
scrapy框架的持久化存储
基于终端指令的持久化存储
基于管道的持久化存储
基于终端指令的持久化存储
1,保证爬虫文件的parse方法中有可迭代类型对象(通常为列表or字典)的返回,该返回值可以通过终端指令的形式写入指定格式的文件中进行持久化操作
2,执行输出指定格式进行存储:将爬取到的数据写入不同格式的文件中进行存储
scrapy crawl 爬虫名称 -o xxx.json
scrapy crawl 爬虫名称 -o xxx.xml
scrapy crawl 爬虫名称 -o xxx.csv
基于管道的持久化存储(集成好了高效、便捷的持久化操作功能,处理好了并发,比我们直接在parse方法里进行IO操作存储要快)
在两个文件中
items.py:数据结构模板文件。定义数据属性。 使用Field()字段就行了
pipelines.py:管道文件。接收数据(items),进行持久化操作。
流程:
1.爬虫文件爬取到数据后,需要将数据封装到items对象中。
2.使用yield关键字将items对象提交给pipelines管道进行持久化操作。
3.在管道文件中的process_item方法中接收爬虫文件提交过来的item对象,然后编写持久化存储的代码将item对象中存储的数据进行持久化存储
4.settings.py配置文件中开启管道
示例:
将糗事百科首页中的段子和作者数据爬取下来,然后进行持久化存储
import scrapy
from secondblood.items import SecondbloodItem
class QiubaidemoSpider(scrapy.Spider):
name = 'qiubaiDemo'
allowed_domains = ['www.qiushibaike.com']
start_urls = ['http://www.qiushibaike.com/']
def parse(self, response):
odiv = response.xpath('//div[@id="content-left"]/div')
for div in odiv:
# xpath函数返回的为列表,列表中存放的数据为Selector类型的数据。我们解析到的内容被封装在了Selector对象中,需要调用extract()函数将解析的内容从Selecor中取出。
author = div.xpath('.//div[@class="author clearfix"]//h2/text()').extract_first()
author = author.strip('
')#过滤空行
content = div.xpath('.//div[@class="content"]/span/text()').extract_first()
content = content.strip('
')#过滤空行
#将解析到的数据封装至items对象中
item = SecondbloodItem()
item['author'] = author
item['content'] = content
yield item#提交item到管道文件(pipelines.py)
# items文件:items.py
import scrapy
class SecondbloodItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
author = scrapy.Field() #存储作者
content = scrapy.Field() #存储段子内容
# 管道文件:pipelines.py
class SecondbloodPipeline(object):
#构造方法
def __init__(self):
self.fp = None #定义一个文件描述符属性
#下列都是在重写父类的方法:
#开始爬虫时,执行一次
def open_spider(self,spider):
print('爬虫开始')
self.fp = open('./data.txt', 'w')
#因为该方法会被执行调用多次,所以文件的开启和关闭操作写在了另外两个只会各自执行一次的方法中。
def process_item(self, item, spider):
#将爬虫程序提交的item进行持久化存储
self.fp.write(item['author'] + ':' + item['content'] + '
')
return item
#结束爬虫时,执行一次
def close_spider(self,spider):
self.fp.close()
print('爬虫结束')
# 配置文件:settings.py
#开启管道
ITEM_PIPELINES = {
'secondblood.pipelines.SecondbloodPipeline': 300, #300表示为优先级,值越小优先级越高
}
scrapy递归解析
递归爬取多个页面
# 需求:爬取boss直聘的python爬虫岗位的url
# spiders目录下的项目文件
import scrapy
from bossPro.items import BossproItem
class BossSpider(scrapy.Spider):
name = 'boss'
#allowed_domains = ['www.xxx.com']
url = 'https://www.zhipin.com/c101010100/?query=python%E7%88%AC%E8%99%AB&page='
pageNum = 1
start_urls = ['https://www.zhipin.com/c101010100/?query=python%E7%88%AC%E8%99%AB&page=1']
def parse(self, response):
li_list = response.xpath('//div[@class="job-list"]/ul/li')
for li in li_list:
job_name = li.xpath('./div/div[1]/h3/a/div[1]/text()').extract_first()
salary = li.xpath('./div/div[1]/h3/a/span/text()').extract_first()
item = BossproItem()
item['job_name'] = job_name
item['salary'] = salary
yield item # for 循环中的yield即相当于yield from 把列表中的内容迭代抛出
#通过循环的形式将其他页码进行请求操作
if self.pageNum <= 3:
self.pageNum += 1 #因为第一页已经请求,现在从第二页开始进行请求
new_url = self.url + str(self.pageNum)
#参数2:回调函数,作用就是对请求到的页面数据进行解析操作
yield scrapy.Request(url=new_url,callback=self.parse)
#yield的使用场景:1.向管道提交item 2.手动请求发送
# items.py文件
import scrapy
class BossproItem(scrapy.Item):
job_name = scrapy.Field()
salary = scrapy.Field()
# pipelines.py文件
这里我们将数据分别存储在两个文件中job.txt 和 job.csv
#将数据存储到txt文件中
class BossproPipeline(object):
#只会在爬虫开始的时候被执行一次
fp = None
def open_spider(self,spider):
self.fp = open('./job.txt','w',encoding='utf-8')
print("开始爬虫")
#该方法只可以处理item类型的对象。爬虫文件每向管道提交一次item,则该方法就会被调用一次
def process_item(self, item, spider):
#取出item对象中存储的数据
self.fp.write(item['job_name']+":"+item['salary']+'
')
return item
def close_spider(self,spider):
self.fp.close()
print('爬虫结束')
#将数据存储到csv文件中
class CsvPipeLine(object):
# 只会在爬虫开始的时候被执行一次
fp = None
def open_spider(self, spider):
self.fp = open('./job.csv','w',encoding='utf-8')
print("开始爬虫1")
# 该方法只可以处理item类型的对象。爬虫文件每向管道提交一次item,则该方法就会被调用一次
def process_item(self, item, spider):
# 取出item对象中存储的数据
self.fp.write(item['job_name']+":"+item['salary']+'
')
return item
def close_spider(self, spider):
self.fp.close()
print('爬虫结束1')
# settings中更改配置
USER_AGENT = 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36'
ROBOTSTXT_OBEY = False
ITEM_PIPELINES = {
'bossPro.pipelines.BossproPipeline': 300,
'bossPro.pipelines.CsvPipeLine': 301, # 数字越小,优先级越高,所以这里BossproPipeline类先执行,先接收parse抛出的一个 item,
# 存储后return item,CsvPipeLine类接收这个item,然后存储,存储后返回,最后CsvPipeLine类接收完后结束,然后BossproPipeline类结束,可以pipelines中的两个类打印文件进行验证
}