【Python-27】scrapy爬虫架构介绍和初试

原文出处:http://my.oschina.net/dragonblog/blog/173290

 

上一篇文章的环境搭建是相对于手动操作的过程,而大家可能对这个疑问是什么是scrapy?为什么要用scrapy?下面主要是对这两个问题的简要回答。

请尊重作者的工作,转载请注明出处http://my.oschina.net/dragonblog/blog/173545

相信大家在百度或google上一搜索scrapy都能够找到一大堆的结果,由于我本人对scrapy没有太了解,因此这里我也是引用了网络上的说法对scrapy进行说明,也希望各位能够多指点一下小弟。

========================华丽的分割线========================

Scrapy 是一套基于Twisted的异步处理框架,是纯python实现的爬虫框架,用户只需要定制开发几个模块就可以轻松的实现一个爬虫,用来抓取网页内容或者各种图片。下图显示了Scrapy的大体架构,其中包含了scheduler、item pipeline、downloader、spider以及engine这几个组件模块,而其中的绿色箭头则说明了整套系统的数据处理流程。

下面就来一个个解释每个组件的作用及数据的处理过程。

一、组件说明:

 

    1、Scrapy Engine(Scrapy引擎)

    Scrapy引擎是用来控制整个系统的数据处理流程,并进行事务处理的触发。更多的详细内容可以看下面的数据处理流程。

    2、Scheduler(调度)

    调度程序从Scrapy引擎接受请求并排序列入队列,并在Scrapy引擎发出请求后返还给他们。

    3、Downloader(下载器)

    下载器的主要职责是抓取网页并将网页内容返还给蜘蛛( Spiders)。

    4、Spiders(蜘蛛)

    蜘蛛是有Scrapy用户自己定义用来解析网页并抓取制定URL返回的内容的类,每个蜘蛛都能处理一个域名或一组域名。换句话说就是用来定义特定网站的抓取和解析规则。

    蜘蛛的整个抓取流程(周期)是这样的:

    (1)首先获取第一个URL的初始请求,当请求返回后调取一个回调函数。第一个请求是通过调用start_requests()方法。该方法默认从start_urls中的Url中生成请求,并执行解析来调用回调函数。

    (2)在回调函数中,你可以解析网页响应并返回项目对象和请求对象或两者的迭代。这些请求也将包含一个回调,然后被Scrapy下载,然后有指定的回调处理。

    (3)在回调函数中,你解析网站的内容,同程使用的是Xpath选择器(但是你也可以使用BeautifuSoup, lxml或其他任何你喜欢的程序),并生成解析的数据项。

    (4)最后,从蜘蛛返回的项目通常会进驻到项目管道。

5、Item Pipeline(项目管道)

    项目管道的主要责任是负责处理有蜘蛛从网页中抽取的项目,他的主要任务是清晰、验证和存储数据。当页面被蜘蛛解析后,将被发送到项目管道,并经过几个特定的次序处理数据。每个项目管道的组件都是有一个简单的方法组成的Python类。他们获取了项目并执行他们的方法,同时他们还需要确定的是是否需要在项目管道中继续执行下一步或是直接丢弃掉不处理。

项目管道通常执行的过程有:

  1. 清洗HTML数据
  2. 验证解析到的数据(检查项目是否包含必要的字段)
  3. 检查是否是重复数据(如果重复就删除)
  4. 将解析到的数据存储到数据库中

6、Downloader middlewares(下载器中间件)

    下载中间件是位于Scrapy引擎和下载器之间的钩子框架,主要是处理Scrapy引擎与下载器之间的请求及响应。它提供了一个自定义的代码的方式来拓展 Scrapy的功能。下载中间器是一个处理请求和响应的钩子框架。他是轻量级的,对Scrapy尽享全局控制的底层的系统。

