Python Scrapy———豆瓣Top250

1.Scrapy简介

        最开始看Scrapy的教程是中文版 ,这个版本是0.24,后来python模块warning的时候,去查看英文版,结果人家已经更新到1.0+了,很多import的模块已经有了一些改变,这里要注意。参与翻译scrapy的作者在他的github上说:

        Scrapy的文档写得很详细,与之带来的就是文档量很大。仅仅靠我需要很多的时间。希望您能加入这个计划,让翻译更快速。

        确实工作量非常大。这里也相参与翻译的工作人员致敬~       

        个人对Scrapy的印象是这样的:它专门为了scrapy而设计,里面有一个“半自动”化的结构,包括图1.1:

《Python Scrapy———豆瓣Top250》 图1.1 scrapy 架构图            

        (1)Scrapy Engine:相当于“经销商”,它负责什么时候向Spider买url,决定买多少,并卖给Scheduler;

         (2)Spider:就是辛辛苦苦作劳动的机器人,它向Engine提供url以及相应的Rule,这是整个获取数据的关键,在你建立的scrapy项目下有一个文件夹叫:spider,里面放了spider的主程序,具体后面介绍。

        (3)Scheduler:故名思意,就是调度,根据Engine给它的url产生各种request信息;

        (4)Downloader:根据接受到的request信息进行下载,产生response对象,返还给spider处理;

        (5)Item/Pipeline:spider在接受到response对象后,自动或者根据callback进行parse,然后把处理好的数据装进item或者输出到文件。

        Scrapy内置了很多方法,我们要做的就是利用这种方法,告诉scrapy我要怎么做,具体谁发送request,谁接收response,item怎么传递的,那么就是由scrapy自己的逻辑实现,这个我们不用操心。但是还要明白spider里面各个method被执行的先后顺序,这样会使自己的逻辑非常清楚。不然scrapy就是一个黑箱,用的时候哪里有问题也不知道。

2.Scrapy使用方法

        这里对于使用scrapy非常重要,弄清楚了各个method的功能和顺序才能有的放矢。

        如果这里对于python不是很熟悉,可以找找python教材中“类”的那一章看看。

PS:本文基于linux平台,使用vim编程

(1)创建scrapy的project

        在命令行输入:

cd ~/Produre #进入Podure目录下,在这个目录下建立projecy

scrapy startproject XXX #建立名为 XXX的project 

此时在Proodure目录下会自动建立一个类似下面这样的文件结构:

《Python Scrapy———豆瓣Top250》 图2:scrapy项目文件结构

        item.py是你要定义item的地方,item你就理解为spider后要把数据存入的地方,item就可以理解为一个字典。

        pipeline可以理解为管道,当你获得的数据很多,不断产生时,用item存储的数据会被覆盖,而此时通过编写pipeline的class和method可以实现将数据源源不断的写入指定的文件类型中,后面介绍。

      settings.py是存放spider的一些配置信息的,比如下载时间间隔,pipeline中类的名字,以及按照什么样的顺序进行下载。后面介绍。

        spider文件夹下存放编写爬虫的主要文件。

(2)定义Item

打开item.py,然后按照你想要存储的数据,进行编写:

《Python Scrapy———豆瓣Top250》 图3:编写item

        每一个定义的变量都可以在spider中作为item字典的键,不过这首先要被赋予scrapy.Field()

(3)Spider中的类和方法

定义好item后,就可以编写spider程序了,但在这之前介绍以下各种方法和类:

name:必须且唯一的spider名字,类型为string,运行该spider时输入它

allow_domains:允许方法的域名,可以是string 或者list,可选项,非必须。

start_urls: 指定要首先访问的url

方法:

start_requests(): 默认从start_urls里面获取url,并且为每一个url产生一个request,默认的    callback为parse。调度就是从这里开始执行的。这里可以改写,以便从指定的url开始访问,一般用于模拟登陆时,获取动态code的时候。获取动态code那么你可以这样:

