地球上最好用的爬虫框架:Scrapy:
基本流程:
了解Scrapy 爬虫框架的工作流程:
在scrapy中, 具体工作流程是这样的:
首先第一步 当爬虫引擎启动后, 引擎会到 spider 中获取 start_url 然后将其封装为一个request对象, 交给调度器, 这个调度器中存的是一个又一个的待请求的url request对象, 然后调度器会通过引擎将请求对象交给 下载器 下载器获取到请求对象后, 发送请求,获取响应, 然后将获取的响应封装成一个响应对象 response 后通过引擎再交给spider 来进行数据解析, 数据的解析结果如果是 Url, 则通过引擎继续交给调度器, 如果是数据, 则会通过引擎,将数据交给管道, 这就是scrapy的工作流程,
下载:
pip install scrapy
创建爬虫项目:
在终端中使用scrapy命令来创建一个爬虫项目:
scrapy startproject 项目名字
当我们使用命令完成创建项目的时候, scrapy会自动给我们创建一个有关 项目名 的文件夹:
第一个 game 只是scrapy 创建的项目文件, 也就是项目根目录。
第二个game 目录则是我们的scrapy项目了, 项目目录下的 spiders 目录就是 有关 spider 爬虫脚本的目录
items: 暂时先不了解
middlewares: 中间件
pipelines: 管道, 所有爬虫获取到的数据最终都会到管道来
settings: 项目配置文件
创建爬虫:
使用scrapy命令创建爬虫, 但在运行命令之前,需要 cd 进入到爬虫项目中
scrapy genspider
scrapy genspider myspider baidu.com
然后你会发现在spiders目录下,会多出一个爬虫脚本,点开脚本 :
你会发现scrapy为我们创建了一个爬虫类, 集成之Spider
name 则是爬虫的名字
allowed_domains 则是允许爬取的域名, 除此以外的域名都会被过滤掉
start_urls 则就是起始URL了
而此爬虫类中, 还提供了一个 parse 方法, 此方法就是用来解析获取的响应结果的,
启动爬虫:
启动爬虫也很简单, 使用命令启动爬虫
scrapy crawl 爬虫名字
你会看到控制台打印很多东西, 不用着急, 这只是scrapy的输出日志而已, 我们可以通过命令行或者在settings中配置一下日志输出级别:
楼主这里是在settings 文件中配置的:
加上这句, 配置日志级别为 warning, 那么控制台就只能打印 warning及以上级别的信息了
数据管道:
从爬虫中解析出的数据, 返回给引擎后,由引擎交给数据管道进行处理, 我们可以定义多个数据管道,用来对数据进行不同的存储方式
在pipelines 中定义的所有类都是管道类, 它拥有一个process_item 的方法, 形参 item 就是我们要处理的数据, 而spider, 见名之意, 则是爬虫
定义好管道后, 还需要到settings 配置文件中启用管道:
在settings文件中, 找到此字典,把注释打开, 对应的 key 则是定义好的管道类, 而value 则是 “权重” , 意思就是, 这个值越小, 执行的优先权则越高。
管道:
scrapy 中, spider模块提取出的数据就会交给数据管道进一步处理,先看一下spider中的代码:
例如这里, 定义了一个爬取彩票网站的spider爬虫, 修改好起始的URL, 就可以在parse 方法中提取解析的数据, 我们可以在scrapy中使用 xpath,css 选择器 等提取规则来提取数据, 这里需要注意的是, xpath,css选择器等 在scrapy中已经封装好了,不需要在额外的下载 lxml, bs4 了
Item:
在scrapy中, 可以使用scrapy封装好的数据对象Item来进行数据存储,当然, 你也可以再定义一个字典,来封装数据,但是这样做不好。 当我们的爬虫项目代码量很多的时候, 会很容易出一些不好找的低级bug, 点开 items.py 文件:
可以看到scrapy为我们自动生成了一个继承自 Item 的类, 我们可以在这个类中定义好要封装的数据字段, 然后在spider中使用, 在spider中使用起来也是很简单的, 直接创建该类的对象,然后使用 key: value 的形式来封装数据, 因为 Item 本质上就是一个 dict 类型。
使用了scrapy中的 Item 对象来管理数据, 那么 cai[“date”] 这个 key 值必须和 Item 类中定义好的字段一模一样, 不然会报错,例如:
这样我们在spider中封装数据的时候, 因为手抖写错了 key 值, 那么scrapy框架就会友好的提示我们bug 所在, 这样会很友好。
在返回数据这里, scrapy中一般都是使用yield 关键字来向引擎返回数据。
存储数据:
在爬虫中, 我们可以将数据通过管道存储到 csv 文件, 数据库, 普通文本文件等。
来看代码:
Csv:
在这个管道中, 我重写了两个方法, 分别是 open_spider, 和 close_spider, 管道启动的时候, 会先调用 open_spider, 然后 再调用 process_item 方法来进行数据存储, 最后调用 close_spider, 由此看来, 我们可以在open_spider 中进行连接的初始化, 例如打开一个文件,或者初始化数据库的链接信息, 当所有数据都存储处理完成后, 在close_spider 中关闭所有链接来做善后处理, 这样就不会造成重复的打开,关闭,打开,关闭的IO 问题了。
Mysql:
存储到mysql数据库中,我们可以重新定义一个管道类, 然后将这个管道类注册到settings中:
class CaipiaoMySQLPipeline:
""" 存储mysql """
def open_spider(self, spider):
self.conn = pymysql.connect(
host="localhost",
port=3306,
user="root",
password="root",
database="spider"
)
def process_item(self, item, spider):
try:
cursor = self.conn.cursor()
sql = "insert into caipiao(date_time, red_ball, blue_ball) values (%s, %s, %s)"
cursor.execute(sql, (item["date"], "_".join(item["red_ball"]), item['blue_ball']))
self.conn.commit()
except:
self.conn.rollback()
finally:
if cursor:
cursor.close()
return item
def close_spider(self, spider):
self.conn.close()
MongoDB:
class CaipiaoMongoDBPipeline:
""" 存储数据到 MongoDB """
def open_spider(self, spider):
# 初始化 MongoDB 连接
self.client = pymongo.MongoClient(host="localhost", port=27017, username="root", password="root")
db = self.client["spider"]
self.collection = db["caipiao"]
def process_item(self, item, spider):
# 插入文档到集合,并处理潜在的插入错误
self.collection.insert_one({
"date": item["date"],
"red_ball": item["red_ball"],
"blue_ball": item["blue_ball"]
})
return item
def close_spider(self, spider):
# 关闭 MongoDB 连接
self.client.close()
scrapy.Request:
网页的每个页面都是不一样的, 例如我们想要在一些图片网站上抓取一些图片, 那么首先我们需要先获取网站的图片列表页, 然后在逐个点击列表页的每张图片进入到图片的详情页, 这样在详情页才能提取出高清质量的图片链接信息,再下载高清图片。 如果遇到这种情况, 怎么处理呢?
当我们在scrapy 提供的 parse方法中提取到了列表页之后, 可以使用scrapy 提供的Request 对象, 将列表页中的详情页url 拼接完毕后使用Request 对象封装成一个请求对象,回顾scrapy 的工作流程, 如果spider 返回给引擎的是一个请求对象,那么引擎会将这个请求对象交给调度器排队继续发送请求, 这个Request对象中的 callback 形参指定的就是一个方法, 因为发送请求必须就得有响应, 所以这里可以传递一个回调方法专门去处理该响应的结果!