scrapy介绍
Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架,我们只需要实现少量的代码,就能够快速的抓取,Scrapy使用了Twisted异步网络框架,可以加快我们的下载速度。
scrapy是异步爬虫的框架,是爬虫必备的技术,很少有语言有专门的框架进行爬虫,python中的scrapy框架是专门用于爬虫的;让爬虫程序更稳定,效率更高,scrapy框架的很多内容都是封装好的;配置和可扩展性很高,有了固定的框架,直接去添加内容和调用就可以了;是基于异步的,内部封装了Twisted(曲折),实现逻辑非常复杂,采取了大量的闭包,以高阶函数(以函数为返回值或是以函数对象为参数的)为基础,大的函数里嵌套了小的函数,函数内部要去引用外部函数的变量,确保变量的安全性,就形成了闭包。下载速度非常快,是异步网络框架,download的原理是基于内部封装的多线程,直接调用就可以了,下载的效率也很高,内部封装了可以控制爬取速度的方法,可以通过修改配置项来达到控制爬取速度的目的。
异步和非阻塞的区别

同步的过程,从上往下看,只有等待蓝色函数执行完后,获取return之后再执行黄色的函数,好比一条流水线,只有把上面的事情做完了才能做下面的事情。
异步的过程,蓝色的函数并没有对黄色的函数产生影响,在蓝色向网站发起请求,在等待网站反馈的时间段里,黄色函数就可以向另外一个页面发起请求,充分利用了等待的时间,提高了爬取的效率。
异步:调用在发出之后,这个调用就直接返回,不管有无结果
非阻塞:关注的是程序在等待调用结果时的状态,指在不能立刻得到结果之前,该调用不会阻塞当前线程。
Scrapy工作流程
我们通常不会仅仅只对一个url发起请求,实现对多个页面的爬取,这时就可以把多个页面放到url list 中。从url list 中提取出url,并向其发送请求,获得相应,提取数据,解析数据,保存内容等数据的处理;然后对下一个url循环进行同样的操作。

有两个队列,队列1存放的是每一页的url,运行的线程从队列1中拿到url,发请求,获相应,解析每一页的数据,把解析到的数据放到队列2中(如解析图片的名字和url),然后放到下一个线程中进行下载和保存的操作。

scrapy是基于异步的,它的可配置性和可扩展性都很高,结构比较特殊和复杂。引擎负责整个scrapy框架的调度,无论是请求还是获取相应都要经过引擎,相当于人类的大脑。第一步,把目标url发送给引擎,引擎的下方有个爬虫程序,里有我们需要的url地址,把url地址发送给引擎,引擎只负责调度,download是个下载器;第二步引擎拿到url之后会先给调度器,调度器接收到请求的url并入列;第三步入列之后调度器给下载器,下载器连接网络之后做请求响应的操作,调度器发起请求,获得响应的结果;第四步响应的结果并不是给下载器处理的,下载器获取到响应结果之后,交给爬虫程序进行处理,爬虫程序拿到响应结果之后做数据解析处理;第五步把解析到的数据交给管道处理,管道专门做保存数据的。然后循环进行操作,直到调度器里没有url为止。
大致的工作流程:引擎会找爬虫程序要到url(可能会是多个),通过爬虫程序拿到url之后给调度器,url在调度器里入列,入列后取出其中一个url返回下载器进行发送请求,获取相应,把相应结果给爬虫程序做解析的处理,最后爬虫程序把解析好的数据给管道做保存操作,这个过程循环进行,直到调度器中没有任何的url,就会停止。

1.爬虫程序发送url给引擎,2.引擎发送url给调度器入列,3.调度器给引擎一个爬取的url,4.引擎把url通过下载中间件发送给下载器,下载器拿到url之后需要联网发送请求,获取相应,5.下载器把生成的response通过下载中间件发送给引擎,6.引擎会把接收到的response给爬虫程序解析,爬虫程序和引擎中间通过爬虫中间件进行连接,7.爬虫程序把解析好的数据之后,通过引擎发送给管道文件进行保存操作,8.通过解析的数据中可能页有新的url需要处理,继续上面的步骤。

