第四周:网络爬虫之框架
第一讲:Scrapy爬虫框架
1.安装
执行pip install scrapy命令。
安装后小测:执行scrapy -h
2.Scrapy爬虫框架结构
爬虫框架是实现爬虫功能的一个软件结构和功能组件集合。爬虫框架是一个半成品,能够帮助用户实现专业网络爬虫。
Scrapy爬虫包括5+2个结构,如图1所示。
图1
它包括三条主要的数据流路径如图中的箭头所示:
(1)从SPIDERS发送REQUESTS到ENGINE模块,然后到SCHEDULER,SCHEDULER负责对请求进行调度。
(2)SCHEDULER发送REQUESTS到ENGINE,再将REQUESTS传送到DOWNLOADER模块。然后DOWNLOADER返回相应通过ENGINE到SPIDERS。
(3)从SPIDERS获取到路径(2)的RESPONSE,处理之后发送ITEMS/REQUESTS到ENGINE,然后ITEMS传递给ITEM PIPELINES,REQUESTS传递给SCHEDULER。
这个框架的入口是SPIDERS,出口是ITEM PIPELINES。其他三个模块用户都不需要关心,用户需要编写的是SPIDERS和ITEM PIPELINES的配置。
3.Scrapy爬虫框架解析
(1)ENGINE:控制所有模块之间的数据流,根据条件触发事件,不需要用户修改。
(2)DOWNLOADER:根据请求下载网页,也不需要用户修改。
(3)SCHEDULER,对所有爬取请求进行调度管理,不需要用户修改。
(4)Downloader Middleware,设置目的是实施Engine、Scheduler和Downloader之间进行用户可配置的控制,可以修改、丢弃、新增请求或响应。
(5)Spider:解析Downloader返回的响应(Response),产生爬取项(scaped item)和额外的爬取请求(Request)。
(6)Item Pipelines:以流水线方式处理Spider产生的爬取项。它是由一组操作顺序组成,类似流水线, 操作是一个Item Pipeline类型。可能操作包括:清理、检验和查重爬取项中的HTML数据,将数据存储到数据库。
(7)Spider Middleware:目的是对请求和爬取项进行再处理,功能包括修改、丢弃、新增请求或爬取项,用户可以配置代码。
4.requests库和Scarpy爬虫比较
库名称 | 相同点 | 不同点 |
requests | 1.两者都可以进行页面请求和爬取。 2.两者可用性都好,文档丰富、入门简单。 3.两者都没有处理js、提交表单、应对验证码等功能(可扩展)。 | 页面级爬虫;功能库;并发性考虑不足,性能较差;重点在于页面下载;定制灵活;上手十分简单。 |
Scrapy | 网站级爬虫;框架;并发性好、性能较高;重点在于爬虫结构;一般定制灵活,深度定制困难;入门稍难。 |
5.Scrapy爬虫常用命令
Scrapy是为持续运行设计的专业爬虫框架,提供操作的是Scrapy命令行。它的格式如下:
scrapy <command>[options][args]
Scrapy常用命令如表1.1所示。
表1.1 Scrapy常用命令
命令 | 说明 | 格式 |
startproject | 创建一个新工程 | scrapy startproject <name> [dir] |
genspider | 创建一个爬虫 | scrapy genspider [options] <name><domain> |
settings | 获取爬虫配置信息 | scrapy setting [options] |
crawl | 运行一个爬虫 | scrapy crawl<spider> |
list | 列出工程中所有爬虫 | scrapy list |
shell | 启动URL调试命令行 | scrapy shell [url] |
第二讲:Scrapy爬虫基本使用
1.Scrapy爬虫的第一个实例
Scrapy爬虫的步骤:
(1)第一步:建立一个工程;
在命令行输入scrapy startproject python123demo
生成的工程目录包括以下内容:
python123demo/ 外层目录
scrapy.cfg 部署Scrapy爬虫的配置文件
python123demo/ Scrapy框架的用户自定义Python代码
__init__.py 初始化脚本
items.py Items代码模板(继承类)
middlewares.py Middlewares代码模板(继承类)
pipelines.py Pipelines代码模板(继承类)
settings.py 爬虫的配置文件
spiders/ Spiders代码模板目录(继承类)
__init__.py 初始文件,无需修改
__pycache__/ 缓存目录,无需修改
(2)第二步:在工程中产生一个Scrapy爬虫。
scrapy genspider demo python123.io
在demo.py文件中,parse()用于处理响应,解析内容形成字典,发现新的URL爬取请求。
(3)第三步:配置产生的spider爬虫
# -*- coding: utf-8 -*-import scrapyclass DemoSpider(scrapy.Spider): name = "demo" #allowed_domains = ["python123.io"] start_urls = ['https://python123.io/ws/demo.html'] def parse(self, response):#对返回页面进行解析并且进行操作的相关步骤 fname = response.url.split('/')[-1] with open(fname, 'wb') as f: f.write(response.body) self.log('Saved file %s.' % name)
(4)运行爬虫,获取网页。
scrapy crawl demo
2.yield关键字的使用
yield<—>生成器
生成器是一个不断产生值的函数。
包含yield语句的函数是一个生成器。
生成器每次产生一个值(yield语句),函数被冻结,被唤醒后再产生一个值。
实例:
def gen(n): for i in range(n): yield i**2for i in gen(5):print(i," ",end="")
生成器相比一次列出所有内容的优势:更节省存储空间;响应更迅速;使用更加灵活。
3.Scrapy爬虫的基本使用
Scrapy爬虫的使用步骤:
步骤1:创建一个工程和Spider模板
步骤2:编写Spider
步骤3:编写Item Pipeline
步骤4:优化配置策略
Scrapy爬虫的数据类型:
Request类:class scrapy.http.Request()
Request对象表示一个HTTP请求。由Spider生成,由Donwnloader执行。它包括6个属性或方法:
表2.1 Request类的属性或方法
属性或方法 | 说明 |
.url | Request对应的请求url地址 |
.method | 对应的请求方法,‘GET’’POST’等 |
.headers | 字典类型风格的请求头 |
.body | 请求内容主题,字符串类型 |
.meta | 用户添加的扩展信息,在Scrapy内部模板间传递信息使用 |
.copy() | 复制该请求 |
Response类:class scrapy.http.Response()
Response对象表示一个HTTP响应,由Downloader生成,Spider处理。
表2.2 Response类的属性或方法
属性或方法 | 说明 |
.url | Response对应的请求url地址 |
.status | HTTP状态码,默认是200 |
.headers | Response对应的头部信息 |
.body | Response对应的内容信息,字符串类型 |
.flags | 一组标记 |
.request | 产生Response类型对应的Request对象 |
.copy() | 复制该响应 |
Item类:class scrapy.item.Item()
Item对象表示一个从HTML页面中提取的信息内容。由Spider生成,由Item Pipeline处理。Item类似字典类型,可以按照字典类型操作。
Scrapy爬虫支持多种HTML信息提取方法,包括Beautiful Soup/lxml/re/XPath Selector/CSS Seletor等。
下面简单介绍一下CSS Selector。CSS Selector的基本使用格式如下:
<HTML>.css(‘a::attr(href)’).extract()
其中a是标签名称,href是标签属性,这样就能获得对应的标签信息。CSS Selector是由W3C组织维护并规范。
第三讲:实例4:股票数据Scrapy爬虫
1.实例介绍
技术路线:scrapy
目标:获取上交所和深交所所有股票的名称和交易信息。
输出:保存在文件中。
2.实例编写
(1)配置stocks.py文件:修改对返回页面的处理;修改对新增URL爬取请求的处理。
stocks.py代码
# -*- coding: utf-8 -*-import scrapyimport reclass StocksSpider(scrapy.Spider): name = "stocks" start_urls = ['https://quote.eastmoney.com/stocklist.html'] def parse(self, response):#对页面中所有的a链接进行提取,格式如下所示 for href in response.css('a::attr(href)').extract(): try: stock = re.findall(r"[s][hz]\d{6}", href)[0] url = 'https://gupiao.baidu.com/stock/' + stock + '.html'#上面是利用东方财富网中获取的股票代码在百度股票中获取其信息 yield scrapy.Request(url, callback=self.parse_stock) except: continue#如下在百度股票的单个页面中提取股票所需信息 def parse_stock(self, response): infoDict = {} stockInfo = response.css('.stock-bets') name = stockInfo.css('.bets-name').extract()[0] keyList = stockInfo.css('dt').extract() valueList = stockInfo.css('dd').extract() for i in range(len(keyList)): key = re.findall(r'>.*</dt>', keyList[i])[0][1:-5] try: val = re.findall(r'\d+\.?.*</dd>', valueList[i])[0][0:-5] except: val = '--' infoDict[key]=val infoDict.update( {'股票名称': re.findall('\s.*\(',name)[0].split()[0] + \ re.findall('\>.*\<', name)[0][1:-1]}) yield infoDict
(2)编写Pipelines,配置pipelines.py文件,定义对爬取项(Scraped Item)的处理类,配置ITEM_PIPELINES选项。
pipelines.py源代码:
# -*- coding: utf-8 -*-# Define your item pipelines here# Don't forget to add your pipeline to the ITEM_PIPELINES setting# See: https://doc.scrapy.org/en/latest/topics/item-pipeline.htmlclass BaidustocksPipeline(object): def process_item(self, item, spider): return item class BaidustocksInfoPipeline(object): def open_spider(self, spider): self.f = open('BaiduStockInfo.txt', 'w') def close_spider(self, spider): self.f.close() def process_item(self, item, spider):#对每一个item进行处理 try: line = str(dict(item)) + '\n' self.f.write(line) except: pass return item
setting.py中被修改的部分的代码:
# Configure item pipelines# See https://scrapy.readthedocs.org/en/latest/topics/item-pipeline.htmlITEM_PIPELINES = { 'BaiduStocks.pipelines.BaidustocksInfoPipeline': 300,}
3.实例优化
配置并发连接选项,在settings.py中,具体如下:
表3.1 settings.py文件
选项 | 说明 |
CONCURENT_REQUESTS | Downloader最大并发请求下载数量,默认32 |
CONCURENT_ITEMS | Item Pipeline最大并发ITEM处理数量,默认100 |
CONCURENT_REQUESTS_PER_DOMAIN | 每个目标域名最大的并发请求数量,默认为8 |
CONCURENT_REQUESTS_PER_IP | 每个目标IP最大的并发请求数量,默认0,非0有效 |