初窥Scrapy

Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架。 可以应用在包括数据挖掘,信息处理或存储历史数据等一系列的程序中。

其最初是为了 网络抓取 所设计的, 也可以应用在获取API所返回的数据(例如 Amazon Associates Web Services 或者通用的网络爬虫。

Scrapy 使用了 Twisted异步网络库来处理网络通讯。整体架构大致如下
Scrpy原理

Scrapy主要包括了以下组件:

  • 引擎(Scrapy) :用来处理整个系统的数据流, 触发事务(框架核心)
  • 调度器(Scheduler) :用来接受引擎发过来的请求, 压入队列中, 并在引擎再次请求的时候返回. 可以想像成一个URL(抓取网页的网址或者说是链接)的优先队列, 由它来决定下一个要抓取的网址是什么, 同时去除重复的网址
  • 下载器(Downloader) :用于下载网页内容, 并将网页内容返回给蜘蛛(Scrapy下载器是建立在twisted这个高效的异步模型上的)
  • 爬虫(Spiders) :爬虫是主要干活的, 用于从特定的网页中提取自己需要的信息, 即所谓的实体(Item)。用户也可以从中提取出链接,让Scrapy继续抓取下一个页面
  • 项目管道(Pipeline) :负责处理爬虫从网页中抽取的实体,主要的功能是持久化实体、验证实体的有效性、清除不需要的信息。当页面被爬虫解析后,将被发送到项目管道,并经过几个特定的次序处理数据。
  • 下载器中间件(Downloader Middlewares) :位于Scrapy引擎和下载器之间的框架,主要是处理Scrapy引擎与下载器之间的请求及响应。
  • 爬虫中间件(Spider Middlewares) :介于Scrapy引擎和爬虫之间的框架,主要工作是处理蜘蛛的响应输入和请求输出。
  • 调度中间件(Scheduler Middewares) :介于Scrapy引擎和调度之间的中间件,从Scrapy引擎发送到调度的请求和响应。

Scrapy运行流程大概如下:

  1. 引擎从调度器中取出一个链接(URL)用于接下来的抓取
  2. 引擎把URL封装成一个请求(Request)传给下载器
  3. 下载器把资源下载下来,并封装成应答包(Response)
  4. 爬虫解析Response
  5. 解析出实体(Item),则交给实体管道进行进一步的处理
  6. 解析出的是链接(URL),则把URL交给调度器等待抓取

搭建Scrapy环境

新建虚拟环境

python3 -m venv /data/code/python/venv/venv_Scrapy

升级pip

/data/code/python/venv/venv_Scrapy/bin/pip3 install --upgrade pip

pip安装Scrapy

/data/code/python/venv/venv_Scrapy/bin/pip3 install Scrapy

创建项目

新建Scrapy项目tutorial

#进入虚拟环境
cd /data/code/python/venv/venv_Scrapy/
#新建项目tutorial
./bin/python3  ./bin/scrapy startproject tutorial

tutorial项目结构

tutorial/
├── tutorial
│   ├── __init__.py
│   ├── items.py
│   ├── middlewares.py
│   ├── pipelines.py
│   ├── settings.py
│   └── spiders
│       └── __init__.py
└── scrapy.cfg

其中:

genspider命令新建爬虫

genspider语法

  • 语法: scrapy genspider [-t template] <name> <domain>

新建百度爬虫

#进入虚拟环境
cd /data/code/python/venv/venv_Scrapy/
#新建百度爬虫
../bin/python3 ../bin/scrapy genspider -t basic baidu_search www.baidu.com

baidu_search.py

# -*- coding: utf-8 -*-
import scrapy


class BaiduSearchSpider(scrapy.Spider):
    name = 'baidu_search'
    allowed_domains = ['www.baidu.com']
    start_urls = ['http://www.baidu.com/']

    def parse(self, response):
        pass

scrapy.Spider

class scrapy.spiders.Spider

Spider是最简单的spider。每个其他的spider必须继承自该类(包括Scrapy自带的其他spider以及您自己编写的spider)。 Spider并没有提供什么特殊的功能。 其仅仅提供了 start_requests()的默认实现,读取并请求spider属性中的 start_urls, 并根据返回的结果(resulting responses)调用spider的 parse方法。

  • name
    定义spider名字的字符串(string)。spider的名字定义了Scrapy如何定位(并初始化)spider,所以其必须是唯一的。 不过您可以生成多个相同的spider实例(instance),这没有任何限制。 name是spider最重要的属性,而且是必须的。
    如果该spider爬取单个网站(single domain),一个常见的做法是以该网站(domain)(加或不加 后缀 )来命名spider。 例如,如果spider爬取 mywebsite.com ,该spider通常会被命名为 mywebsite 。

  • allowed_domains
    可选。包含了spider允许爬取的域名(domain)列表(list)。 当 OffsiteMiddleware 启用时, 域名不在列表中的URL不会被跟进。

  • start_urls
    URL列表。当没有指定特定的URL时,spider将从该列表中开始进行爬取。 因此,第一个被获取到的页面的URL将是该列表之一。 后续的URL将会从获取到的数据中提取。

crawl开始爬虫

  • 语法: scrapy crawl <spider>
#进入虚拟环境
cd /data/code/python/venv/venv_Scrapy/
#crawl开始爬虫
../bin/python3 ../bin/scrapy crawl baidu_search

Forbidden by robots.txt

2018-12-05 13:15:04 [scrapy.utils.log] INFO: Scrapy 1.5.1 started (bot: tutorial)
2018-12-05 13:15:04 [scrapy.utils.log] INFO: Versions: lxml 4.2.5.0, libxml2 2.9.8, cssselect 1.0.3, parsel 1.5.1, w3lib 1.19.0, Twisted 18.9.0, Python 3.7.0 (v3.7.0:1bf9cc5093, Jun 26 2018, 23:26:24) - [Clang 6.0 (clang-600.0.57)], pyOpenSSL 18.0.0 (OpenSSL 1.1.0j  20 Nov 2018), cryptography 2.4.2, Platform Darwin-16.7.0-x86_64-i386-64bit
2018-12-05 13:15:04 [scrapy.crawler] INFO: Overridden settings: {'BOT_NAME': 'tutorial', 'DUPEFILTER_CLASS': 'scrapy_splash.SplashAwareDupeFilter', 'HTTPCACHE_STORAGE': 'scrapy_splash.SplashAwareFSCacheStorage', 'NEWSPIDER_MODULE': 'tutorial.spiders', 'ROBOTSTXT_OBEY': True, 'SPIDER_MODULES': ['tutorial.spiders']}
2018-12-05 13:15:04 [scrapy.middleware] INFO: Enabled extensions:
['scrapy.extensions.corestats.CoreStats',
 'scrapy.extensions.telnet.TelnetConsole',
 'scrapy.extensions.memusage.MemoryUsage',
 'scrapy.extensions.logstats.LogStats']
2018-12-05 13:15:04 [scrapy.middleware] INFO: Enabled downloader middlewares:
['scrapy.downloadermiddlewares.robotstxt.RobotsTxtMiddleware',
 'scrapy.downloadermiddlewares.httpauth.HttpAuthMiddleware',
 'scrapy.downloadermiddlewares.downloadtimeout.DownloadTimeoutMiddleware',
 'scrapy.downloadermiddlewares.defaultheaders.DefaultHeadersMiddleware',
 'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware',
 'scrapy.downloadermiddlewares.retry.RetryMiddleware',
 'scrapy.downloadermiddlewares.redirect.MetaRefreshMiddleware',
 'scrapy.downloadermiddlewares.redirect.RedirectMiddleware',
 'scrapy.downloadermiddlewares.cookies.CookiesMiddleware',
 'scrapy_splash.SplashCookiesMiddleware',
 'scrapy_splash.SplashMiddleware',
 'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware',
 'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware',
 'scrapy.downloadermiddlewares.stats.DownloaderStats']
2018-12-05 13:15:04 [scrapy.middleware] INFO: Enabled spider middlewares:
['scrapy.spidermiddlewares.httperror.HttpErrorMiddleware',
 'scrapy_splash.SplashDeduplicateArgsMiddleware',
 'scrapy.spidermiddlewares.offsite.OffsiteMiddleware',
 'scrapy.spidermiddlewares.referer.RefererMiddleware',
 'scrapy.spidermiddlewares.urllength.UrlLengthMiddleware',
 'scrapy.spidermiddlewares.depth.DepthMiddleware']
2018-12-05 13:15:04 [scrapy.middleware] INFO: Enabled item pipelines:
['tutorial.pipelines.QQVideoCommentPipeline']
2018-12-05 13:15:04 [scrapy.core.engine] INFO: Spider opened
2018-12-05 13:15:04 [scrapy.extensions.logstats] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min)
2018-12-05 13:15:04 [scrapy.extensions.telnet] DEBUG: Telnet console listening on 127.0.0.1:6023
2018-12-05 13:15:04 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://www.baidu.com/robots.txt> (referer: None)
2018-12-05 13:15:04 [scrapy.downloadermiddlewares.robotstxt] DEBUG: Forbidden by robots.txt: <GET http://www.baidu.com/>
2018-12-05 13:15:05 [scrapy.core.engine] INFO: Closing spider (finished)
2018-12-05 13:15:05 [scrapy.statscollectors] INFO: Dumping Scrapy stats:
{'downloader/exception_count': 1,
 'downloader/exception_type_count/scrapy.exceptions.IgnoreRequest': 1,
 'downloader/request_bytes': 281,
 'downloader/request_count': 1,
 'downloader/request_method_count/GET': 1,
 'downloader/response_bytes': 677,
 'downloader/response_count': 1,
 'downloader/response_status_count/200': 1,
 'finish_reason': 'finished',
 'finish_time': datetime.datetime(2018, 12, 5, 5, 15, 5, 55729),
 'log_count/DEBUG': 3,
 'log_count/INFO': 7,
 'memusage/max': 53755904,
 'memusage/startup': 53755904,
 'response_received_count': 1,
 'scheduler/dequeued': 1,
 'scheduler/dequeued/memory': 1,
 'scheduler/enqueued': 1,
 'scheduler/enqueued/memory': 1,
 'start_time': datetime.datetime(2018, 12, 5, 5, 15, 4, 737516)}
