scrapy 库复习
scrapy的概念:Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架
scrapy框架的运行流程以及数据传递过程:
- 爬虫中起始的url构造成request对象–>爬虫中间件–>引擎–>调度器
- 调度器把request–>引擎–>下载中间件—>下载器
- 下载器发送请求,获取response响应---->下载中间件---->引擎—>爬虫中间件—>爬虫
- 爬虫提取url地址,组装成request对象---->爬虫中间件—>引擎—>调度器,重复步骤2
- 爬虫提取数据—>引擎—>管道处理和保存数据
创建项目和爬虫
scrapy startproject <项目名称>
scrapy genspider <爬虫名字> <允许爬取的域名>
网上找的简单实例
import scrapyclass ItcastSpider(scrapy.Spider):# 爬虫名字name = 'itcast'# 允许爬取的范围allowed_domains = ['itcast.cn']# 开始爬取的url地址start_urls = ['http://www.itcast.cn/channel/teacher.shtml']# 数据提取的方法,接受下载中间件传过来的responsedef parse(self, response):# scrapy的response对象可以直接进行xpathnames = response.xpath('//div[@class="tea_con"]//li/div/h3/text()')print(names)# 获取具体数据文本的方式如下# 分组li_list = response.xpath('//div[@class="tea_con"]//li')for li in li_list:# 创建一个数据字典item = {}# 利用scrapy封装好的xpath选择器定位元素,并通过extract()或extract_first()来获取结果item['name'] = li.xpath('.//h3/text()').extract_first() # 老师的名字item['level'] = li.xpath('.//h4/text()').extract_first() # 老师的级别item['text'] = li.xpath('.//p/text()').extract_first() # 老师的介绍print(item)
运行方式,在文件所在目录内运行 scrapy crawl <爬虫名>
注意:
- scrapy.Spider爬虫类中必须有名为parse的解析
- 如果网站结构层次比较复杂,也可以自定义其他解析函数
- 在解析函数中提取的url地址如果要发送请求,则必须属于allowed_domains范围内,但是start_urls中的url地址不受这个限制,我们会在后续的课程中学习如何在解析函数中构造发送请求
- 启动爬虫的时候注意启动的位置,是在项目路径下启动
- parse()函数中使用yield返回数据,注意:解析函数中的yield能够传递的对象只能是:BaseItem, Request, dict, None
解析并获取scrapy爬虫中的数据: 利用xpath规则字符串进行定位和提取
- response.xpath方法的返回结果是一个类似list的类型,其中包含的是selector对象,操作和列表一样,但是有一些额外的方法
- 额外方法extract():返回一个包含有字符串的列表
- 额外方法extract_first():返回列表中的第一个字符串,列表为空没有返回None
利用管道pipeline来处理(保存)数据
在pipelines.py文件中定义对数据的操作
- 定义一个管道类
- 重写管道类的process_item方法
- process_item方法处理完item之后必须返回给引擎
import json
class ItcastPipeline():# 爬虫文件中提取数据的方法每yield一次item,就会运行一次# 该方法为固定名称函数def process_item(self, item, spider):print(item)return item
在settings.py配置启用管道
ITEM_PIPELINES = {'myspider.pipelines.ItcastPipeline': 400
}
配置项中键为使用的管道类,管道类使用.进行分割,第一个为项目目录,第二个为文件,第三个为定义的管道类。
配置项中值为管道的使用顺序,设置的数值约小越优先执行,该值一般设置为1000以内。
scrapy 构造并发送请求
数据建模
通常在做项目的过程中,在 items.py 中进行数据建模
1、为什么建模
- 定义item即提前规划好哪些字段需要抓,防止手误,因为定义好之后,在运行过程中,系统会自动检查
- 配合注释一起可以清晰的知道要抓取哪些字段,没有定义的字段不能抓取,在目标字段少的时候可以使用字典代替
- 使用scrapy的一些特定组件需要Item做支持,如scrapy的ImagesPipeline管道类,百度搜索了解更多
2、如何建模
在 item.py 文件中定义要提取的字段:
class MyspiderItem(scrapy.Item):name = scrapy.Field() #名字title = scrapy.Field() #职称desc = scrapy.Field() #介绍
3、如何使用建好的模板
模板类定义以后需要在爬虫中导入并且实例化,之后的使用方法和使用字典相同
from mySpider.mySpider.items import MyspiderItem #导入itemclass ItcastSpider(scrapy.Spider):……# 数据提取的方法,接受下载中间件传过来的responsedef parse(self, response):……for li in li_list:# 创建一个数据字典item = MyspiderItem()# 利用scrapy封装好的xpath选择器定位元素,并通过extract()或extract_first()来获取结果item['name'] = li.xpath('.//h3/text()').extract_first() # 老师的名字item['level'] = li.xpath('.//h4/text()').extract_first() # 老师的级别item['text'] = li.xpath('.//p/text()').extract_first() # 老师的介绍yield item
注意:
- from myspider.items import MyspiderItem这一行代码中 注意item的正确导入路径,忽略pycharm标记的错误
- python中的导入路径要诀:从哪里开始运行,就从哪里开始导入
翻页请求
requests模块是如何实现翻页请求的:
- 找到下一页的URL地址
- 调用requests.get(url)
scrapy实现翻页的思路:
- 找到下一页的url地址
- 构造url地址的请求对象,传递给引擎
构造 Request 对象,并发送请求
1、 实现方法
- 确定url地址
- 构造请求,scrapy.Request(url,callback)
- callback:指定解析函数名称,表示该请求返回的响应使用哪一个函数进行解析
- 把请求交给引擎:yield scrapy.Request(url,callback)
2、招聘爬虫实例
通过网易招聘页面爬取招聘信息,并实现翻页请求
步骤:
1、获取首页的数据
2、寻找下一页的地址,进行翻页,获取数据
spider 文件
import scrapyclass mySpider(scrapy.Spider):name = "joblistspider"allowed_domains = ["gz.gov.cn"]start_urls = ["https://www.gz.gov.cn/zwgk/zcjd/zcjd/index.html"]base_url = "https://www.gz.gov.cn/zwgk/zcjd/zcjd/index_"offset = 1end = '.html'def parse(self, response):#提取下一页的hrefnex_url = response.xpath("//ul[@class='news_list']/li")for url in nex_url:item = {}item['name'] = url.xpath("./a/text()").extract_first()item['time'] = url.xpath("./span/text()").extract_first()item['link'] = url.xpath("./a/@href").extract_first()yield itemif self.offset <=40:self.offset += 1url = self.base_url+str(self.offset)+self.endyield scrapy.Request(url, callback=self.parse)
pipelines.py
import jsonclass JoblistspiderPipeline:def __init__(self):#self.f = open('joblist.json','w')self.f = open('joblist.csv','w',encoding='utf-8')def process_item(self, item, spider):content = json.dumps(dict(item), ensure_ascii=False) + ',\n'self.f.write(content)return itemdef close_spider(self, spider):self.f.close()
setting.py
ITEM_PIPELINES = {'Gzgov.pipelines.GzgovPipeline': 300,
}ROBOTSTXT_OBEY = False
scrapy.Request的更多参数
scrapy.Request(url[,callback,method="GET",headers,body,cookies,meta,dont_filter=False])
参数解释:
- 中括号里的参数为可选参数
- callback:表示当前的url的响应交给哪个函数去处理
- meta:实现数据在不同的解析函数中传递,meta默认带有部分数据,比如下载延迟,请求深度等
- dont_filter:默认为False,会过滤请求的url地址,即请求过的url地址不会继续被请求,对需要重复请求的url地址可以把它设置为Ture,比如贴吧的翻页请求,页面的数据总是在变化;start_urls中的地址会被反复请求,否则程序不会启动
- method:指定POST或GET请求
- headers:接收一个字典,其中不包括cookies
- cookies:接收一个字典,专门放置cookies
- body:接收json字符串,为POST的数据,发送payload_post请求时使用(在下一章节中会介绍post请求)
meta 参数使用
meta可以实现数据在不同的解析函数中的传递
……yield scrapy.Request(url, callback=self.parse,meta={"item":item})
特别注意
meta参数是一个字典
meta字典中有一个固定的键proxy,表示代理ip