Fork me on GitHub

scrapy架构简介与基本操作

不求与人相比,但求超越自己,要哭就哭出激动的泪水,要笑就笑出成长的性格!

scrapy处理的大致流程

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

其最初是为了页面抓取 (更确切来说, 网络抓取 )所设计的, 也可以应用在获取API所返回的数据(例如 Amazon Associates Web Services ) 或者通用的网络爬虫。Scrapy用途广泛,可以用于数据挖掘、监测和自动化测试

Scrapy主要包括了以下组件:

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

Scrapy运行流程大概如下:

  • 首先,引擎从调度器中取出一个链接(URL)用于接下来的抓取
  • 引擎把URL封装成一个请求(Request)传给下载器,下载器把资源下载下来,并封装成应答包(Response)
  • 然后,爬虫解析Response
  • 若是解析出实体(Item),则交给实体管道进行进一步的处理。
  • 若是解析出的是链接(URL),则把URL交给Scheduler等待抓取

如何使用?

运行scrapy startproject tutorial(名称自己定)
运行scrapy genspider example example.com
可以看到生成了如下目录结构:

1
2
3
4
5
6
7
8
9
10
11
├── tutorial
├── scrapy.cfg
└── tutorial
├── __init__.py
├── middlewares.py
├── items.py
├── pipelines.py
├── settings.py
└── spiders
└── example.py
└── __init__.py

目录解析:

  • items.py用来保存数据的结构
  • middlewares.py爬取过程中用来处理request,response,exception的操作
  • pipelines.py项目管道,用来处理item数据
  • settings.py配置信息
  • 主要代码在spiders下的example.py编写解析规则

scrapy的选择器示例

Example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<html>
<head>
<base href='[http://example.com/'](http://example.com/'); />
<title>Example website</title>
</head>
<body>
<div id='images'>
<a href='image1.html'>Name: My image 1 <br /><img src='image1_thumb.jpg' /></a>
<a href='image2.html'>Name: My image 2 <br /><img src='image2_thumb.jpg' /></a>
<a href='image3.html'>Name: My image 3 <br /><img src='image3_thumb.jpg' /></a>
<a href='image4.html'>Name: My image 4 <br /><img src='image4_thumb.jpg' /></a>
<a href='image5.html'>Name: My image 5 <br /><img src='image5_thumb.jpg' /></a>
</div>
</body>
</html>

两种选择方式:

  • response.xpath()
  • response.css()
    1
    2
    3
    4
    5
    6
    7
    8
    response.xpath('//title/text()').extract_first()
    response.css('title::text').extract_first()
    response.xpath('//div[@id="not-exists"]/text()').extract_first() is None==> True
    response.xpath('//div[@id="not-exists"]/text()').extract_first(default='not fount')==> not found
    response.xpath('//base/@href').extract()
    response.css('base::attr(href)').extract()
    response.xpath('//a[contains(@href,"image")]/@href').extract()
    response.css('a[href*=image]::attr(href)').extract()

选择附近的元素:

1
2
3
4
links = response.xpath('//a[contains(@href, "image")]')
for index,link in enumerate(links):
args = (index, link.xpath('@href').extract(),link.xpath('img/@src').extract())
print 'Link number %d points to url %s and image %s' % args

注:使用xpath时如果要在当前元素下继续选择元素需要使用.//而不是//。。因为//会从整个文档解 析

使用正则:

1
2
response.xpath('//a[contains(@href, "image")]/text()').re(r'Name:\s*(.*)')
response.xpath('//a[contains(@href, "image")]/text()').re_first(r'Name:\s*(.*)')

EXSLT 扩展的使用:

1
2
3
4
5
6
7
8
9
10
11
12
# re(test()函数):
from scrapy import Selector

doc = """<div>
<ul>
<li class="item-0"><a href="link1.html">first item</a></li><li class="item-1"><a href="link2.html">second item</a></li><li class="item-inactive"><a href="link3.html">third item</a> </li>
<li class="item-1"><a href="link4.html">fourth item</a></li><li class="item-0"><a href="link5.html">fifth item</a></li></ul>
</div>
"""
sel = Selector(text=doc, type="html")
sel.xpath('//li//@href').extract()
sel.xpath('//li[re:test(@class, "item-\d$")]//@href').extract()

当需要使用元素的text内容作为一个参数传给一个xpath的string function(比如contains、start_with)时,避免使用.//text(),应该使用.代替。这是因为表达式// text()产生了一组文本元素 - 一个节点集合。当一个节点集合被转换成一个字符串,当它被作为参数传递给一个像contains()或starts-with()这样的字符串函数时,就会产生第一个元素的文本。:

1
2
3
4
5
6
7
8
9
10
11
from scrapy import Selector

sel = Selector(text='<a href="#">Click here to go to the <strong>Next Page</strong></ a>')

sel.xpath('//a//text()').extract()==> # take a peek at the node-set[u'Click here to g o to the ', u'Next Page']

sel.xpath("string(//a[1]//text())").extract()==> # convert it to string[u'Clic k here to go to the ']

sel.xpath("//a[contains(.//text(), 'Next Page')]").extract()==>[]

sel.xpath("//a[contains(., 'Next Page')]").extract()==>[u'<a href="#">Click here to g o to the <strong>Next Page</strong></a>']

当使用clss属性查询时,且class有多个属性时,考虑使用css而不是xpath,因为如果你使用@ class=’someclass’,你最终可能会丢失具有其他类的元素,如果你只是使用contains(@class,’someclass’)来弥补,你可能会得到更多的元素,如果他们有一个不同的类名称共享字符串someclass。 事实证明,Scrapy选择器允许你链接选择器,所以大多数情况下,你可以通过CSS来选择类,然后在需要时切换到XPath:

1
2
3
4
5
from scrapy import Selector

sel = Selector(text='<div class="hero shout"><time datetime="2014-07-23 19:00">Specia l date</time></div>')

sel.css('.shout').xpath('./time/@datetime').extract()

-------------本文结束感谢您的阅读-------------

本文标题:scrapy架构简介与基本操作

文章作者:Longofo

发布时间:2018年04月01日 - 22:04

最后更新:2018年04月02日 - 23:04

原始链接:http://longofo.cc/scrapy架构简介与基本操作.html

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

请我吃包辣条也好啊!!!
分享到: