怎么使用Python爬虫中的Scrapy框架
怎么使用Python爬虫中的Scrapy框架
这篇文章主要介绍怎么使用Python爬虫中的Scrapy框架,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!
一、前情提要
为什么要使用Scrapy 框架?
前两篇深造篇介绍了多线程这个概念和实战
多线程网页爬取
多线程爬取网页项目实战
经过之前的学习,我们基本掌握了分析页面、分析动态请求、抓取内容,也学会使用多线程来并发爬取网页提高效率。这些技能点已经足够我们写出各式各样符合我们要求的爬虫了。
但我们还有一个没解决的问题,那就是工程化。工程化可以让我们写代码的过程从「想一段写一段」中解脱出来,变得有秩序、风格统一、不写重复的东西。
而Scrapy 就是爬虫框架中的佼佼者。它为我们提前想好了很多步骤和要处理的边边角角的问题,而使用者可以专心于处理解析页面、分析请求这种最核心的事情。
二、Scrapy框架的概念
Scrapy 是一个纯 Python 实现的、流行的网络爬虫框架,它使用了一些高级功能来简化网页的抓取,能让我们的爬虫更加的规范、高效。
它可以分为如下几个部分
组件 | 功能 |
---|---|
Scrapy Engine | Scrapy 引擎,负责控制整个系统的数据流和事件的触发 |
Scheduler | 调度器,接收 Scrapy 引擎发来的请求并将其加入队列中,等待引擎后续需要时使用 |
Downloader | 下载器,爬取网页内容,将爬取到的数据返回给 Spiders(爬虫) |
Spiders | 爬虫,这部分是核心代码,用于解析、提取出需要的数据 |
Item Pipeline | 数据管道,处理提取出的数据,主要是数据清洗、验证和数据存储 |
Downloader middlewares | 下载器中间件,处理 Scrapy 引擎和下载器之间的请求和响应 |
Spider middlewares | 爬虫中间件,处理爬虫输入的响应以及输出结果或新的请求 |
Scrapy 中数据流的过程如下
步骤 | 数据流 |
---|---|
1 | 引擎打开一个网站,找到处理该网站对应的爬虫,并爬取网页的第一个页面 |
2 | 引擎从爬虫中获取第一个页面地址,并将其作为请求放进调度器中进行调度 |
3 | 引擎从调度器中获取下一个页面的地址 |
4 | 调度器返回下一个页面的地址给 Scrapy 引擎,Scrapy 引擎通过下载器中间件传递给下载器进行爬取 |
5 | 爬取到数据后,下载器通过下载器中间件回传给 Scrapy 引擎 |
6 | Scrapy 引擎将爬取到的数据通过爬虫中间件传递给爬虫进行数据解析、提取 |
7 | 爬虫处理完数据后,将提取出的数据和新的请求回传给 Scrapy 引擎 |
8 | Scrapy 将提取出的数据传给数据管道进行数据清洗等操作,同时将新的请求传递给调度器准备进行下一页的爬取 |
9 | 重复 2-8 步,直到调度器中没有新的请求,数据爬取结束 |
三、Scrapy安装
Win + R打开运行,点击确定
然后在命令行上敲上
pipinstallscrapy-ihttps://pypi.doubanio.com/simple/#这句话后面-ihttps://pypi.doubanio.com/simple/表示使用豆瓣的源,这样安装会更快
之后点击回车,等待它自己安装完成便可!
然后,我们在命令行上敲上scrapy,便会显示scrapy的信息,这样就代表安装成功啦!
注意!!再然后我们在命令行敲上explorer . (Mac 中是 open .,注意 . 前面有个空格) 命令并回车,可以打开命令行当前所在的目录。下面,我们就要在这个目录里开始编写代码。
四、Scrapy实战运用
这次我们试着用Scrapy爬取的网站是:小众软件 https://www.appinn.com/category/windows/
在进行网页爬取前,我们先需要创建代码文件,然后利用Scrapy命令进行执行。
在上面我们利用explorer . 命令打开了目录,在这个目录下我们创建一个spider.py 的文件↓
方法:创建文本文件改后缀名即可
然后将爬虫代码放进去,现在大家先复制黏贴代码,进行尝试一下,之后我再来讲解代码的含义!
爬虫代码
importscrapy#定义一个类叫做TitleSpider继承自scrapy.SpiderclassTitleSpider(scrapy.Spider):name='title-spider'#设定开始爬取的页面start_urls=['https://www.appinn.com/category/windows/']defparse(self,response):#找到所有article标签forarticleinresponse.css('article'):#解析article下面a标签里的链接和标题a=article.css('h3.titlea')ifa:result={'title':a.attrib['title'],'url':a.attrib['href'],}#得到结果yieldresult#解析下一页的链接next_page=response.css('a.next::attr(href)').get()ifnext_pageisnotNone:#开始爬下一页,使用parse方法解析yieldresponse.follow(next_page,self.parse)
然后在命令行中执行scrapy 的runspider 命令
scrapyrunspiderspider.py-tcsv-oapps.csv#spider.py是刚刚写的爬虫代码的文件名#-t表示输出的文件格式,我们用csv,方便用Excel等工具打开#-o表示输出的文件名,所以执行完会出现一个apps.csv的文件
敲完上面这句命令,稍等一下,你应该能看见很多的输出?
网页爬取结果
以及目录里多出来一个apps.csv 文件。有 Excel 的同学可以用 Excel 打开apps.csv,或者直接用记事本或者其他编辑器打开它。
打开后能看见 400 多篇小众软件的软件推荐文章的标题和链接?
可是我们的代码里完全没有用到 requests、beautifulsoup、concurrent 以及文件相关的库,是怎么完成了一次快速的爬取并写到文件的呢?别急,让我为你慢慢讲解!
这一串代码干了什么?
上面用到的爬虫代码
importscrapy#定义一个类叫做TitleSpider继承自scrapy.SpiderclassTitleSpider(scrapy.Spider):name='title-spider'#设定开始爬取的页面start_urls=['https://www.appinn.com/category/windows/']defparse(self,response):#找到所有article标签forarticleinresponse.css('article'):#解析article下面a标签里的链接和标题a=article.css('h3.titlea')ifa:result={'title':a.attrib['title'],'url':a.attrib['href'],}#得到结果yieldresult#解析下一页的链接next_page=response.css('a.next::attr(href)').get()ifnext_pageisnotNone:#开始爬下一页,使用parse方法解析yieldresponse.follow(next_page,self.parse)
当运行scrapy runspider spider.py -t csv -o apps.csv时,Scrapy 会执行我们写在spider.py里的爬虫,也就是上面那段完整的代码
1、首先,Scrapy 读到我们设定的启动页面 start_urls,开始请求这个页面,得到一个响应。
//Anhighlightedblockstart_urls=['https://www.appinn.com/category/windows/']
2、之后,Scrapy 把这个响应交给 默认 的解析方法 parse 来处理。响应 response 就是 parse 的第一个参数
defparse(self,response):
3、在我们自己写的 parse 方法里,有两个部分:一是解析出页面里的 article 标签,得到标题和链接作为爬取的结果;二是解析 下一页 按钮这个位置,拿到下一页的链接,并同样继续请求、然后使用 parse 方法解析
#把这条结果告诉Scrapyyieldresult#通知Scrapy开始爬下一页,使用parse方法解析yieldresponse.follow(next_page,self.parse)
yield 是 Python 中一个较高级的用法,在这里我们只需要知道,我们通过yield 通知Scrapy 两件事:我们拿到了结果,快去处理吧、我们拿到了下一个要爬的链接,快去爬取吧。
流程图
没错,除了解析想要的数据,其他的一切都是 Scrapy 替你完成的。这就是 Scrapy 的最大优势:
requests 去哪了?不需要,只要把链接交给Scrapy 就会自动帮你完成请求;
concurrent 去哪了?不需要,Scrapy 会自动把全部的请求都变成并发的;
怎么把结果写到文件?不用实现写文件的代码,使用yield 通知一下Scrapy 结果即可自动写入文件;
怎么继续爬取下一个页面?使用 yield 通知 =Scrapy下一个页面的链接和处理方法就好;
BeautifulSoup 去哪了?可以不需要,Scrapy 提供了好用的 CSS 选择器。
解析数据这件事情还是值得我们关心的,即使 Scrapy 没有强制让我们使用什么,因此我们非要继续使用BeautifulSoup也是可以的,只需在 parse() 方法里将 response.text 传递给 BeautifulSoup 进行解析、提取即可。
但是 Scrapy 提供了很好用的工具,叫做 CSS 选择器。CSS 选择器我们在 BeautifulSoup 中简单介绍过,你还有印象吗?
对BeautifulSoup这个库忘记了的同学,可以看看我之前写的一篇文章:requests库和BeautifulSoup库
Scrapy 中的 CSS 选择器语法和 BeautifulSoup 中的差不多,Scrapy 中的 CSS 选择器更加强大一些
#从响应里解析出所有article标签response.css('article')#从article里解析出class为title的h3标签下面的a标签article.css('h3.titlea')#取出a里面的href属性值a.attrib['href']#从响应里解析出class为next的a标签的href属性,并取出它的值response.css('a.next::attr(href)').get()
scrapy 中的 CSS 选择器可以取代 beautifulsoup 的功能,我们直接用它就解析、提取获取到的数据。看到这里,再回头看上面的完整代码,试着结合流程图再理解一下就会有不错的了解了。
五、Scrapy的css选择器教学
我们还是打开之前爬取的网站:小众软件 https://www.appinn.com/category/windows/
用网页开发者工具选中下一页↓
注意截图中被框住的部分,浏览器已经展示出来这个按钮的 CSS 选择方法是什么了。它告诉我们下一页按钮的选择方式是a.next.page-numbers。
开始css选择器教学前,我建议你使用 Scrapy 提供的互动工具来体验一下 CSS 选择器。方式是在命令行中输入以下命令并回车
scrapyshell"https://www.appinn.com/category/windows/"
这时 Scrapy 已经访问了这个链接,并把获取到的结果记录了下来,你会进入到一个交互环境,我们可以在这个环境里写代码并一句一句执行。输入response 并回车,你能看见类似下面的响应,这就是上面获取到的网页结果。
我之前有说过,输出的200其实就是一个响应状态码,意思就是请求成功了!
之前的文章:requests库和BeautifulSoup库
下面我们就来学习一下css选择器吧,我们以下图中“下一页”按钮为例子?
按标签名选择
小众软件网站下一页按钮的选择方式是a.next.page-numbers,其中的 a 是标签名。试着在互动环境中,输入response.css(‘a'),可以看到页面上所有的 a 元素。其他元素也是一样,例如写response.css(‘ul') 就可以选择出所有 ul 元素,response.css(‘div') 可以选择出div 元素。
按 class 选择
a.next.page-numbers 中的.next 和.page-numbers 表示class的名字。当我们想要选择 class 包含container 的div 元素,我们可以写response.css(‘div.container')。
上面的选择器前面是标签名,. 表示 class,后面跟着 class 的名称。注意,它们是紧紧挨在一起的,中间不能有空格!
当要选择的元素有多个 class 时,比如下面这样的一个元素
<aclass="nextpage-numbers"href="/windows/page/2/"rel="externalnofollow">下一页</a>
这个 a 元素有 next 和 page-number 两个 class,可以写多个 . 来选择:response.css(‘a.next.page-numbers')。表示选择 class 同时包含next 和 page-numbers 的 a 元素,这里它们也必须紧挨在一起,之前不能有空格。
按 id 选择
除了 class 选择器外,同样也有 id 选择器,Scrapy 中也是用 # 代表 id。比如网页上的菜单按钮,我们看到它的 id 是 pull,class 是toggle-mobile-menu。所以可以写response.css(‘a#pull'),表示我们想选择一个 id 为 pull 的 a 元素。
当然,你也可以组合使用:response.css(‘a#pull.toggle-mobile-menu')。表示我们要选择 id 为 pull,并且 class 包含toggle-mobile-menu 的 a 元素。
按层级关系选择
还是小众软件的这个页面,如果我们想用 CSS 选择器选中标题这个位置的 a 元素,使用 Chrome 选取之后发现这个 a 元素既没有 id 也没有 class,浏览器也只给我们提示一个 a?
这时,我们就需要在该元素的父元素上找找线索,例如我们发现这个 a 元素在一个 h3 元素的下面,而这个 h3 元素是有 class 的,class 为 title 和 post-title。所以我们要做的是选择 class 为 title 和 post-title 的 h3 元素下面的 a 元素,用 CSS 选择器写作
response.css('h3.title.post-titlea::text')
可以看到,title 和 post-title 的 h3 元素写作 h3.title.post-title,是紧紧连在一起的,而下面的 a 元素则在 a 前面加了一个空格。想起之前说过的规则了吗?规则便是:并列关系连在一起,层级关系用空格隔开。
.title 和 .post-title 紧跟在 h3 后面,它俩都是 h3 的筛选条件。而空格后面跟着的 a 表示符合 h3.title.post-title 条件元素的子元素中的所有 a 元素。
我们之前还说过,空格后面表示的是所有的子元素,不管是处于多少层的子元素。而如果只想要第一层的子元素则应该用 > 分隔开。这里的 a 元素就是第一层的子元素,所以 h3.title.post-title a 和 h3.title.post-title > a 这两种写法的效果是一样的。
取元素中的文本
我们拿到了标题位置的 a 元素,想要拿到其中的文本内容就需要在后面加上 ::text,代码如下
response.css('h3.title.post-titlea::text')
在互动环境执行一下,会发现文本内容能获取到,但不是我们想要的纯文本,如果想拿到纯文本,还需要使用 get() 或者 getall() 方法,如下
#取符合条件的第一条数据response.css('h3.title.post-titlea::text').get()#取符合条件的所有数据response.css('h3.title.post-titlea::text').getall()
取元素的属性
还是用这个 a 元素举例。如果我们想得到这个 a 元素的 href 属性,需要调用这个元素的 attrib 属性。在互动环境中执行下面两句代码
#拿到符合选择器条件的第一个a标签a=response.css('h3.title.post-titlea')a.attrib['href']
attrib 属性实际上是一个字典,里面存储了元素上的所有 HTML 属性。如果把第二句换成 a.attrib,你就能看到这个 a 元素上的所有属性。类似的,输入 a.attrib[‘title'],你可以得到它的 title 属性。
现在我们试试打印所有符合 h3.title.post-title a 这个条件的标签的 href 属性,就像下面这样
forainresponse.css('h3.title.post-titlea'):print(a.attrib['href'])
或者另一种写法也可以取到 href 属性,就是加上 ::attr(href)
forhrefinresponse.css('h3.title.post-titlea::attr(href)').getall():print(href)
以上是“怎么使用Python爬虫中的Scrapy框架”这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注恰卡编程网行业资讯频道!
推荐阅读
-
python(中无效的十进制怎么解决 python怎么转换进制)
python怎么转换进制?Python执行二进制转换:1.十进制到二进制(bin)首先,让让我们看看如何将十进制转换成二进制。我...
-
python怎么清除完全相同的行(python splte如何分隔有多个相同符号的str)
pythonsplte如何分隔有多个相同符号的str?str你的string内容str_(相同的符号)执行完了以后再在相同符号的...
-
python(编程控制电脑关机 如何控制电脑关机)
如何控制电脑关机?可以在电脑的运行窗口中输入输入公式,给电脑可以设置自动关机。1.按开快捷键winr然后打开运行窗口。2.在运行窗...
-
python中的特殊标识符(python 中 标识符中可以有逗号吗)
python中标识符中可以有逗号吗?在python语言中合法的标识符是字母、数字以及_,所以我合法的标识符中肯定不能有逗号if...
-
python(excel 提取数据写入新表 python导入excel数据找不到工作簿)
python导入excel数据找不到工作簿?我可以导入数据后找不到工作,不是因为他的工作没有被转移。什么软件可提取并合并Exce...
-
python中字典定义的四种方法(python global关键字的用法详解)
pythonglobal关键字的用法详解?global标志实际上是目的是提示python讲解器,说被其修饰的变量是全局变量。这样...
-
python(array用法 python如何对两个数组做差处理)
python如何对两个数组做差处理?Python中的列表中的元素肯定不能真接相加,减。t最佳的位置的是将列表装换成Python中的...
-
python多行注释符号怎么表示
python多行注释符号怎么表示这篇文章主要介绍“python多行...
-
python支持的操作系统是什么
python支持的操作系统是什么这篇文章主要介绍“python支持...
-
python如何判断列表为空
python如何判断列表为空这篇文章主要介绍“python如何判断...