scrapy库
scrapy库的安装
1,使用pip install scrapy安装,但是因为来源于外网,网络不稳定,所以很难安装
2,使用anaconda安装
(1)安装anaconda,按照这两个博客① ②就可以,注意:添加环境变量的时候不需要在目录名后面加上\
(2)把anaconda连接到IDE上(我用的是pycharm),直接在interpreter里面勾选anaconda就好了
(3)win开始位置打开anaconda navigator,更改安装来源,换成国内镜像地址,安装scrapy包,安装指导在此
(4)在pycharm中导入看一看能不能用,没有报错,应该是ok了
爬虫框架
-
爬虫框架是实现爬虫功能的一个软件结构和功能组件集合
-
爬虫框架是一个半成品,能够帮助用户实现专业网络爬虫
-
spiders是入口,item pipelines是出口,engine/downloader和scheduler是已有的功能实现,用户不需要自己编写;用户需要自己编写spiders和item pipelines模块。由于用户不需要自己编写完整的程序,而只是对已有的框架进行局部调整,所以我们也把这种编写方式称为配置
-
Engine,整个框架的核心,它控制所有模块之间的数据流,根据条件触发事件
-
Downloader模块根据请求下载网页,不需要用户修改,功能单一
-
Scheduler模块对所有的爬取请求进行调度管理,确定先后顺序
-
在Engine和Downloader之间增加一个Downloader Middleware,实施Engine,Scheduler和Downloader之间用户可配置的控制,因为如果三个模块都是自动运行的,那么就没用户什么事了,功能是修改、丢弃、新增请求或者响应
-
Spider模块解析Doenloader返回的响应(response),产生爬取项(scraped item)并产生额外的爬取请求(request),用户主要编写的就是这个模块
-
item pipelines以流水线的方式处理spider模块产生的爬取项,它由一组操作顺序组成,类似于流水线,每个操作是一个item pipeline类型,可能的操作包括清理、检验和查重爬取项中的HTML数据、将数据储存到数据库,完全需要由用户配置
-
在spider和engine之间有一个中间键spider middlewire,它的目的是对请求和爬取项进行再处理,功能包括修改、丢弃、新增请求或爬取项,用户可以编写配置代码
-
requests库和scrapy框架的比较
- 相同点
- 两者都可以进行页面请求和爬取,是python爬虫的两个重要技术路线
- 两者可用性都好,文档丰富,入门简单
- 两者都没有处理js、提交表单、应对验证码等功能,需要加入其它的库
- 不同点
- r是页面级爬虫;s是网站级爬虫
- r是功能库,主要由函数构成;s是一个框架,重点不在函数
- r并发性考虑不足,性能较差;s并发性好,性能较高
- r重点在于页面下载;s重点在于爬虫结构
- r定制灵活;s一般定制灵活,深度定制困难
- r上手十分简单;s入门稍难
- 库的选取
- 非常小的需求,使用r库
- 不太小的需求,使用s库,即反复爬取、积累信息类
- 如果需要定制很高的需求(不考虑规模),则需要自己搭建框架,使用r库
- 相同点
srcapy库的常用命令
cmd中输入 scrapy -h
打开scrapy命令行,它通过命令行操作而不是图形界面
scrapy命令行格式:
>scrapy<command>[options][args]
具体命令在command中,常用命令包括6个:
命令 | 说明 | 格式 |
---|---|---|
startproject | 创建一个新工程 | scrapy startproject<name>[dir] |
genspider | 创建一个爬虫 | scrapy genspider[options]<name><domain> |
settings | 获取爬虫配置信息 | scrapy settings[options] |
crawl | 运行一个爬虫 | scrapy crawl<spider> |
list | 列出工程中所有爬虫 | scrapy list |
shell | 启动URL调试命令行 | scrapy shell[url] |
scrapy实例
演示页面的地址:http://python123.io/ws/demo.html
cmd中cd到指定目录,然后scrapy startproject python123创建一个scrapy文件
生成的工程目录
- python123 -->外层目录
- scrapy.cfg scrapy的配置文件,就是把爬虫放在服务器上并在服务器上配置好相关的操作接口,对于这个实例,不需要配置
- python123 scrapy框架的用户自定义python代码
- _init_.py初始化脚本,不需要用户编写
- items.py Items代码模版,需要继承scrapy提供的Item类,一般不需要用户编写
- middlewares.py Middlewares代码模版,需要继承类
- pipelines.py,pipelilnes代码模版(继承类)
- settings.py scrapy爬虫的配置文件
- spiders,spiders代码模块
- _init_.py 初始文件,无须修改
- _pycache_/ 缓存目录,无需修改
生成一个爬虫
cmd到先前目录中,使用scrapy genspider X python123.io,生成一个叫做X的爬虫,然后会在spiders的目录下生成一个spiders.py,实际上也可以手工生成
- 这个DemoSpider是继承scrapy.Spider的子类
- name是爬虫的名字
- allowed_domains是域名,指定爬虫只能爬取这个域名以下的相关链接
- start_urls以列表形式包含一个或多个url,就是scrapy框架所要爬取页面的初始页面
- parse是解析页面的空的方法,用于处理响应,解析内容形成字典,发现其中新的URL爬取请求
配置产生的spiders爬虫
就是编写demo.py
- allowed_domains不需要,可以注释掉
- 修改start_urls,修改为我们需要访问的http://python123.io/ws/demo.html
- 更改爬取方法的具体功能,爬取方法有2个参数一个是self,是面向对象类所属关系的标记,还有一个是response,相当于从网络中返回内容所存储的或对应的对象,这里我们要把response中内容写到一个html文件中,首先定义这个文件的名字
运行爬虫,获取文件
cmd中使用crawl命令执行,存储的文件在demo.html中
这是一个简化版的代码
# -*- coding: utf-8 -*-
import scrapy
class DemoSpider(scrapy.Spider):
name = 'demo'
# allowed_domains = ['python123.io']
start_urls = ['http://python123.io/ws/demo.html']
def parse(self, response):
#从响应的url中提取文件名字,作为保存问本地的文件名
fname = response.url.split('/')[-1]
#将返回的内容保存为文件
with open(fname,'wb') as f:
f.write(response.body)
self.log('Saved file %s.'% fname) #在self中记录日志
完整版的代码:
import scrapy
class DemoSpider(scrapy.Spider):
name = 'demo'
def start_requests(self):
urls =[
'http://python123.io/ws/demo.html'
]
for url in urls:
yield scrapy.Requests(url = url,calssback = self.parse)
def parse(self,response):
fname = response.url.split('/')[-1]
with open(fname,'wb') as f:
f.write(response.body)
self.log('Saved file %s.'%fname)
yield关键字的使用
生成器:是一个不断产生值的函数,包含yield语句的函数就是一个生成器,生成器每次产生一个值(yield语句),函数被冻结,被唤醒后再产生一个值,而生成器唤醒时,它所使用的局部变量的值与之前执行所使用的值是一致的,也就是说一个函数执行到某一个位置,产生了一个值,然后它被冻结,再次被唤醒的时候继续从这个位置去执行,每次执行的时候都产生一个数据,这样这个函数不停执行就产生了源源不断的数据,这样的函数就叫生成器
栗子:
def gen(n):
for i in range(n):
yield i**2 #这一行产生的值会被返回
for i in gen(5):
print(i," ",end = "")
生成器相比于普通写法(一次列出所有内容)的优势:
更节省存储空间;响应更迅速;使用更灵活
scrapy爬虫的基本使用
-
创建一个工程和Spider模版
-
编写spider模版
-
编写Item pipeline
-
优化策略配置
-
scapy爬虫的数据类型
-
Request类,代表向网络上提交请求的内容,request对象是一个http请求,它由spider生成,并由downloader执行
属性或方法 说明 .url Request对应的请求URL地址 .method 对应的请求方法,‘GET’'POST’等等 .headers 字典类型风格的请求头 .body 请求内容主体,字符串类型 .meta 用户添加的扩展信息,在scrapy内部模板间传递信息使用 .copy() 复制该请求 -
Response类,表示从网络中爬取内容的封装类,由downloader生成,由spider处理
属性或方法 说明 .url Response对应的URL地址 .status HTTP状态码,默认是200 .headers Response对应的头部信息 .body Response对应的内容信息,字符串类型 .flags 一组标记 .request 产生Response类型对应的Request对象 .copy() 复制该响应 -
Item类,由spider产生的信息封装而来的类,表示从HTML页面中提取的信息内容,由spider生成,由Itempipeline处理,item类似字典类型,可以按照字典类型操作
-
-
scrapy爬虫提取信息的方法
- scrapy爬虫支持多种HTML信息提取方法
- Beautiful Soup
- lxml
- re
- XPath Selector
- CSS Selector
- CSS Selector的基本使用
- 使用格式:<HTML>.css(‘a::attr(href)’).extract(),其中a是标签名称,attr(href)是标签属性,这样可以获得对应的标签信息
- CSS Selecter由W3C组织维护并规范
- scrapy爬虫支持多种HTML信息提取方法
股票数据scrapy实例
功能描述:
技术路线;scrapy
目标:获取上交所和深交所所有股票的名称和交易信息
输出:保存到文件中
数据网站:
获取股票列表用东方财富网
获取个股信息使用百度股票和单个股票
步骤:
1,建立工程和spider模版
2,编写Spider,包括配置stocks.py文件,修改对返回页面的处理,修改对(可能)新增URL爬取请求的处理
3,编写ITEM Pipelines
4,在setting.py中修改ITEM_PIPELINES,将自己定义的BaidustocksInfoPipeline写入配置文件中
5,crawl执行命令
stocks.py文件
# -*- coding: utf-8 -*-
import scrapy
import re
class StocksSpider(scrapy.Spider):
name = 'stocks'
# allowed_domains = ['baidu.com']
start_urls = ['http://quote.eastmoney.com/stock_list.html']
def parse(self, response):
#对页面的a标签进行提取
for href in response.css('a::attr(href)').extract():
try:
#获取了单一股票的代码
stock = re.findall(r"\d{6}",herf)[0]
#生成百度个股的对应链接
url = 'https://gupiao.baidu.com/stock/' + stock + '.html'
#将这个url重新提交给scrapy框架,callback给出了对这个页面的处理函数,定义了一个新的处理函数parse_stock()
yield scrapy.Request(url,callback = self.parse_stock)
except:
continue
def parse_stock(selfself,response):
infoDict= {} #因为要提交给itempipeline,所以要先生成一个空的字典
stockInfo = response.css('.stock-bets')#找到数据区域
name = stockInfo.css('.bets-name').extract() #拿到股票的名字
keyList = stockInfo.css('dt').extract()
valueList = stockInfo.css('dd').extract()
#将提取的信息保存在字典中
for i in range(len(keyList)):
key = re.findall(r'>.*</d>',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
pipeline.py文件
# -*- coding: utf-8 -*-
# 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
class BaidustocksPipeline(object):
def process_item(self, item, spider): #打开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
实例优化,提高速度
配置并发联结选项
settting.py
选项 | 说明 |
---|---|
CONCURRENT_REQUESTS | Downloader最大并发请求下载数量。默认32 |
CONCURRENT_ITEMS | Item Pipeiline最大并发ITEM处理数量,默认100 |
CONCURRENT_REQUESTS_PER_DOMAIN | 每个目标域名最大的并发请求数量,默认8 |
CONCURRENT_REQUESTS_PER_IP | 每个目标IP最大的并发请求数量,默认0,非0有效 |
对于JavaScript页面,可以引入第三方库PhantomJS,这是一个轻量级的浏览器库
可以在https://pypi.python.org上面看到一批以scrapy-*的第三方库,是完善scrapy的功能单元