from scrapy.http import Request,FromRequest

start_requests():

    return [ Request( url, mata={‘cookiejar’:1}callback=login ) ] #加入meta想要获取cookie

        这里的url就是你登陆的login URL,访问这个url时,server会返回你一个response,这个response里面就有下一步登陆的时候要发送的code。那么这里的callback到login这个方法的功能就是要从返回的response里面通过正则表达式或者结合xpath等得到这个code。

        start_requests中将Downloader下载的response返回给callback,也就是我定义的login方法,那么在login方法中,除了要解析并获得动态code外,还可以进行模拟登陆,在login中可以加入:

def login(self,response):

      code=response.xpath(‘//h1/text()’).extract() #就是为了获得code,也可以结合re来提取

      headers={} #模拟浏览器登陆的header

      postdata={} #server要你post的数据,包括上面获得的code

      return [FormRequest.from_response(    url,  headers=headers, formdata=postdata,  meta={‘cookiejar’:response.meta[‘cookiejar’],  callback=loged  , dont_filter=x   }  )   ]

      #注意这里postdata并没有用urlencode,且cookie用的是返回的response中的cookie,也就是上面start_requests那里记录的cookie。另外此时的url则是你真正post数据的url,一般可以通过firebug获得。其实,这里也可以这个时候才获得cookie,这样可以获得登陆以后的cookie。这个方法被调用以后,就成功登陆了,那么此时可以在loged方法中通过下面make_requests_from_url这个方法来访问登陆以后的其他页面。

      #这里如果需要输入验证码,可以采用下载图片并手动输入的方式进行,在另外一片记录里可以看到。

   

        如果该方法被重写了,那么start_urls里面的url将不会被首先访问,后面想要访问的时候则要特别的“强调“。会在后面说明。

      还要注意的是,start_requests只被自动调用一次。

make_requests_from_url(url):

        这个方法就是当你指定了url的时候,则通过这个方法,可以自动返回给parse。scrapy中能够自动调用parse的方法,就我目前的学习来看,只有这两个(start_requests和make_requests_from_url)。这个之所以重要,是因为要结合后面说的CrawlSpider中的rule。

        可以通过make_requests_from_url()来实现访问start_urls里面的url:

def loged(self, response):

    for url in start_urls:

        yield make_requests_from_url(url)

parse():

       scrapy中默认将response传递到的地方就是parse(),这里顾名思义是用来提取网页内容的地方,在Spider类中可以在这里实现网页内容提取,但是在CralwSpider中,parse()实现用rule中获得的link进行进一步处理,所以在CrawlSpider中不建议重写parse方法。

rule():

        rule提供了如何指导Downloader获取链接的的功能,其具体实现是:

from scrapy.linkextractors import LinkExtractor as LKE

《Python Scrapy———豆瓣Top250》 图:rule举例

LinkExtractor的教程见:linkextractor 

linkextractor的参数这里主要用到:

(1)allow=(这里用正则表达式写明要获取的链接)

(2)restrict_xpaths=(这里要用xpath格式写明特别要从哪个节点获取链接)

在Rule里面,特别要注意callback后面要加的是string,而不是向类中引用其他方法的self.parse_1。follow意位“跟踪”,那其实这里是有一个思考的。

        rule是通过调用parse()方法来按照其里面提供的各种Rule来进行链接获取及response的返回,其逻辑是这样的:

(1)必须调用parse

(2)然后按照Rule规则,在parse中的response中寻找符合Rule指定规则的链接

(3)如果找到了相应的链接,那么请求这个链接,并把这个链接的response发送给callback,进行分析

(4)然后考虑是否跟进,如果跟进,那么以这个链接为基点再按照Rule中规则进行寻找

        这里就存在两个问题,第一个发送到rule中的response,其实是没有被传给callback的;另外就是如果follow=False,那么其实……(未完待续)

    原文作者:AquilaP
    原文地址: https://www.jianshu.com/p/a1018729d695
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