7、Spider middlewares(蜘蛛中间件)

    蜘蛛中间件是介于Scrapy引擎和蜘蛛之间的钩子框架,主要工作是处理蜘蛛的响应输入和请求输出。它提供一个自定义代码的方式来拓展Scrapy的功能。蛛中间件是一个挂接到Scrapy的蜘蛛处理机制的框架,你可以插入自定义的代码来处理发送给蜘蛛的请求和返回蜘蛛获取的响应内容和项目。

8、Scheduler middlewares(调度中间件)

    调度中间件是介于Scrapy引擎和调度之间的中间件,主要工作是处从Scrapy引擎发送到调度的请求和响应。他提供了一个自定义的代码来拓展Scrapy的功能。

二、数据处理流程

Scrapy的整个数据处理流程由Scrapy引擎进行控制,其主要的运行方式为:

  1. 引擎打开一个域名,时蜘蛛处理这个域名,并让蜘蛛获取第一个爬取的URL。
  2. 引擎从蜘蛛那获取第一个需要爬取的URL,然后作为请求在调度中进行调度。
  3. 引擎从调度那获取接下来进行爬取的页面。
  4. 调度将下一个爬取的URL返回给引擎,引擎将他们通过下载中间件发送到下载器。
  5. 当网页被下载器下载完成以后,响应内容通过下载中间件被发送到引擎。
  6. 引擎收到下载器的响应并将它通过蜘蛛中间件发送到蜘蛛进行处理。
  7. 蜘蛛处理响应并返回爬取到的项目,然后给引擎发送新的请求。
  8. 引擎将抓取到的项目项目管道,并向调度发送请求。
  9. 系统重复第二部后面的操作,直到调度中没有请求,然后断开引擎与域之间的联系。

========================华丽的分割线========================

以上部分是属于网上抄过来的,谁是第一手就无可考究了,对于大家是否能看明白就没有保证了,我本还还算能够明白七成吧。

上面两个分割线中的内容也算得是回答了第一个问题了,那么为什么要用scrapy呢?我有一个习惯,在提出问题的时候都会先再找一个问题,对于这个问题而提出的问题是:我自己写一个不行吗?

刚开始的时候我也是这样想的,于是就自己开始找python怎么抓网页数据之类的了,后来还弄了一个不堪入目的一段代码,用于从一个根网页中找到所有的链接,然后将这些链接都放到一个列表中,然后弄个循环从这个列表中一个个去抓。下面就是我之前第一次接触python时写的代码(不堪入目,不喜勿喷。。。)

 

