摘要
本文内容转自网络,个人学习记录使用,请勿传播
管道深入操作
如何将数据存储到数据库
- 注意:一个管道类负责将数据存储到一个具体的载体中。如果想要将爬取到的数据存储到多个不同的载体/数据库中,则需要定义多个管道类。
思考:
- 在有多个管道类的前提下,爬虫文件提交的item会同时给没一个管道类还是单独的管道类?
- 爬虫文件只会将item提交给优先级最高的那一个管道类。优先级最高的管道类的process_item中需要写return item操作,该操作就是表示将item对象传递给下一个管道类,下一个管道类获取了item对象,才可以将数据存储成功!
- 在有多个管道类的前提下,爬虫文件提交的item会同时给没一个管道类还是单独的管道类?
管道类:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66# 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
# useful for handling different item types with a single interface
from itemadapter import ItemAdapter
import pymysql
import redis
import pymongo
#负责将数据存储到mysql中
class MysqlPipeline:
conn = None #mysql的链接对象
cursor = None
def open_spider(self,spider):
self.conn = pymysql.Connect(
host = '127.0.0.1',
port = 3306,
user = 'root',
password = 'boboadmin',
db = 'spider3qi',
charset = 'utf8'
)
self.cursor = self.conn.cursor()
#爬虫文件每向管道提交一个item,则process_item方法就会被调用一次
def process_item(self, item, spider):
title = item['title']
sql = 'insert into xiaoshuo (title) values ("%s")'%title
self.cursor.execute(sql)
self.conn.commit()
print('成功写入一条数据!')
return item
def close_spider(self,spider):
self.cursor.close()
self.conn.close()
#将数据持久化存储到redis中
class RedisPipeLine:
conn = None
def open_spider(self,spider):
#在链接前务必手动启动redis的服务
self.conn = redis.Redis(
host='127.0.0.1',
port=6379
)
def process_item(self,item,spider):
#注意:如果想要将一个python字典直接写入到redis中,则redis模块的版本务必是2.10.6
#如果redis模块的版本不是2.10.6则重新安装:pip install redis==2.10.6
self.conn.lpush('xiaoshuo',item)
print('数据存储redis成功!')
return item
class MongoPipeline:
conn = None #链接对象
db_sanqi = None #数据仓库
def open_spider(self,spider):
self.conn = pymongo.MongoClient(
host='127.0.0.1',
port=27017
)
self.db_sanqi = self.conn['sanqi']
def process_item(self,item,spider):
self.db_sanqi['xiaoshuo'].insert_one({'title':item['title']})
print('插入成功!')
return item配置文件:
1
2
3
4
5
6ITEM_PIPELINES = {
#数字表示管道类被执行的优先级,数字越小表示优先级越高
'xiaoshuoPro.pipelines.MysqlPipeline': 300,
'xiaoshuoPro.pipelines.RedisPipeLine': 301,
'xiaoshuoPro.pipelines.MongoPipeline': 302,
}
scrapy爬取多媒体资源数据
使用一个专有的管道类ImagesPipeline
具体的编码流程:
1.在爬虫文件中进行图片/视频的链接提取
2.将提取到的链接封装到items对象中,提交给管道
3.在管道文件中自定义一个父类为ImagesPipeline的管道类,且重写三个方法即可:
1
2
3
4def get_media_requests(self, item, info):接收爬虫文件提交过来的item对象,然后对图片地址发起网路请求,返回图片的二进制数据
def file_path(self, request, response=None, info=None, *, item=None):指定保存图片的名称
def item_completed(self, results, item, info):返回item对象给下一个管道类
4.在配置文件中开启指定的管道,且通过IMAGES_STORE = ‘girlsLib’操作指定图片存储的文件夹。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28# 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
# useful for handling different item types with a single interface
import scrapy
from itemadapter import ItemAdapter
from scrapy.pipelines.images import ImagesPipeline
#自定义的管道类一定要继承与ImagesPipeline
class mediaPileline(ImagesPipeline):
#重写三个父类的方法来完成图片二进制数据的请求和持久化存储
#可以根据图片地址,对其进行请求,获取图片数据
#参数item:就是接收到的item对象
def get_media_requests(self, item, info):
img_src = item['src']
yield scrapy.Request(img_src)
#指定图片的名称(只需要返回图片存储的名称即可)
def file_path(self, request, response=None, info=None, *, item=None):
imgName = request.url.split('/')[-1]
print(imgName,'下载保存成功!')
return imgName
#如果没有下一个管道类,该方法可以不写
def item_completed(self, results, item, info):
return item #可以将当前的管道类接收到item对象传递给下一个管道类2.
scrapy深度爬取
如何爬取多页的数据(全站数据爬取)
手动请求发送:
1
2#callback用来指定解析方法
yield scrapy.Request(url=new_url,callback=self.parse)
如何爬取深度存储的数据
什么是深度,说白了就是爬取的数据没有存在于同一张页面中。
必须使用请求传参的机制才可以完整的实现。
请求传参:
1
2
3yield scrapy.Request(meta={},url=detail_url,callback=self.parse_detail)
可以将meta字典传递给callback这个回调函数
1 | import scrapy |