![Python数据分析从入门到精通](https://wfqqreader-1252317822.image.myqcloud.com/cover/705/33643705/b_33643705.jpg)
3.3 使用爬虫框架Scrapy
![](https://epubservercos.yuewen.com/3F131D/17977545801605906/epubprivate/OEBPS/Images/81_03.jpg?sign=1739349984-HQFGSS0cpkH9SZ5kzurLwa23E8E1TSCO-0-4e388c8e9952d25ae2b999ad323e160b)
因为爬虫应用程序的需求日益高涨,所以在市面中诞生了很多第三方开源爬虫框架,其中Scrapy是一个为了爬取网站数据、提取结构性数据而编写的专业框架。Scrapy框架的用途十分广泛,可以用于数据挖掘、数据监测和自动化测试等工作。本节将简要讲解爬虫框架Scrapy的基本用法。
3.3.1 Scrapy框架基础
框架Scrapy使用了Twisted异步网络库来处理网络通信,其整体架构大致如图3-9所示。
![](https://epubservercos.yuewen.com/3F131D/17977545801605906/epubprivate/OEBPS/Images/82_01.jpg?sign=1739349984-5YENr3kv3Uto5PWTtdQ2B9engrAizXoG-0-186e4a7b1e124ac1b21dbd0574f8493c)
图3-9 框架Scrapy的架构
在Scrapy框架中,主要包括如下所示的组件。
● 引擎(Scrapy Engine):来处理整个系统的数据流,会触发框架核心事务。
● 调度器(Scheduler):用来获取Scrapy发送过来的请求,然后将请求传入队列中,并在引擎再次请求的时候返回。调度器的功能是设置下一个要抓取的网址,并删除重复的网址。
● 下载器(Downloader):建立在高效的异步模型Twisted之上,下载目标网址中的网页内容,并将网页内容返回给Scrapy Engine。
● 爬虫(Spiders):功能是从特定的网页中提取指定的信息,这些信息在爬虫领域中被称为实体(Item)。
● 项目管道(Pipeline):处理从网页中提取的爬虫实体。当使用爬虫解析一个页面后,会将实体发送到项目管道中进行处理,然后验证实体的有效性,并将不需要的信息删除。
● 下载器中间件(Downloader Middlewares):此模块位于Scrapy引擎和Downloader之间,为Scrapy引擎与下载器之间的请求及响应建立桥梁。
● 爬虫中间件(Spider Middlewares):此模块在Scrapy引擎和Spiders之间,功能是处理爬虫的响应输入和请求输出。
● 调度中间件(Scheduler Middewares):在Scrapy引擎和Scheduler之间,表示从Scrapy引擎发送到调度的请求和响应。
在使用Scrapy框架后,下面是大多数爬虫程序的运行流程。
1)Scrapy Engine从调度器中取出一个URL链接,这个链接作为下一个要抓取的目标。
2)Scrapy Engine将目标URL封装成一个Request请求并传递给下载器,下载器在下载URL资源后,将资源封装成Response应答包。
3)使用爬虫解析Response应答包,如果解析出Item实体,则将结果交给实体管道进行进一步的处理。如果是URL链接,则把URL交给Scheduler等待下一步的抓取操作。
3.3.2 搭建Scrapy环境
在本地计算机安装Python后,可以使用pip命令或easy_install命令来安装Scrapy,具体命令格式如下所示。
![](https://epubservercos.yuewen.com/3F131D/17977545801605906/epubprivate/OEBPS/Images/83_01.jpg?sign=1739349984-vNdgxJpp4xVeQAPYYvqMYYMSehfMGaC8-0-8ad5246a9575afcfe61a6f2b60566f4f)
另外,需要确保已安装了“win32api”模块,同时必须安装与本地Python版本相对应的版本和位数(32位或64位)。读者可以登录http://www.lfd.uci.edu/~gohlke/pythonlibs/找到需要的版本,如图3-10所示。
![](https://epubservercos.yuewen.com/3F131D/17977545801605906/epubprivate/OEBPS/Images/83_02.jpg?sign=1739349984-HOXNYhBtcgJxdtGwmHlsNjbVvmbt58mv-0-bcdb74cdb20452bae59dbb5261100ea4)
图3-10 下载“win32api”模块
下载后将得到一个“.whl”格式的文件,定位到此文件的目录,然后通过如下命令安装“win32api”模块。
![](https://epubservercos.yuewen.com/3F131D/17977545801605906/epubprivate/OEBPS/Images/83_03.jpg?sign=1739349984-1lfsA6TqY1tSmRh1NeYLPy91NnMT94OQ-0-8ff3a1192387d5724d4620ffa6c2abcb)
注意:如果遇到“ImportError: DLL load failed: 找不到指定的模块。”错误,需要将“Python\Python35\Lib\site-packages\win32”目录中的如下文件保存到本地系统盘中的“Windows\System32”目录下。
● pythoncom36.dll。
● pywintypes36.dll。
3.3.3 创建第一个Scrapy项目
下面的实例代码演示了创建第一个Scrapy项目的过程。
源码路径:daima\3\3-5\
(1)创建项目
在开始爬取数据之前,必须先创建一个新的Scrapy项目。进入准备存储代码的目录中,然后运行如下所示的命令。
![](https://epubservercos.yuewen.com/3F131D/17977545801605906/epubprivate/OEBPS/Images/84_01.jpg?sign=1739349984-FKOZvGgLbeMRwveJ2yue6kreEmk3zhzK-0-e8db2a6a4ef1d35ac8ccf31ae09729d0)
上述命令的功能是创建一个包含下列内容的“tutorial”目录。
![](https://epubservercos.yuewen.com/3F131D/17977545801605906/epubprivate/OEBPS/Images/84_02.jpg?sign=1739349984-RP0TclQokXmCstKDBDzLEBSvk5L348in-0-fd00b9f7a399ca832f3febd4e466b539)
对上述文件的具体说明如下所示。
● scrapy.cfg:项目的配置文件。
● tutorial/:该项目的python模块,之后在此加入代码。
● tutorial/items.py:项目中的item文件。
● tutorial/pipelines.py:项目中的pipelines文件。
● tutorial/settings.py:项目的设置文件。
● tutorial/spiders/:放置spider代码的目录。
(2)定义Item
Item是保存爬取到的数据的容器,使用方法与Python字典类似,并且提供额外保护机制,避免拼写错误导致未定义的字段错误。在实际应用中可以创建一个scrapy.Item类,并且定义类型为scrapy.Field。
首先需要从dmoz.org获取数据对item进行建模。需要从dmoz中获取名称、url以及网站的描述。对此,在Item中定义相应的字段。编辑“tutorial”目录中的文件items.py,具体实现代码如下所示。
![](https://epubservercos.yuewen.com/3F131D/17977545801605906/epubprivate/OEBPS/Images/84_03.jpg?sign=1739349984-4l2pP9upFPMxRqtmCF366cIpJ7514TbT-0-2ad4c6f6d3673b6c0de1148699e2e97e)
通过定义Item,可以很方便地使用Scrapy中的其他方法。而这些方法需要知道Item的定义。
(3)编写第一个爬虫(Spider)
Spider是用户编写用于从单个网站(或者一些网站)爬取数据的类,其中包含一个用于下载的初始URL,如何跟进网页中的链接和如何分析页面中的内容以及提取生成Item的方法。为了创建一个Spider,必须继承类scrapy.Spider,且定义如下所示的三个属性。
● name:用于区别Spider。该名称必须是唯一的,因此不可以为不同的Spider设定相同的名称。
● start_urls:包含了Spider在启动时进行爬取的url列表。因此,第一个被获取到的页面将是其中之一。后续的URL则从初始的URL获取到的数据中提取。
● parse():spider的一个方法。被调用时,每个初始URL完成下载后生成的Response对象将会作为唯一的参数传递给该方法。它负责解析返回的数据(response data),提取数据(生成Item)以及生成需要进一步处理的URL的Request对象。
下面是我们编写的第一个Spider代码,保存在tutorial/spiders目录下的文件dmoz_spider.py中,具体实现代码如下所示。
![](https://epubservercos.yuewen.com/3F131D/17977545801605906/epubprivate/OEBPS/Images/85_01.jpg?sign=1739349984-G4JezaDykyCKdV4QSDnZR4oSOyhdG2UB-0-9f991a3bc8185244960db13dd5218868)
(4)爬取
进入项目的根目录,执行下列命令启动spider。
![](https://epubservercos.yuewen.com/3F131D/17977545801605906/epubprivate/OEBPS/Images/85_02.jpg?sign=1739349984-D1A6LSj5RtCkiloqnpRfmpQjw2gPJvLt-0-2bdd83dae513f26ee0102180685fe1ad)
crawl dmoz是负责启动用于爬取dmoz.org网站的Spider,之后得到如下所示的输出。
![](https://epubservercos.yuewen.com/3F131D/17977545801605906/epubprivate/OEBPS/Images/85_03.jpg?sign=1739349984-qNGoczUYXWRcdstpc2UAB8yNfk10LZEp-0-2662f5de81fe898ed7bca8bb3f8c6932)
查看包含dmoz的输出,可以看到在输出的log中包含定义在start_urls的初始URL,并且与spider一一对应。在log中可以看到它没有指向其他页面(referer:None)。同时创建两个包含url所对应的内容的文件:Book和Resources。
由此可见,Scrapy为Spider的start_urls属性中的每个URL创建了scrapy.Request对象,并将Parse方法作为回调函数(callback)赋值给Request。Request对象经过调度,执行生成scrapy.http.Response对象并送回给spider parse()方法。
(5)提取Item
有很多种从网页中提取数据的方法,Scrapy使用了一种基于XPath和CSS表达式机制:Scrapy Selectors。关于Selector和其他提取机制的信息,建议读者参考Selector的官方文档。下面给出XPath表达式的例子及对应的含义:
● /html/head/title:选择HTML文档中<head>标签内的<title>元素。
● /html/head/title/text():选择<title>元素的文字。
● //td:选择所有的<td>元素。
● //div[@class="mine"]:选择所有具有class="mine"属性的div元素。
上面仅仅列出了几个简单的XPath例子,XPath的功能实际上要强大很多。为了配合XPath,Scrapy除了提供Selector之外,还提供了多个方法来避免每次从Response中提取数据时生成Selector的麻烦。
在Selector中有如下4个最基本的方法。
● xpath():用于选取指定的标签内容,例如下面的代码表示选取所有的book标签。
![](https://epubservercos.yuewen.com/3F131D/17977545801605906/epubprivate/OEBPS/Images/86_01.jpg?sign=1739349984-P3ZGi4OuSElHfIYbmW8iGo7D33VSQfte-0-f25717b77a795f1c7428d9101c2dd289)
● css():传入CSS表达式,用于选取指定的CSS标签内容。
● extract():返回选中内容的Unicode字符串,返回结果是列表。
● re():根据传入的正则表达式提取数据,返回Unicode字符串格式的列表。
● re_first():返回SelectorList对象中的第一个Selector对象调用的re方法。
使用内置的Scrapy shell,首先需要进入本实例项目的根目录,然后执行如下命令来启动Shell。
![](https://epubservercos.yuewen.com/3F131D/17977545801605906/epubprivate/OEBPS/Images/86_02.jpg?sign=1739349984-SBnujqOiQe2aAcwwXRcRN9aVpCR72LML-0-180e31ce1c016422d9a63778b969dbc2)
此时shell将会输出类似如下所示的内容。
![](https://epubservercos.yuewen.com/3F131D/17977545801605906/epubprivate/OEBPS/Images/86_03.jpg?sign=1739349984-xB8cKmAfmyozPswKC30rW1FE4GpgQrbi-0-64d84c1cfa2905de70c4e52176bb500d)
![](https://epubservercos.yuewen.com/3F131D/17977545801605906/epubprivate/OEBPS/Images/87_01.jpg?sign=1739349984-jvQTYuRSmsvODBSzEV3cVDsb4hdfamTz-0-c636481ef0408a302fb74794c7018d2a)
载入Shell后得到一个包含Response数据的本地Response变量。输入“response.body”命令后会输出Response的包体,输入“response.headers”后可以看到Response的包头。更为重要的是,当输入“response.selector”时,将获取一个可以用于查询返回数据的Selector(选择器),以及映射到response.selector.xpath()、response.selector.css()的快捷方法(shortcut):response.xpath()和response.css()。同时,Shell根据Response提前初始化了变量sel。该Selector根据Response的类型自动选择最合适的分析规则(XML vs HTML)。
(6)提取数据
接下来尝试从这些页面中提取有用数据,只需在终端中输入response.body来观察HTML源码并确定合适的XPath表达式。但这个任务非常无聊且不易,可以考虑使用Firefox的Firebug扩展来简化工作。
查看网页源码后会发现网站的信息被包含在第二个<ul>元素中。可以通过下面的代码选择该页面中网站列表里的所有<li>元素。
![](https://epubservercos.yuewen.com/3F131D/17977545801605906/epubprivate/OEBPS/Images/87_02.jpg?sign=1739349984-P1jEYqESzkiuB0SgwkhJyZU5igpnNqke-0-c256890a7989f73baa21aee174f50932)
通过如下命令获取对网站的描述。
![](https://epubservercos.yuewen.com/3F131D/17977545801605906/epubprivate/OEBPS/Images/87_03.jpg?sign=1739349984-1vm2NyR3ju7F79NO1dutl4vCMhxkeqXz-0-1ae7dfe2bb10a7ec0d118a0a38e0943a)
通过如下命令获取网站的标题。
![](https://epubservercos.yuewen.com/3F131D/17977545801605906/epubprivate/OEBPS/Images/87_04.jpg?sign=1739349984-pcDlrju85zQyXKlq40x0Nm4YAc6xFHVI-0-fbe889f958e1482b374c67326eb6a346)
3.3.4 抓取某电影网的热门电影信息
本实例的功能是,使用Scrapy爬虫抓取某电影网中热门电影信息。
源码路径:daima\3\3-6\
1)在具体爬取数据之前,必须先创建一个新的Scrapy项目。首先进入准备保存项目代码的目录中,然后运行如下所示的命令。
![](https://epubservercos.yuewen.com/3F131D/17977545801605906/epubprivate/OEBPS/Images/87_05.jpg?sign=1739349984-kc9yr4GwDqENO6B1RUZwAj1uaWBiCJIG-0-97adef763f078ea82d6fa69bb28af055)
2)编写文件moviedouban.py设置要爬取的URL范围和过滤规则,主要实现代码如下所示。
![](https://epubservercos.yuewen.com/3F131D/17977545801605906/epubprivate/OEBPS/Images/87_06.jpg?sign=1739349984-FK6qbuJT8EPBrmbw7Ysx3gwVmfUhFpBr-0-73845b139cf18b0b54b0a0217f115add)
![](https://epubservercos.yuewen.com/3F131D/17977545801605906/epubprivate/OEBPS/Images/88_01.jpg?sign=1739349984-bjw03UtqygKegJ5eE0a4zAt8ZEhYmoGz-0-f8a84c6673c48aca5885bb22515ca976)
3)编写执行脚本文件pyrequests_douban.py,功能是编写功能函数获取热门电影的详细信息,包括电影名、URL链接地址、导演信息、主演信息等。文件pyrequests_douban.py的主要实现代码如下所示。
![](https://epubservercos.yuewen.com/3F131D/17977545801605906/epubprivate/OEBPS/Images/88_02.jpg?sign=1739349984-Xm8TEPdQ3X5RXoGvAcdzJYc10adVb6EV-0-4599210db37c393c402c970237951bb0)
![](https://epubservercos.yuewen.com/3F131D/17977545801605906/epubprivate/OEBPS/Images/89_01.jpg?sign=1739349984-80WcRVwPAupkkWetWNjOif4E5VfpTtHF-0-6c812563a534f80ad1258d98ffadb1bd)
![](https://epubservercos.yuewen.com/3F131D/17977545801605906/epubprivate/OEBPS/Images/90_01.jpg?sign=1739349984-Qp0x8O4TLXwDhMZcdy67mVsOr5TTQWDe-0-2591129a3ec15dffc86755651b4f8ef6)
![](https://epubservercos.yuewen.com/3F131D/17977545801605906/epubprivate/OEBPS/Images/91_01.jpg?sign=1739349984-RGz7JjZePAnESDpGHG1Z0pxw09JleFRq-0-e42a74af7ad0e2b8a82448bb72e61980)
执行后会输出显示爬取到的热门电影信息,如图3-11所示。
![](https://epubservercos.yuewen.com/3F131D/17977545801605906/epubprivate/OEBPS/Images/91_02.jpg?sign=1739349984-L2kRf9bMsz4PAaII9589KVQ213KlYzyQ-0-62f4a7c7e683e096b6024ccc7a200cac)
图3-11 爬取到的热门电影信息
3.3.5 抓取某网站中的照片并保存到本地
本实例的功能是使用Scrapy爬虫抓取某网站中的照片信息,并将抓取到的照片保存到本地硬盘中。编写文件art.py设置要爬取的URL范围和抓取的内容元素,主要实现代码如下所示。
源码路径:daima\3\3-7\
![](https://epubservercos.yuewen.com/3F131D/17977545801605906/epubprivate/OEBPS/Images/92_01.jpg?sign=1739349984-uIumfOWmK2bqhc8tWdvBSbNN9Kw6dAKy-0-fb839f2dca323de04fabf5954f1e42be)
执行后会显示抓取目标网站图片的过程,如图3-12所示。
![](https://epubservercos.yuewen.com/3F131D/17977545801605906/epubprivate/OEBPS/Images/92_02.jpg?sign=1739349984-KPkIcubE5WjJAuwazBIKzVejPrnnpe0h-0-8254510fa33fb2968377d0dc94c4bc6e)
图3-12 网站图片抓取过程
将抓取到的照片保存到本地文件夹“download_images”中,如图3-13所示。
![](https://epubservercos.yuewen.com/3F131D/17977545801605906/epubprivate/OEBPS/Images/93_01.jpg?sign=1739349984-afVTD0cGidXk23pou7Ebrbi8uuQ4vW38-0-0c3e5230aa9a6c0159dc3cec205b4fd7)
图3-13 在本地硬盘保存抓取到的图片
3.3.6 抓取某网站中的主播照片并保存到本地
本实例的功能是使用Scrapy爬虫抓取某网站中的主播照片,并将抓取到的主播照片保存到本地硬盘中。编写文件douyu.py设置要爬取的URL范围和抓取的内容元素,设置要抓取的Item(是主播昵称和主播照片)。文件douyu.py的主要实现代码如下所示。
源码路径:daima\3\3-8\
![](https://epubservercos.yuewen.com/3F131D/17977545801605906/epubprivate/OEBPS/Images/93_02.jpg?sign=1739349984-nUktlVkApAfVThyJn7OWTqG9H1b8pOSS-0-b8e96cdd18634ce9e08a306d9b055ab8)
![](https://epubservercos.yuewen.com/3F131D/17977545801605906/epubprivate/OEBPS/Images/94_01.jpg?sign=1739349984-5tuNAL5ajiUPHrRZOtKxqtmmFuxFJhc6-0-ad3126d0abd93d3c3a7aa69694664977)
执行后会将抓取到的主播照片保存到本地文件夹中,如图3-14所示。
![](https://epubservercos.yuewen.com/3F131D/17977545801605906/epubprivate/OEBPS/Images/94_02.jpg?sign=1739349984-QW3qfcRujKYgnV1QnJf4Nigd7s8w4TmI-0-85ab3cb4d12c8f0a3a678238bf7d6db4)
图3-14 抓取到的主播照片