| 名称 | 作用 | 实现 |
|---|---|---|
| Scrapy engine(引擎) | 整个框架的核心,总指挥:负责数据和信号的在不同模块间的传递 | scrapy已经实现 |
| Scheduler(调度器) | 一个队列,存放引擎发过来的request请求,接收从引擎发送来的url,进行入列的操作 | scrapy已经实现 |
| Downloader(下载器) | 发送请求,获取相应,下载把引擎发过来的requests请求,并返回给引擎 | scrapy已经实现 |
| Spider(爬虫文件) | 数据解析,处理引擎发来的response,提取数据,提取url,并交给引擎 | 需要改写 |
| Item Pipline(管道) | 存储数据,处理引擎传过来的数据,比如存储 | 需要改写 |
| Downloader Middlewares(下载中间件) | 位于引擎和下载器中间,用来处理它们之间的请求和相应(用的比较多),可以自定义的下载扩展,比如设置代理 | 一般不用手写 |
| Spider Middlewares(中间件) | 可以自定义requests请求和进行response过滤 | 一般不用手写 |
| 爬虫中间件 | 位于引擎和爬虫程序中间,用来处理爬虫程序的响应和输出结果以及新的请求(用的比较少) | 一般不用手写 |
框架是搭好的,内部是已经封装好的程序,爬虫文件,管道需要改写,下载中间件可能需要改写。
用scrapy爬取数据的基本步骤
第一步 创建scrapy项目,需要用到命令,scrapy startproject(固定的)+ 项目名字,开始项目后面跟项目的名字
第二部 创建爬虫程序 scrapy genspider(固定的)+爬虫文件的名字 + 爬取的范围(域名)
执行scrapy爬虫程序的命令:scrapy crawl 爬虫文件的名字
1 创建一个scrapy项目
scrapy startproject mySpider
2 生成一个爬虫
scrapy genspider demo demo.cn
https://www.baidu.com/ --> baidu.com
https://www.douban.com/ --> douban.com
3 提取数据
完善spider 使用xpath等
4 保存数据
pipeline中保存数据
具体步骤:点击pycham下方的Terminal进入路径界面,依次按路径输入 cd 爬虫,cd 21day ,进入到D:\PycharmProjects\爬虫\21day>路径里,然后创建mySpider的文件夹,执行命令scrapy startproject mySpider。

现在新的工程文件已经创建成功,同时在pycham左侧显示创建成功的文件夹

依次展开mySprider文件夹,出现以下文件,打开scrapy.cfg文件,里面会提示这个文件是自动创建的,有最新的帮助文档地址,以及告诉我们其他配置文件的来源及如何创建的。

创建好文件夹之后,下面就可以通过cd mySprider进入到文件夹内部,创建通过scrapy genspider 爬虫程序了,这里先创建豆瓣的爬虫文件,scrapy genspider db douban.com。

提示爬虫文件已经创建完成,我们通过mySprider,spiders目录下看到创建好的db文件。

创建好的db文件内,在parse函数里会有高亮提示,给出了警告,在继承父类的过程中,会有修改父类的需求,涉及到面向对象的重写和重载的概念,重写是子类对父类的实现方法进行重新的编写,此时返回值和形参都不能改变,只能修改函数里面的代码,头和尾都不能修改,也就是说外壳不能改变,内部的东西可以进行重写;重载是方法名相同,参数以及返回值类型都不一样。这里是需要对函数进行重载,对参数的个数进行了修改,出现了不一致的情况,在代码源文件中有三个参数(def parse(self, response, **kwargs):),这里只有两个,这个提示并不影响后面的爬取和程序的运行,也可以把源代码复制进去进行替代。
这时程序运行是在21day文件夹下的mySprider,如果对mySprider文件进行删除操作,会提示文件夹正在使用不能删除,可以用cd…,退出当前文件夹。
在创建的文件夹中需要修改几个常用的参数,settings.py中设置 ROBOTSTXT_OBEY、CONCURRENT_REQUESTS、DOWNLOAD_DELAY、DEFAULT_REQUEST_HEADERS、SPIDER_MIDDLEWARES、DOWNLOADER_MIDDLEWARES、ITEM_PIPELINES,打开注释就可以使用。运行程序的时候用的比较多的是爬虫、pipelines、settings文件。
用scrapy爬取豆瓣主页标签
页面分析
在页面“选电影”处,点右键检查,定位到li下的a标签内,复制“选电影”到网页源码中查看,发现网页是静态加载出来的,需要的数据在网页源码中。往上折叠一下,发现电影类别下每个标签都存放在相应的li内,所有的li都放到ul标签内,一直往上收,发现有电影、小组等多个类别放在div标签中的,而我们需要的数据标签都放在class="sid-links nav-anon"的标签内,我们要先定位到class=“sid-links nav-anon”,从网页源码中可以看到有个这样的标签,代表页面5个这样的类别。



