pyspider框架的使用

介绍

  • 用Python编写脚本
  • 功能强大的WebUI,包括脚本编辑器,任务监视器,项目管理器和结果查看器
  • MySQL,MongoDB,Redis,SQLite,Elasticsearch ; PostgreSQL使用SQLAlchemy作为数据库后端
  • RabbitMQ,Beanstalk,Redis和Kombu作为消息队列
  • 任务优先级,重试,定期,按年龄重新抓取等...
  • 分布式架构,抓取Javascript页面,Python 2和3等...

pyspider的架构

pyspider的架构主要分为Scheduler(调度器)、Fetcher(抓取器)、Processer(处理器)三个部分,整个爬取过程受到Monitor(监视器)的控制,抓取的结果被Result Worker(结果处理器)处理,如下图所示。pyspider框架的使用_第1张图片

Scheduler发起任务调度,Fecher负责抓取网页内容,Processer负责解析网页内容,然后将新生成的Request发给Scheduler进行调度,将生成的提取结果输出保存。

pyspider的基本使用

1.打开cmd,输入命令

pyspider all

pyspider框架的使用_第2张图片

这样可以启动pyspider的所有组件,包括PhantomJS、ResultWorker、Processer、Fetcher、Scheduler、WebUI,这些都说pyspider运行必备的组件。可以打开浏览器,输入链接http://localhost:5000,这时我们会看到页面,如图所示:

pyspider框架的使用_第3张图片

此页面便是pyspider的WebUI,我们可以用它来管理项目、编写代码、在线调试、监控任务等。

创建项目

新建一个项目,点击右边的create按钮,在弹出的浮窗里输入项目名称和爬取链接,在点击create按钮,这样就成功创建了一个项目,如图所示pyspider框架的使用_第4张图片

接下来会看到pyspider的项目编辑和调试页面,如图所示;
pyspider框架的使用_第5张图片

左侧就是代码的调试页面,点击左侧右上角的run单步调试爬虫程序,在左侧下半部分可以预览当前的爬取页面。右侧是代码编辑页面,我们可以直接编辑代码和保存代码。

注意右侧,pyspider生成了一些代码,代码如下所示:

#!/usr/bin/env python
# -*- encoding: utf-8 -*-
# Created on 2018-09-22 16:46:39
# Project: q

from pyspider.libs.base_handler import *


class Handler(BaseHandler):
    crawl_config = {
    }

    @every(minutes=24 * 60)
    def on_start(self):
        self.crawl('http://travel.qunar.com/travelbook/list.htm', callback=self.index_page)

    @config(age=10 * 24 * 60 * 60)
    def index_page(self, response):
        for each in response.doc('a[href^="http"]').items():
            self.crawl(each.attr.href, callback=self.detail_page)

    @config(priority=2)
    def detail_page(self, response):
        return {
            "url": response.url,
            "title": response.doc('title').text(),
        }

这样的Handler就是pyspider爬虫的主类,我们可以在此处定义爬取,解析、存储的逻辑。整个爬虫的功能只需要一个Handler即可完成。

接下来我们可以看到一个crawl_config属性。我们可以将本项目的所有爬取配置统一定义道这里,如定义Headers、设置代理等,配置之后全局生效。

然后,on_start()方法是爬取入口,初始的爬取请求会在这里产生,该方法通过调用crawl()方法即可新建一个爬取请求,第一个参数是爬取的URL,这里自动替换成我们定义的URL。crawl()方法还有一个参数callback,它指定了这个页面爬取成功后用哪个方法进行解析,代码中指定为index_page()方法,即如果这个URL对应的页面爬取成功了,那Response将交给index_page()方法进行解析。

index_page()方法恰好接收这个Response参数,Response对接了pyquery。我们直接调用doc()方法传入相应的CSS选择器,就可以像pyquery一样解析此页面,代码中默认是a[href^="http"],也就是说该方法解析了页面的所有链接,然后将链接遍历,再次调用了crawl()方法生成了新的爬取请求,同时指定了callback和detail_page,意识是说这些页面爬取成功了就调用detail_page()方法解析。这里,index_page()实现了两个功能,一是将爬取的结果进行解析,二是生成新的爬取请求。

