4. scrapy框架基础
scrapy框架基础
1.安装
Linux安装:
pip install scrapy
Windows安装:
1.pip install wheel -- 可以安装 .whl文件
2.下载twisted <http://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted>
- 找到对应自己电脑python版本
3.进入下载目录,执行 pip install Twisted‑17.1.0‑cp35‑cp35m‑win_amd64.whl(下载的文件)
4.pip install pywin32
5.pip install scrapy -- 安装scrapy爬虫框架
2.基本操作
1.创建一个工程:scrapy startproject 工程名
- 工程目录中:
- spiders:爬虫包
- settings:工程的配置文件
2.创建一个爬虫文件:
cd 工程名 -- 进入工程目录
scrapy genspider 爬虫文件名 www.xxx.com(随意网站,文件里能改)
-数据的爬取和解析是需要编写在爬虫文件中
3.执行工程:scrapy crawl 文件名
- 程序会输出各种日志信息
- 指定输入日志的类型:settings配置文件:LOG_LEVEL= 'ERROR'
- robots.txt协议:君子协议,限制爬虫。
- 如何忽略该协议:settings配置文件:ROBOTSTXT_OBEY = False
简单使用
import scrapy
class FirstSpider(scrapy.Spider):
#爬虫文件的名称:表示当前爬虫文件的唯一标识
name = 'first'
#允许的域名
# allowed_domains = ['www.baidu.com']
#起始url列表:列表中存放的url可以被scrapy进行get请求发送
start_urls = ['https://www.baidu.com/','https://www.jd.com']
#数据解析:response响应对象
def parse(self, response):
print(response)
3.示例 -- 糗事百科 - 段子
解析数据:
settings配置上User-Agent
多页解析时:
- 手动请求发送:
1.get请求:
yield scrapy.Request(url=new_url,callback=self.parse)
2.post请求:
yield scrapy.FormRequest(url=new_url,callback=self.parse,formdata={})
spiders/qiubai.py
import scrapy
class QiubaiSpider(scrapy.Spider):
name = 'qiubai'
# allowed_domains = ['www.xxx.com']
start_urls = ['https://www.qiushibaike.com/text/']
# 1. 数据解析:解析第一页
# def parse(self, response):
# div_list = response.xpath('//*[@id="content"]/div/div[2]/div')
# for div in div_list:
# #extract()可以将Selector对象中的data值取出
# # author = div.xpath('./div[1]/a[2]/h2/text()')[0].extract()
# author = div.xpath('./div[1]/a[2]/h2/text()').extract_first()
# #extract()返回的是列表
# content = div.xpath('./a[1]/div/span//text()').extract()
# content = ''.join(content)
# print(author,content)
# 1.1 解析多页
# 点击下一页通用的url模板
url = 'https://www.qiushibaike.com/text/page/%d/'
page_num = 2
def parse(self, response):
div_list = response.xpath('//*[@id="content"]/div/div[2]/div')
for div in div_list:
#extract()可以将Selector对象中的data值取出
# author = div.xpath('./div[1]/a[2]/h2/text()')[0].extract()
author = div.xpath('./div[1]/a[2]/h2/text()').extract_first()
#extract()返回的是列表
content = div.xpath('./a[1]/div/span//text()').extract()
content = ''.join(content)
print(author,content)
# 手动请求发送
if self.page_num < 6: #
new_url = format(self.url%self.page_num)
self.page_num += 1
yield scrapy.Request(url=new_url,callback=self.parse)
持久化存储
- 方案:
1.基于终端指令的持久化存储
- 只可以将parase方法的返回值存储到指定后缀的文本文件中
- 存储指令:scrapy crwal 爬虫文件名 -o 储存文件路径
2.基于管道的持久化存储(重点)
- 在爬虫文件中进行数据解析
- 在items文件中声明数据解析出的字段属性
- 在爬虫文件中将解析出的字段存储封装到items类型的对象中
- 将item对象提交给管道
- 在管道文件的类中实现任意形式的持久化存储操作
- 需要在配置文件中开启管道机制
- 什么时候需要创建多个管道类?
- 数据备份。一个管道类负责将数据存储到一种平台种。
- 注意:爬虫文件提交过来的item只会给优先级最高的那一个管道类
- 如果保证其他的管道类都可以获取item对象:
- 每个管道类都return item:将item提交给下一个即将被执行的管道类
1.基于终端指令的持久化存储
1.基于终端指令的持久化存储
- 只可以将parase方法的返回值存储到指定后缀的文本文件中
- 存储指令:scrapy crwal 爬虫文件名 -o 储存文件路径
spiders/qiubai.py
import scrapy
class QiubaiSpider(scrapy.Spider):
name = 'qiubai'
# allowed_domains = ['www.xxx.com']
start_urls = ['https://www.qiushibaike.com/text/']
all_list = []
# 基于终端指令的持久化存储
def parse(self, response):
div_list = response.xpath('//*[@id="content"]/div/div[2]/div')
for div in div_list:
#extract()可以将Selector对象中的data值取出
# author = div.xpath('./div[1]/a[2]/h2/text()')[0].extract()
author = div.xpath('./div[1]/a[2]/h2/text()').extract_first()
#extract()返回的是列表
content = div.xpath('./a[1]/div/span//text()').extract()
content = ''.join(content)
print(author,content)
dic = {
'author':author,
'content':content
}
self.all_list.append(dic)
return self.all_list
执行项目
scrapy crawl qiubai -o 1.csv
2.基于管道的持久化存储(重点)
2.基于管道的持久化存储(重点)
- 在爬虫文件中进行数据解析
- 在items文件中声明数据解析出的字段属性
- 在爬虫文件中将解析出的字段存储封装到items类型的对象中
- 将item对象提交给管道
- 在管道文件pipelines.py的类中实现任意形式的持久化存储操作
- 需要在配置文件中开启管道机制
- 什么时候需要创建多个管道类?
- 数据备份。一个管道类负责将数据存储到一种平台种。
- 注意:爬虫文件提交过来的item只会给优先级最高的那一个管道类
- 如果保证其他的管道类都可以获取item对象:
- 每个管道类都return item:将item提交给下一个即将被执行的管道类
redis-Windows安装:
下载地址:https://github.com/tporadowski/redis/releases
解压->cd到文件夹下:redis-server.exe redis.windows.conf
spiders/qiubai.py
import scrapy
from qiubaiPro.items import QiubaiproItem # 引入items类
class QiubaiSpider(scrapy.Spider):
name = 'qiubai'
# allowed_domains = ['www.xxx.com']
start_urls = ['https://www.qiushibaike.com/text/']
# 基于管道持久化存储
def parse(self, response):
div_list = response.xpath('//*[@id="content"]/div/div[2]/div')
for div in div_list:
#extract()可以将Selector对象中的data值取出
# author = div.xpath('./div[1]/a[2]/h2/text()')[0].extract()
author = div.xpath('./div[1]/a[2]/h2/text()').extract_first()
#extract()返回的是列表
content = div.xpath('./a[1]/div/span//text()').extract()
content = ''.join(content)
item = QiubaiproItem() # 实例化item对象,将解析出的值赋给item对象
item['author'] = author
item['content'] = content
yield item # 将item对象提交给管道
items.py
import scrapy
class QiubaiproItem(scrapy.Item):
# define the fields for your item here like:
# 声明两个字段
author = scrapy.Field()
content = scrapy.Field()
settings.py
ITEM_PIPELINES = {
#300表示的是管道类的优先级,数值越小表示优先级越高
'qiubaiPro.pipelines.QiubaiproPipeline': 300,
'qiubaiPro.pipelines.MySqlPipeLine': 301,
'qiubaiPro.pipelines.RedisPipeLine': 302,
}
pipelines.py
import pymysql
from redis import Redis
# 将数据储存到本地文件
class QiubaiproPipeline:
fp = None
def open_spider(self,spider):#在开始爬取数据的时候被调用一次
print('i am open_spider()')
self.fp = open('./qiubai.txt','w',encoding='utf-8')
# 参数item就是管道接收到的item对象
# 该方法的调用次数取决于爬虫文件提交item的次数
def process_item(self, item, spider):
self.fp.write(item['author']+':'+item['content']+'\n')
return item #将item提交给下一个即将被执行的管道类
def close_spider(self,spider):#只会在爬虫结束时调用一次
print('i am close_spider()')
self.fp.close()
# 定义管道类,负责将数据存储到mysql
class MySqlPipeLine(object):
conn =None
cursor = None
def open_spider(self,spider):
# 创建连接
self.conn = pymysql.Connect(host='127.0.0.1',port=3306,user='root',password='123456',db='qiushi',charset='utf8')
def process_item(self,item,spider):
# 创建游标对象
self.cursor = self.conn.cursor()
# sql语句插入数据
sql = 'insert into qiubai values("%s","%s")'%(item['author'],item['content'])
try:
self.cursor.execute(sql) # 执行sql语句
self.conn.commit() # 没有错误提交
except Exception as e:
print(e)
self.conn.rollback() # 出错回滚
return item
def close_spider(self,spider):
self.cursor.close() # 关闭游标
self.conn.close() # 关闭连接
# 定义管道类,负责将数据存储到redis
# redis模块的版本2.10.6
class RedisPipeLine(object):
conn = None
def open_spider(self,spider):
# 建立连接
self.conn = Redis(host='127.0.0.1',port=6379)
def process_item(self,item,spider):
self.conn.lpush('qiubaiQueue',item)
return item