001#encoding=utf-8
002 
003__author__ = 'dragon'
004 
005import urllib2
006import os
007import pymongo
008import time
009import hashlib
010 
011def myspider(startweb, keyword):
012    list = [startweb]
013    curindex = 0
014    Keyword = keyword
015 
016    #网络上MongoHQ
017    #con = pymongo.Connection("paulo.mongohq.com", 10042)
018    #db = con.mytest
019    #db.authenticate("dragon", "dragon")
020    #db.urllist.drop()
021 
022    #本地数据库
023    con = pymongo.Connection("localhost"27017)
024    db = con.mytest
025 
026    while curindex < len(list):
027        url = list[curindex]
028        print "list count ="len(list), "  curcheck ", curindex
029        print "try to visit ", url
030 
031        headers = ('User-Agent''Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.66 Safari/537.36')
032 
033        try:
034            opener = urllib2.build_opener()
035            opener.addheaders = [headers]
036            openness = opener.open(url, None30)
037            data = openness.read()
038            opener.close()
039        except:
040            print "some error ..."
041            curindex += 1
042            continue
043 
044        print "finish get data..."
045 
046        os.remove("d:/test.txt")
047        file = open("d:/test.txt""a")
048        print >> file, data
049        file.close()
050 
051        myfile      = open("d:/test.txt""r")
052        mystring    = myfile.read()
053        myfile.close()
054 
055        #找到标题
056        title       = ""
057        headstart   = mystring.find("<head>")
058        headend     = mystring.find("</head>")
059        if headstart < 0:
060            headstart   = mystring.find("<HEAD>")
061            headend     = mystring.find("</HEAD>")
062 
063        if headstart > 0:
064            titlestart  = mystring.find("<title>")
065            titleend    = mystring.find("</title>")
066            if titlestart < 0:
067                titlestart  = mystring.find("<TITLE>")
068                titleend    = mystring.find("</TITLE>")
069 
070            if titleend > titlestart and titlestart < headend and titleend < headend:
071                title = mystring[titlestart+len("<title>"):titleend]
072 
073        dbdata = {"title":"", "url":"", "time":""}
074 
075        try:
076            title = title.decode("utf-8").encode("utf-8")
077        except:
078            try:
079                title = title.decode("gbk").encode("utf-8")
080            except:
081                pass
082 
083 
084        dbdata["title"= title
085        dbdata["url"= url
086        dbdata["time"= time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))
087        try:
088            db.urllist.insert(dbdata)
089        except:
090            print "insert error"
091 
092        if len(mystring) > 0:
093            while len(mystring) > 0:
094                start = mystring.find("href=\"")
095                if start <= 0:
096                    break
097 
098                substring = mystring[start+6:]
099                end = substring.find("\"")
100                weblink = substring[:end]
101                if Keyword != "":
102                    if weblink.find(Keyword) >= 0 and list.count(weblink) <= 0:
103                        list.append(weblink)
104                elif 0 > weblink.find("video.sina.com.cn") \
105                    and 0 > weblink.find("video.baidu.com") \
106                    and 0 <= weblink.find("http:") \
107                    and 0 >= list.count(weblink):
108 
109                    list.append(weblink)
110 
111                mystring = mystring[start+6:]
112 
113        curindex += 1
114 
115if __name__ == '__main__':
116    myspider("http://www.hao123.com""hao123")

处理的流程是:

    1. 将一个开始的网页url存放到list中

    2. 不断从list中取出url进行数据获取

    3. 在获取到的网页数据中的链接都存放到list里面

    4. 不断重复2、3步骤

上面这段代码写得怎么样就不值得评论了,但是值得我们思考的是,上面的代码出发点是爬虫,并且还是漫无目的的爬虫,没有了终点,或者大家会想到很多退出循环的方法,但是我们还有很多问题需要考虑:如何提高爬虫的效率?如何最大限度利用网络带宽?如果提高抓取回来数据的处理?最重要一点是:我们都不会想着去做google或百度,而是针对一些特定的需求来实现一个爬虫,那么我们如何简单而又快速的去实现我们的定制功能呢?

上面的几个问题就是我们最终都会遇到的问题,也是scrapy能够很好的处理的问题,它通过几个组件完成不同的部分,将类似下载网页数据的这些通用操作封装起来,减少了我们编写爬虫时的难度,并且各个部件之间通过异步来处理,能够最大限度利用了网络带宽。我们只需要按照它的要求来实现几个模块就可以了。

最后,讲讲使用如何生成一个scrapy工程。

打开cmd,cd到你要创建工程的目录,然后使用以下命令创建工程test:

    scrapy startproject test

如下图所示,我们看到创建了一个test文件夹,里面包含了其他一些文件

根据上图可以对照第一幅图,找到一些组件的对应文件,我们可以在spider下面创建一个py文件(例如:spider.py),然后写上以下代码:

1from scrapy.spider import BaseSpider
2 
3class test(BaseSpider):
4    name = "test"
5    allowed_domains = ["hao123.com"]
6    start_urls = ["http://www.hao123.com"]
7 
8    def parse(self, response):
9        print response.url

在cmd中,cd进入刚才创建的test目录,使用以下命令运行这个爬虫,我们可以最后看到一些debug输出

这篇文章到此为止,写得比较粗糙。可能大家对于spider.py中的一些变量和函数名称,以及该模块什么时候被调用存在疑问,大家可以上网找找资料学习,我将在下一篇文件中说明,并且以获取百度文库中的图书信息作为例子,完成相关的代码并提供源码。

 

1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 、4下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。、可私 6信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 、4下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。、可 6私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 、4下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。、可私 6信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值