detail_page()同样接收Response作为参数。detail_page()抓取的就是详情页的信息,就不会生成新的请求,只对Response对象做解析,解析之后将结果以字典的形式返回。当然我们也可以进行后续处理,如将数据保存到数据库中。

爬取首页

点击左栏右上角的run按钮,即可看到页面下方follows便会出现一个标注,其中包含数字1,这代表有新的爬取请求产生,如图所示。

pyspider框架的使用_第6张图片

左栏左上角会出现当前run的配置文件,这里有一个callback为on_start,这说明点击run之后实际是执行了on_start()方法。在on_start()方法中,我们利用crawl()方法生成一个爬取请求,那下方follows部分的数字1就代表了一个爬取请求。

点击下方的follows按钮,即可以看到生成的爬取请求链接。如图所示:

pyspider框架的使用_第7张图片

上方的callback已经变成了index_page,这就代表当前运行了index_page()方法。index_page()接收到的response参数就是刚才生成的第一个爬取请求的Response对象。index_page()方法通过调用doc()方法,传入提取所有a节点的CSS选择器,然后获取a节点的属性href,这样实际上就是获取第一个爬取页面中的所有链接。然后在index_page()方法里遍历了所有链接,同时调用了crawl()方法,就把这一个个的链接构造成新的爬取请求了。所以最下方follows按钮部分有231的数字标记,这就代表生成了217个爬取请求,同时这些请求的URL都呈现在当前页面了。

再点击下方的web按钮,即可预览当前爬取结果的页面,如图所示:

pyspider框架的使用_第8张图片

点击html按钮即可查看当前页面的源码,如图所示:

pyspider框架的使用_第9张图片

刚才在index_page()方法中提取了所以的链接并生成了新的爬取请求。

当我们要爬取攻略详情页面链接的时候我们就使用下方enable css selector helper这个工具即可,点击它,然后选择标题就会多一个红框,上方出现了一个CSS选择器,这就是当前标题对应的CSS选择器,如图所示:

pyspider框架的使用_第10张图片

在右侧代码选择要更改的区域,点击左栏的右箭头,此时在上方出现的标题的CSS选择器就会被替换到右侧代码中,如图所示:

pyspider框架的使用_第11张图片

这样就完成了CSS选择器的替换,非常便捷。

重新点击左栏右上角的run按钮,即可重新执行index_page()方法,此时的follows就变成了10个,也就是说现在我们提取的只有当前10个攻略,如图所示:

pyspider框架的使用_第12张图片

我们现在抓取的只是第一页的内容,还需要抓取后续页面,所以还需要一个爬取链接,即爬取下一页的攻略列表页面。我们再利用crawl()方法添加下一页的爬取请求,在index_page()方法里添加如下代码,然后点击save保存,如下图所示:

pyspider框架的使用_第13张图片

现在我们就把所以列表页的解析过程完成了。

爬取详情页

任意选取一个详情页进入,点击前10个爬取请求中的任意一个的右箭头,执行详情页的爬取,如图所示

pyspider框架的使用_第14张图片

切换到Web页面预览效果,页面下拉之后,头图正文中的一些图片一直显示加载中

此现象的原因是pyspider默认发送HTTP请求,请求的HTML文档本身就不包含img节点。但是在浏览器中我们看到了图片,这时因为这张图片是后期经过JavaScript出现的。

我们可以将index_page()中生成抓取详情页的请求方法添加一个参数fetch_type,改写的index_page()变为如下内容:

for each in response.doc('li > .tit > a').items():
            self.crawl(each.attr.href, callback=self.detail_page,fetch_type='js')
        next=response.doc('.next').attr.href
        self.crawl(next,callback=self.index_page)
          

接下来看效果:

pyspider框架的使用_第15张图片

图片被成功渲染出来了,这就是启动了PhantomJS渲染后的结果。只需要添加一个fetch_type参数即可,这非常的方便。