2018-12-05 13:15:05 [scrapy.core.engine] INFO: Spider closed (finished)

首次开启爬虫,可能会遇到Forbidden by robots.txt

robots协议

Robots协议(也称为爬虫协议、机器人协议等)的全称是“网络爬虫排除标准”(Robots Exclusion Protocol),网站通过Robots协议告诉搜索引擎哪些页面可以抓取,哪些页面不能抓取。

访问一下 https://www.baidu.com/robots.txt
最后我们可以看见

.....
User-agent: *
Disallow: /

简单来说,就是百度禁止一切爬虫。当然,尊不遵守君子协定就看你个人了。我们这里先到 settings.py 禁止掉

ROBOTSTXT_OBEY

编辑 settings.py 修改以下设置

# Obey robots.txt rules
ROBOTSTXT_OBEY = False

爬取百度首页

这里我们修改 baidu_search.py 打印百度首页

# -*- coding: utf-8 -*-
import scrapy


class BaiduSearchSpider(scrapy.Spider):
    name = 'baidu_search_'
    allowed_domains = ['www.baidu.com']
    start_urls = ['http://www.baidu.com/']

    def parse(self, response):
        print(response.text)

再次运行,就可以看到我们已经拿到了百度的首页了

../bin/python3 ../bin/scrapy crawl baidu_search

附录

Scrapy 1.0 文档

GitHub源码

猜你喜欢

转载自blog.csdn.net/weixin_43430036/article/details/84831795