本文主要是介绍09—小白学Python爬虫之Scrapy快速入门与实战,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
从本篇起,将学习一下Scrapy爬虫框架,以及如何通过该框架实现定向爬虫。Scrapy是一个非常优秀的框架,操作简单,扩展方便,是比较流行的爬虫解决方案。
初识
Scrapy是使用Python编写的Crawler Framework,简单轻巧,其使用Twisted异步库来处理网络通信,架构清晰,并且包含了各种中间件接口,可以灵活的完成各种需求。
架构及组件
首先看一下Scrapy的整体架构图(绿线是数据流向),如下:
根据架构图介绍一下Scrapy中各大组件及其功能:
- Scrapy引擎(Engine)
:负责Spider
ItemPipeline
Downloader
Scheduler
之间的通讯、数据传递等
- 调度器(Scheduler)
:负责接受引擎发送过来的Request请求,并按照一定的方式进行整理排列,加入队列,当引擎需要时,交还给引擎
- Downloader(下载器)
:负责下载引擎发送过来的所有Request请求,并将其获取到的Responses交还给引擎,由引擎交给Spider
来处理
- Spider(爬虫)
:负责处理所有Responses,从中分析提取数据,获取Item
字段需要的数据,并将需要跟进的URL提交给引擎,再次进入Scheduler(调度器)
- ItemPipeline(管道)
:负责处理Spider
中获取的Item
,并进行后期处理,比如详细分析、过滤、存储等
- 下载器中间件(Downloader middlewares)
:是在引擎及下载器之间的特定钩子(specific hook)
,处理Downloader传递给引擎的Response,可以自定义扩展下载功能
- Spider Middlewares(Spider中间件)
:是在引擎与Spider
之间的特定钩子,可以自定义扩展通信功能,比如进入Spider
的Responses和从Spider
出去的Requests
Scrapy工作流程
官方版
- 引擎打开一个网站
(open a domain)
,找到处理该网站的Spider
,并向该Spider
请求第一个要爬取的URL - 引擎从
Spider
中获取到第一个要爬取的URL并通过调度器(Scheduler)
以及Request
进行调度 - 引擎向调度器请求下一个要爬取的URL
- 调度器返回下一个要爬取的URL给引擎,引擎将URL通过下载中间件
(请求request方向)
转发给下载器(Downloader)
- 一旦页面下载完毕,下载器会生成该页面的Response,并将其通过下载中间件
(返回response方向)
发送给引擎 - 引擎从下载器中接收到Response并通过
Spider
中间件(输入方向)发送给Spider
处理 Spider
处理Response并返回爬取到的Item
以及使用有需要跟进的新的Request给引擎- 引擎将(
Spider
返回的)Item
交给Item Pipeline
,将(Spide
r返回的)Request给调度器 - (从第二步)重复直到调度器中没有Request,引擎关闭该网站
白话版
引擎
:Hi!Spider, 你要处理哪一个网站?Spider
:老大要我处理xxxx.com。引擎
:你把第一个需要处理的URL给我吧。Spider
:给你,第一个URL是xxxxxxx.com。引擎
:Hi!调度器,我这有request请求你帮我排序入队一下。调度器
:好的,正在处理你等一下。引擎
:Hi!调度器,把你处理好的request请求给我。调度器
:给你,这是我处理好的request引擎
:Hi!下载器,你按照老大的下载中间件的设置帮我下载一下这个request请求下载器
:好的!给你,这是下载好的东西。(如果失败:sorry,这个request下载失败了。然后引擎告诉调度器,这个request下载失败了,你记录一下,我们待会儿再下载)引擎
:Hi!Spider,这是下载好的东西,并且已经按照老大的下载中间件处理过了,你自己处理一下(注意!这儿responses默认是交给def parse()这个函数处理的)Spider
:(处理完毕数据之后对于需要跟进的URL),Hi!引擎,我这里有两个结果,这个是我需要跟进的URL,还有这个是我获取到的Item数据。引擎
:Hi !管道 我这儿有个item你帮我处理一下!调度器!这是需要跟进URL你帮我处理下。然后从第四步开始循环,直到获取完老大需要全部信息。管道
And调度器
:好的,现在就做!
只有当调度器中不存在任何request了,整个程序才会停止。(也就是说,对于下载失败的URL,Scrapy也会重新下载。)
安装
Windows安装
- 安装
pywin32
,点我下载,下载响应版本的pywin32
,双击安装即可。 - 安装
pyOpenSSL
,源码下载,下载完成后,运行python setup.py install
安装即可 - 安装
lxml
,使用pip install lxml
,如果提示Microsoft Visual C++
库没安装,则需要下载响应支持的库,点我下载。 - 安装
Scrapy
,使用pip install Scrapy
。
Linux(macOS)
Linux下绝大部分版本都预装了Python环境,而且还预装了lxml和OpenSSL,所有直接使用pip install Scrapy
安装即可。
接下来,会发现,安装了如下包:
Installing collected packages: six, w3lib, cssselect, parsel, pycparser, cffi, asn1crypto, cryptography, pyOpenSSL, PyDispatcher, zope.interface, constantly, incremental, attrs, Automat, hyperlink, Twisted, queuelib, pyasn1, pyasn1-modules, service-identity, Scrapy
Successfully installed Automat-0.6.0 PyDispatcher-2.0.5 Scrapy-1.5.0 Twisted-17.9.0 asn1crypto-0.24.0 attrs-17.4.0 cffi-1.11.5 constantly-15.1.0 cryptography-2.2.2 cssselect-1.0.3 hyperlink-18.0.0 incremental-17.5.0 parsel-1.4.0 pyOpenSSL-17.5.0 pyasn1-0.4.2 pyasn1-modules-0.2.1 pycparser-2.18 queuelib-1.5.0 service-identity-17.0.0 six-1.11.0 w3lib-1.19.0 zope.interface-4.4.3
点我查看官方各平台安装方法
入门实战
目标
- 创建一个Scrapy项目
- 定义提取的结构化数据(Item)
- 编写爬取网站的Spider并提取结构化数据(Item)
- 编写Item Pipelines存储提取到的Item
新建项目(scrapy startproject)
- 在开始爬取之前,先创建新的Scrapy项目。进入目标项目目录后,执行以下命名:
scrapy startproject novelSpider
- 其中
novelSpider
为项目名称,可以看到会在当前目录下创建novelSpider文件夹,目录结构如下:
- 简单介绍一下各文件作用:
scrapy.cfg
:项目的配置文件novelSpider/
:项目的python模块,将会从这里引用代码novelSpider/items.py
:项目的目标文件novelSoider/pipelines.py
:项目的管道文件novelSpider/settings.py
:项目的设置文件novelSpider/spiders
:存储爬虫代码目录
明确目标(novelSpider/items.py)
在此,我们打算抓取http://www.jjwxc.net/topten.php?orderstr=13
中小说的序号、作者、类型、进度等信息。
- 打开
novelSpider
目录下的items.py
- Item定义结构化数据字段,用来保存爬取到的数据,有点像Python中的dict,但提供了一些额外的保护减少错误
- 创建一个
scrapy.Item
类,并定义类型为scrapy.Field
的类属性来定义一个Item - 接下来,创建
NovalItem
类和构建item模型(model)
import scrapy
class NovelItem(scrapy.Item):id = scrapy.Field()author = scrapy.Field()title = scrapy.Field()type = scrapy.Field()style = scrapy.Field()process = scrapy.Field()date = scrapy.Field()
制作爬虫(spiders/novel.py)
爬数据
上一步在调用scrapy startproject novelSpider
时,曾提示我们:
You can start your first spider with:cd novelSpiderscrapy genspider example example.com
接下来,就用到这个提示了。首先cd novelSpider
进入小说爬虫目录,执行如下命令:
scrapy genspider novel "jjwxc.net"
- 打开
novelSpider/spiders
目录中的novel.py
,默认增加了如下代码:
# -*- coding: utf-8 -*-
import scrapyclass NovelSpider(scrapy.Spider):name = 'novel'allowed_domains = ['jjwxc.net']start_urls = ['http://jjwxc.net/']def parse(self, response):pass
其实我们也可以自行创建novel.py
并编写上面代码,只不过使用命令可以免去编写固定代码的麻烦。
建立一个Spider,必须使用scrapy.Spider
类创建一个子类,并确定三个属性和一个方法:
name = ""
:爬虫的唯一标识,不可重复allowed_domains = []
:爬虫搜索的域名范围,只能在该域名下进行爬取start_urls = []
:爬取的URL元祖或列表。从这里开始抓取数据,也就是第一次下载的数据会从这些urls开始,其他子URL会从起始URL中继承性生成parse(self,response)
:解析方法,每个URL下载完成后被调用,传入Response对象作为参数,主要用来解析返回的网页数据(response.body
),提取结构化数据(Item
),生成下一页URL请求
在此,将start_urls
的值修改为爬取的第一个url:
start_urls = ['http://www.jjwxc.net/topten.php?orderstr=13']
- 修改parse方法
def parse(self, response):filename = 'novel.html'with open(filename, 'w') as f:f.write(response.body.decode(response.encoding))
- 运行抓取,执行如下命令
scrapy crawl novel
novel
就是我们生成的唯一爬虫名。
运行之后,打印的日志出现[scrapy.core.engine] INFO: Spider closed (finished)
,代表执行完成。当前文件夹会出现一个novel.html
文件,内容就是爬取网页的全部源代码信息。
取数据
- 引入在
novelSpider/items.py
中定义的NovelItem
类
from novelSpider.items import NovelItem
- 分析html内容,查询目标内容,把数据封装到
NovelItem
对象中
# -*- coding: utf-8 -*-
import scrapy
from novelSpider.items import NovelItemclass NovelSpider(scrapy.Spider):name = 'novel'allowed_domains = ['jjwxc.net']start_urls = ['http://www.jjwxc.net/topten.php?orderstr=13']def parse(self, response):content = response.body.decode(response.encoding)# filename = 'novel.html'# with open(filename, 'w') as f:# f.write(content)# bgcolor #eefaeenovelList = []for item in response.xpath('//tr[@bgcolor="#eefaee"]'):id = item.xpath('td')[0].xpath('text()').extract()author = item.xpath('td')[1].xpath('a/text()').extract()title = item.xpath('td')[2].xpath('a/text()').extract()type = item.xpath('td')[3].xpath('text()').extract()style = item.xpath('td')[4].xpath('text()').extract()date = item.xpath('td')[8].xpath('text()').extract()# print(id, author, title, type, style, date)novelItem = NovelItem()novelItem['num'] = id[0]novelItem['author'] = author[0]novelItem['title'] = title[0]novelItem['type'] = type[0]novelItem['style'] = style[0]novelItem['date'] = date[0]novelList.append(novelItem)return novelList
- 暂时先不处理管道,后面再详细介绍
保存数据
scray保存信息主要有四种,-o
输出指定格式的文件,命令如下:
# json格式,默认为Unicode编码啊
scrapy crawl novel -o novels.json# json lines格式,默认为Unicode编码啊
scrapy crawl novel -o novels.jsonlines# json格式,默认为Unicode编码啊
scrapy crawl novel -o novels.json# xml格式
scrapy crawl novel -o novels.xml
好了,scrapy的基本介绍就到这了,有一个小问题,在parse
方法中,我们使用的是return items
,如果换成yield
会有什么区别和不同呢?请听下回分解。
这篇关于09—小白学Python爬虫之Scrapy快速入门与实战的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!