最好在detail_page()方法改写如下所示:

 def detail_page(self, response):
        return {
            "url": response.url,
            "title": response.doc('#booktitle').text(),
            "date":response.doc('.when .data').text(),
            "day":response.doc('.howlong .data').text(),
            "who":response.doc('.who .data').text(),
            "text":response.doc('#b_panel_schedule').text(),
            "image":response.doc('.cover_img').attr.src
        }

我们分别提取了页面的链接、标题、出行日期、出行天数、人物、攻略正文、头图信息、将这些信息构造成一个字典。

启动爬虫

返回爬虫的主页面,将爬虫的status设置成DEBUG或RUNNING,点击右侧的Run按钮即可开始爬取,如图所示

pyspider框架的使用_第16张图片

在最左侧我们可以定义项目的分组,以方便管理。rate/burst代表当前的爬取速率,rate代表1秒发出多少个请求,burst相当于流量控制中的令牌桶算法的令牌数,rate和burst设置的越大,爬取速率越快,当然速率需要考虑本机性能和爬取过快被封的问题。process中的5m、1h、1d指的是最近5分、1小时、1天内的请求情况,all代表所有的请求情况。请求由不同颜色表示,蓝色代表等待被执行的请求,绿色的代表成功的请求,黄色的代表请求失败后等待重试的请求,红色的代表失败次数过多而被忽略的请求,这样可以直观知道爬取的进度和请求情况,如图所示pyspider框架的使用_第17张图片

点击Active Tasks,即可查看最近请求的详细情况,如图所示:

pyspider框架的使用_第18张图片

点击Results,即可查看所有爬取的结果,如图所示:

pyspider框架的使用_第19张图片

点击右上角的按钮,即可获得数据的JSON、CSV格式。

pyspider用法

self.crawl

self.crawl(url, **kwargs)

self.crawl 是告诉pyspider应该抓取哪个url的主界面。

参数:

  • url

url是爬取时的URL,可以定义为单个URL字符串,也可以定义成URL列表。

  • callback

callback是回调函数,指定了该URL对应的响应内容用哪个方法来解析,如下所示:

 def on_start(self):
        self.crawl('http://travel.qunar.com/travelbook/list.htm', callback=self.index_page)

这里指定了callback为index_page,就代表爬取http://travel.qunar.com/travelbook/list.htm'链接得到的响应会用index_page()方法来解析。

  • age

age是任务的有效时间。如果某个任务在有效时间内且已经被执行,则它不会重复执行,如下所示:

@config(age=10 * 24 * 60 * 60) 
    def index_page(self, response): 

默认的有效时间为10天。

  • priority

priority是爬取任务的优先级,其默认值是0,priority的数值越大,对应的请求会越优先被调度,如下所示:

def index_page(self): 
    self.crawl('http://www.example.org/page2.html', callback=self.index_page)
    self.crawl('http://www.example.org/233.html', callback=self.detail_page,priority=1)

第二个任务会优先被调用,233.html这个链接优先爬取。

  • exetime

exetime参数可以设置定时任务,其值是时间戳,默认是0,即代表立即执行,如下所示:
 

import time def on_start(self):
    self.crawl('http://www.example.org/', callback=self.callback,exetime=time.time()+30*60)

这样该任务会在30分钟之后执行。

  • retries

retries可以定义重试次数,其默认值是3.

  • itag

itag参数设置判定网页是否发生变化的节点值,在爬取时会判定次当前节点是否和上次爬取到的节点相同。如果节点相同,则证明页面没有更新,就不会重复爬取,如下所示:

def index_page(self, response):  
    for item in response.doc('.item').items():
        self.crawl(item.find('a').attr.url, callback=self.detail_page,       itag=item.find('.update-time').text())
class Handler(BaseHandler): 
    crawl_config = { 'itag': 'v223' }

修改全局参数itag,使所有任务都重新执行(需要点run按钮来启动任务)

  • auto_recrawl

当开启时,爬取任务在过期后会重新执行,循环时间即定义的age时间长度,如下所示"

def on_start(self): 
    self.crawl('http://www.example.org/', callback=self.callback,age=5*60*60, auto_recrawl=True)

