学习自:
Scrapy爬虫框架教程(一)-- Scrapy入门 - 知乎
Scrapy爬虫框架,入门案例(非常详细)_ck784101777的博客-CSDN博客_scrapy爬虫案例
本章介绍Scrapy使用时的基本要素构成。
1、简介
Scrapy最初是为了页面抓取/网络抓取设计的。Scrapy用途广泛,可以应用数据挖掘、监控、自动化测试等领域。
Scrapy吸引人的地方在于它是一个框架,任何人都可以根据需求方便地进行修改。它也提供了多种类型爬虫的基类,如BaseSpider、sitemap爬虫等,最新版本又提供了web2.0爬虫的支持。
2、各组件作用
Scrapy框架主要由五大组件组成,分别是Scrapy引擎(Scrapy Engine)、下载器(Downloader)、Spider、Item Pipeline、调度器(Scheduler)。
①Scrapy Engine
引擎是整个框架的核心,它用来控制、调度Scheduler、Downloader、Spider。
②调度器(Scheduler)
调度器可以视为一个想要进行抓取的URL队列,由它来决定下一个要抓取的网址是什么,同时可以去除重复的网址。用户可以根据自己的需求定制调度器。
③下载器(Downloader)
下载器负责下载页面数据并提供给引擎,而后提供给Spider。Scrapy的下载器代码并不复杂,但是效率很高,这是因为Scrapy下载器是建立在twisted这个高效的异步模型上的。
④Item Pipeline
Item Pipeline负责处理被Spider提取出来的Item。典型的处理有清理多余信息、验证Item有效性及持久化Item(例如存取到数据库中)。
当页面被爬虫解析所需的数据存入Item之后,将会被发送到Pipeline,并经过几个特定的次序处理数据,最后存入本地文件或者存入数据库。
⑤Spider
用户定制自己的爬虫(通过正则表达式等语法),用于从特定的网页中提取自己需要的信息,即Item。用户也可以从中提取出链接,让Scrapy继续抓取下一个页面。
除了以上五种组件,还有另外三个概念(它们与前边五种组件是相互关联的)也需要了解:
①下载器中间件(Downloader middlewares)
下载器中间件是在引擎及下载器之间的特定钩子(Specific hook),处理Downloader传递给引擎的response。它提供了一个简便机制,通过插入自定义代码来扩展Scrapy功能
通过设置下载器中间件可以事先爬虫自动更换User-Agent、IP等功能。
②Spider中间件(Spider middlewares)
Spider中间件是在引擎及Spider之间的特定钩子(Specific hook),处理Spider的输入(Response)和输出(Item及Requests)。
③数据流(Data Flow)
1).Engine打开一个网站,找到处理该网站的Spider并向该Spider请求第一个要爬取的URL(s);
2).Engine从Spider中获取到第一个要爬取的URL,将其放入Scheduler的URL队列中;
3).Engine向Scheduler请求下一个要爬取的URL;
4).Scheduler返回下一个要爬取的URL给Engine,Engine将URL发送给Downloader;
5)、6).Downloader访问Internet,下载页面;
7).Downloader生成一个该页面的Response,并将其发送给Engine;
8).Engine将Response发送给Spider处理;
9).Spider处理Response并返回爬取到的Item及新URL给Engine,重复上述流程直到URL队列中没有多余URL;
10).Engine将爬取到的Item发送到Item Pipeline。
将整个流程可视化,可以得到如下流程图,该图是按照上文数据流中的顺序进行的。
官方架构图:图中的绿线是数据流向。
3、一些类、文件的作用
①类
1)Spider
class scrapy.spider.Spider
Spider是最简单的spider。每个其他的spider都必须继承自该类(包括Scrapy自带的其他spider以及我们自己编写的spider)。Spider没有提供其他特殊的功能,其作用为1)区分请求给定的start_urls/start_requests;2)根据response调用parse方法。
属性:
name:spider名字的字符串。spider的名字定义了Scrapy如何开始定位(并初始化)spider,所以其必须是唯一的。如果该spider爬取单个网站,一个常见的做法是以该网站名来命名spider。例如spider要爬取mywebsite.com,该spider通常会被命名为mywebsite。
allowed_domains:可选。包含了spider允许爬取的URL List。当OffsiteMiddleware启用时,不在List中指定URL及其子URL中的URL将不会被跟进(即爬取的URL必须与该List中的URL有相同的前缀)。
start_urls:URL List。当没有特定的URL时,spider将从该List中开始进行爬取。因此,第一个被获取到的页面的URL必将是该List其中之一,后续URL将会从获取到的数据中提取。
方法:
start_requests():该方法必须返回一个Iterable。该Iterable包含了spider用于爬取的第一个Request。当spider启动爬取且并未制定URL时,该方法将会被调用。该方法的默认实现是使用start_urls的URL来生成Request。如果我们想要修改最初爬取某个网站的Request对象,那么可以重写该方法。例如,如果我们需要在启动时以POST的方式登录某个网站,可以这么写
def start\_requests(self):
return \[scrapy.FormRequest('http://www.example.com/login',
formdata={'user': 'john', 'pass': 'secret'},
callback=self.logged\_in)\]
def logged\_in(self,response):
pass
默认未被重写的情况下,该方法返回的Request对象中,parse()作为回调函数,dont_filter参数也被设置为开启。(详情见Reueqst)
make_requests_from_url(url):当spider启动且指定了URL时,该方法将会被调用,且仅仅会被调用一次,因此我们可以将之实现为Generator。该方法接受一个URL并返回用于爬取的Request对象。该方法在初始化Requests时被start_requests调用,也被用于转化URL为Request。
parse(response):当Response没有指定回调函数时,该方法是Scrapy处理下载的Response的默认方法。该方法负责处理Response并返回处理的数据以及跟进的URL。spider对其他的Request的回调函数也有相同的要求。关于返回值,该方法及其他Request回调函数必须返回一个包含Request或Item的Iterable。
参数:response:用于分析的Response
log(message [ ,level , commponent ] ):使用scrapy.log.msg()方法记录(log)message。log中自动带上该spider的name属性。更多数据可以参见Logging。
closed(reason):当spider关闭时,该方法被调用。该方法用于替代signals.connect()来监听spider_closed信号的快捷方式。
以上是最简单的Spider,此外还有其他Spider:Spiders — Scrapy 2.5.0 documentation
2)CrawlSpider
用于爬取URL具有一定规律的网页
3)Response
Scrapy中的response对象的属性、方法
属性
说明
类型
url
HTTP响应的URL
str
status
响应状态码
int
headers
响应头部,可以用get或getlist方法访问
类Dict
body
响应正文
bytes
text
文本形式的响应正文
response.text = response.body.decode(response.encoding)
str
encoding
响应正文的编码
request
产生该响应的Request对象
meta
即response.request.meta,在构造Request对象时,可以将传递给响应处理函函数的信息通过meta参数传入;响应处理函数处理相应时,通过response.meta将信息提取出来
selector
Selector对象用于在Response中提取数据
方法
说明
xpath(query)
根据XPath路径表达式提取要素
css(query)
根据CSS语法提取要素
urljoin(url)
用于构造绝对url,当传入的url是一个相对地址时,根据response.url计算出相应的绝对url
②文件
通过指令scrapy startproject S创建项目后,会生成以下的文件结构:
S--->scrapy.cfg #项目的配置文件
S--------> #该项目的Python模块。之后你将在此加入代码
__init__.py
items.py #项目中的Item文件
pipelines.py #Pipelines文件
settings.py #设置文件
spiders---> #放置Spider代码的目录
__init__.py
xxx.py #Spider代码
除了目录名S和Spider文件名是我们自定义的外,其他文件都是自动生成的,其中最关键的是pipelines.py和settings.py
1)items.py
存放需要提取元素名。
2)settings.py
BOT_NAME:项目名。
USER_AGENT:该项默认是注释掉的,但是由于现在的网站访问时都需要User-Agent,所以需要我们手动填充该项。
ROBOTSTXT_OBEY:是否遵循机器人协议,默认True,需要修改为False,否则很多东西爬不了(该项待验证)。
CONCURRENT_REQUESTS:最大并发数;同时允许开启多少个爬虫线程。
DOWNLOAD_DELAY:下载延迟时间;单位s,默认3s,即爬一个停3s。有的网站可能会对下载过快的情况进行侦测,从而判断出是爬虫并加以拒绝。
COOKIES_ENABLED:是否保存COOKIES;默认关,开启后可以记录爬取过程中的COOKIE。
DEFAULT_REQUEST_HEADERS:默认请求头;之前我们写了一个USER_AGENT,其实该项就是放在请求头中的。
ITEM_PIPELINES:项目管道;300为优先级,越低爬取的优先级越高。比如我的pipelines.py中写了两个pipeline,一个爬取网页的管道,另一个存数据库的管道,我调整了它们的优先级,如果有爬虫数据,则优先执行库存操作(如果items.py中有需要运行的代码,则该项必须声明)
ITEM_PIPELINES = {
'S.pipelines.BaiduPipeline' : 300,
'S.pipelines.BaiduMysqlPipeline':200
}
该Dict中的两个Key需要均是在要在pipelines.py事先定义好的两个类:
class BaiduPipeline(object):
#爬取网页
def process_item(self,item,spider):
return item
class BaiduMysqlPipeline(object):
#将爬取内容存入数据库
def process_item(self,item,spider):
return item
LOG_LEVEL:日志等级;日志登记分级见下表
DEBUG
调试信息
INFO
一般信息
WARNING
警告
ERROR
普通错误
CRITICAL
严重错误
默认为'DEBUG',即所有信息都会被记录进日志中,如果设置为WARNING,则只会记录WARNING、ERROR和CRITICAL
LOG_FILE:日志文件名;格式为 '日志名.log'
3.5、建立Scrapy爬虫项目的流程
创建爬虫和运行爬虫时,要在cmd中用到三段指令:
scrapy startproject 项目名
scrapy genspider 爬虫名 域名
scrapy crawl 爬虫名
其中前两句分别是创建项目和创建爬虫,而创建爬虫也可以通过第②部分中的中的name和start_urls进行创建。
第三句话是爬虫构建好之后,运行爬虫的命令。
①创建项目
在开始爬取之前,需要建立一个新的Scrapy项目。
进入你打算存储代码的目录中,运行以下命令
scrapy startproject 项目名
cd 项目名
scrapy genspider 爬虫名 URL
②编写爬虫代码
Spider是用户编写的用于从网站爬取数据的类。
其包含了一个用于下载初始URL,如何跟进网页中的链接及如何分析页面中的内容,提取生成Item的方法。
为了创建一个Spider,你必须继承scrapy.Spider类,且定义以下三个属性及方法
name:用于区别不同的Spider。
start_urls:包含了Spider在启动时进行爬取的URL列表。因此,第一个被获取到的页面将是其中之一。后续的URL则从初始URL获取到的数据中心提取。
parse():Spider的一个方法。被调用时,每个初始URL完成下载后生成的Response对象将作为唯一的参数传递给该函数。该方法负责解析返回的数据(response data),提取数据(生成Item)以及生成需要进一步处理的URL的Request对象。
③启动爬虫
打开终端进入项目所在文件夹中,运行命令:
scrapy crawl woodenrobo
启动爬虫后就可以看到打印出来当前页所有的文章标题了。
可以把爬取到的内容导出为JSON或者CSV格式,方法是在执行爬虫指令时加入参数-o:
scrapy crawl 爬虫名 -o 文件名.csv
scrapy crawl 爬虫名 -o 文件名.json
对于JSON文件,需要在setting.py文件中设置编码格式,否则会乱码:
FEED_EXPORT_ENCODING = 'UTF-8'
启动爬虫时的程序运行流程:
Scrapy为Spider的start_urls属性中的每个URL创建了Request对象,并将parse方法作为回调函数赋值给requests,而requests对象经过Scheduler的调度,执行生成response对象并送回给parse()方法进行解析,所以url的改变是靠回调函数实现的。
yield scrapy.Request(self.url,callback=self.parse)
4、实例
①提取百度首页的标题title
现在看第一个Spider代码,保存位置为S2\Spiders目录下,名字取为baidu.py,目的是使用XPath提取百度首页的标题title
import scrapy
class BaiduSpider(scrapy.Spider):
name = 'baidu'
allowed_domains = ['www.baidu.com']
start_urls = ['http://www.baidu.com/']
def parse(self, response):
tile=response.xpath('//html/head/title/text()')
print(tile)
打开cmd终端,输入
scrapy crawl baidu
就可以看到一大堆输出信息,其中就包含了我们需要的内容。
然而,使用终端运行太麻烦了,而且不能提取数据,我们写一个运行文件作为程序的入口:
from scrapy import cmdline
cmdline.execute('scrapy crawl baidu'.split())
这段话可以写在另一个py文件或者spider.py文件中,直接运行这句话所在的py文件就可以了。
②爬取腾讯视频中的电影信息
1)
创建项目,将爬虫项目命名为TX;
创建爬虫,爬虫命名为txms,爬虫的start_url设置为v.qq.com
scrapy startproject TX
cd TX
scrapy genspider txs v.qq.com
2)修改setting
修改三项:
ROBOTSTXT_OBEY:机器人项
DOWNLOAD_DELAY:下载间隙
DEFAULT_REQUEST_HEADERS:请求头,需要添加一个User-Agent
ROBOTSTXT_OBEY = False
DOWNLOAD_DELAY = 1
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 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.94 Safari/537.36'
}
3)确认要提取的数据,Item项
Item定义你要提取的内容(定义数据结构),比如我提取的内容为电影名和电影描述,我就创建两个变量(每有一个需要提取的内容,就要在items.py中新建一个变量)。Field方法实际上是创建一个Dict,给Dict添加一个Key,暂时不赋值,等待提取数据后再赋值。
下面的Item结构可以表示为:{ 'name':'' ; 'description':'' }
#items.py
import scrapy
class TXItem(scrapy.Item):
name=scrapy.Field()
description=scrapy.Field()
4)写爬虫程序
我们要写的部分是parse方法中的内容,重点在于如何写XPath。
我们要爬取的网页的URL为https://v.qq.com/channel/movie,页面如下:
from scrapy import Request
from scrapy import Spider
from TX.items import TXItem
class TxsSpider(Spider):
name = 'txs'
allowed_domains = ['v.qq.com']
start_urls = ['https://v.qq.com/channel/movie']
def parse(self, response):
item=TXItem()
movies=response.xpath('//div\[@id="movie\_v3\_new"\]//div\[@class="list\_item "\]')
for movie in movies:
item\['name'\]=movie.xpath('.//div/a/text()').extract()\[0\]
item\['description'\]=movie.xpath('.//div/div/text()').extract()\[0\]
yield item
5)、运行爬虫,保存爬取到的数据
scrapy crawl tms -o TX.csv
这一部分代码的解释,请看Scrapy(二)最后一部分
手机扫一扫
移动阅读更方便
你可能感兴趣的文章