爬取完成之后,发现书评和音乐人之前有空的内容,检查网页中发现中间有个购书单,点右键检查,发现购书单在a标签下的em标签里,可以对爬取的标签进行判断,如果在em标签里,就在a标签里打印。scrapy.Request(url,callback=‘解析方法’)用做翻页的处理,可以通过yield 返回,返回的是request对象。
解析完成之后,下一步进行保存,scrapy里有pipelines(管道)进行数据的保存。
1.在settings文件里把管道文件给打开,开启管道
2.去爬虫程序里,加上yield item,把需要的数据yield给管道,yield把函数变为生成器函数,直接给管道接收。在管道函数中加上开启爬虫、结束爬虫的函数,注意必须要传入参数spider。
代码实现
设置参数
setting.py
LOG_LEVEL = 'WARNING' # 设置打印等级
BOT_NAME = 'mySpider'
SPIDER_MODULES = ['mySpider.spiders']
NEWSPIDER_MODULE = 'mySpider.spiders'
ROBOTSTXT_OBEY = True
DEFAULT_REQUEST_HEADERS = {
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'en',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36 Edg/92.0.902.62'
}
ITEM_PIPELINES = {
'mySpider.pipelines.MyspiderPipeline': 300,
}
管道文件
pipelines.py
class MyspiderPipeline:
def __init__(self):
self.f = open('db.txt', 'w', encoding='utf-8')
# 爬虫开始的方法
def open_spider(self, spider):
print('爬虫开始!')
def process_item(self, item, spider):
# item 是从爬虫端接收到的数据,作为参数传递进去,在保存之前可以先打印看一下
# item 此时是个字典,保存的类型是txt,需要强转为字符串存入
print(item)
self.f.write(str(item) + '\n')
return item
# 爬虫结束的方法
# spider是爬虫的对象,是爬虫的名字db
def close_spider(self, spider):
# print(spider.name) # db,爬虫的名字
print('爬虫结束!')
self.f.close()
定义带爬取的字段名,提前做好数据封装
items.py
import scrapy
class MyspiderItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
# 可以在里面定义带爬取的字段名
title = scrapy.Field()
爬虫程序
db.py
import scrapy
class DbSpider(scrapy.Spider): # DbSpider类继承了scrapy.Spider
name = 'db' # 爬虫的名字
allowed_domains = ['douban.com'] # 可允许的范围,网页爬取的范围,内容可以更改,内容是列表,可以添加其他内容
start_urls = ['http://douban.com/'] # 内容是列表,可以增加和修改,
# 具体的解析方法,response对应的是响应结果,当成parse解析函数的参数传递到进去,
# 在parse里就不用再做请求,响应的操作,只需要解析拿到的响应结果就可以了
def parse(self, response,**kwargs): # **kwargs 可加可不加,不加有警告,不影响运行
# response是html的response对象,可以用xpath方法
li_list =response.xpath('.//div[@class="side-links nav-anon"]/ul/li')
for li in li_list:
item = {}
# item['title'] = li.xpath('.//a/text()')
# print(item)
# 通过 crapy crawl db 执行scrapy文件,在settings里设置打印等级和UA
# {'title': [<Selector xpath='.//a/text()' data='专题'>]} 打印的是Selector对象,获取里面的内容
"""获取Selector对象文本数据的方法:
extract_first() 返回一条数据
extract 返回多条数据
get() 返回一条数据
getall() 返回多条数据
"""
# item['title'] = li.xpath('./a/text()').get()
# print(item)
# 这是第一种启动scrapy的方法,在Terminal中输入 crapy crawl db
# 第二种启动的方法,在第一个mySprider里创建start.py
# 返回的数据中 书评和音乐人之间有空行,检查网页发现里面的购书单存放在a标签下的em标签里
item['title'] = li.xpath('.//a/em/text()').get()
if item['title'] == None:
item['title'] = li.xpath('.//a/text()').get()
# print(item)
yield item
启动程序
start.py
from scrapy import cmdline
# cmdline.execute(['scrapy', 'crawl', 'db']) # 方法一
cmdline.execute('scrapy crawl db'.split(" ")) # 方法二
本文详细介绍Scrapy爬虫框架的核心功能与工作流程,包括异步网络请求处理、多线程下载机制及数据解析保存方法。并通过实例演示如何使用Scrapy进行豆瓣网站标签爬取。
1042

被折叠的 条评论
为什么被折叠?