这里定义了age有效期为5个小时,设置了auto_recrawl为True,这样任务就会每5个小时执行一次。

  • method

method是HTTP的请求方式,它默认是GET。如果想发起POST请求,可以将method设置为POST。

  • params

我们可以方便地使用params来定义GET请求参数,如下所示:

def on_start(self): 
    self.crawl('http://httpbin.org/get', callback=self.callback,params={'a': 123, 'b': 'c'})
    self.crawl('http://httpbin.org/get?a=123&b=c', callback=self.callback)

这里两个爬取任务是等价的

  • data

data是POST表单数据。当请求方式为POST时,我们可以通过此参数传递表单数据,如下所示:

def on_start(self): 
    self.crawl('http://httpbin.org/post', callback=self.callback,method='POST', data={'a': 123, 'b': 'c'})
  • files

files是上传的文件,需要指定文件名,如下所示:

def on_start(self): 
    self.crawl('http://httpbin.org/post', callback=self.callback,method='POST', files={field:{filename:'content'}})
  • user_agent

user_agent是爬取使用的User_Agent.

  • headers

headers是爬取时使用的Headers,即Request Headers。

  • cookies

cookies是爬取时使用的Cookies,为字典格式。

  • connect_timeout

connect_timeout是在初始化连接时的最长等待时间,它默认是20秒。

  • timeout

timeout是爬取网页时的最长等待时间,它默认是120秒。

  • allow_redirects

确定是否自动处理重定向,它默认为True。

  • validate_cert

确定是否验证证书,此选项对HTTPS请求有效,默认是True。

  • proxy

proxy是爬取时使用的代理,它支持用户名密码的配置,格式是username:password@hostname:port,如下所示:

class Handler(BaseHandler): 
    crawl_config = { 'proxy': 'localhost:8080' }
  • fetch_type

fetch_type开启PhantomJS渲染。如果遇到JavaScript渲染的页面,指定字段即可实现PhantomJS的对接,pyspider将会使用PhantomJS进行网页的抓取,如下所示:

def on_start(self): 
    self.crawl('http://www.taobao.com', callback=self.callback,method='POST', fetch_type='js')

这样我们就可以实现淘宝页面的抓取了,得到的结果就是浏览器中看到的效果。

  • js_script

js_script是页面加载完毕后执行的Javascript脚本,如下所示:

def on_start(self): 
    self.crawl('http://www.example.org/', callback=self.callback,fetch_type='js', js_script='''
               function() {
                   window.scrollTo(0,document.body.scrollHeight);
                   return 123;
               }
               ''')

页面加载成功后将执行页面混动的JavaScript代码,页面会下拉到最底部。

  • load_images

在加载JavaScript页面时确定是否加载图片,它默认是否

  • save

save参数非常有用,可以在不同的方法之间传递参数,如下所示:

def on_start(self): 
    self.crawl('http://www.example.org/', callback=self.callback,save={'page': 123}) def callback(self, response): return response.save['page']

在on_start()方法中生成Request并传递额外的参数page,在回调函数里可以通过response遍历的save字段接收到这些参数值

  • cancel

取消任务,如果一个任务是ACTIVE状态的,则需要force_update设置为True。

  • force_update

即使任务处于ACTIVE状态,也会强制更新状态。

项目状态

每个项目都有6个状态,分别是TODO、STOP、CHECKING、DEBUG、RUNNING、PAUSE。

TODO:项目刚刚被创建还未实现时的状态。

STOP:如果想停止某项目的抓取,可以将项目的状态设置成STOP

CHECKING:正在运行的项目被修改后就会变成CHECKING状态,项目在中途出错需要调整的时候会遇到这种情况。

DEBUG/RUNNING:这两个状态对项目的运行没有影响,状态设置成任意一个,项目都可以运行,但是可以用二者来区分项目是否已经测试通过。

PAUSE:当爬取过程中出现连续多次错误时,项目会自动设置为PAUSE状态,并等待一定时间后继续抓取。

 

你可能感兴趣的:(Python)