python爬虫的最佳实践(七)--pyspider框架的使用

Ps:惯例ps环节,经过前面几章的学习,写一些简单的爬虫已经是手到擒来了吧。这章我们看看如何使用pyspider框架来写爬虫~

环境配置

在这之前简单介绍一下为什么选择这个框架:

  1. 这个框架是共和国人民写的(最强大的理由,没有之一)。
  2. 其次,有webUi的界面,如果你有服务器,那么随时随地都可以编写爬虫,在线调试的机制也做得很好。
  3. 多任务并行,健全的任务管理机制。
  4. 支持各种主流数据库。

建议大家去看看文档,因为我这里只能介绍少部分功能,后续得还需要大家自己在使用的时候自行挖掘~pyspider文档

  • mac环境
    mac环境是很好配置的,只需要打开你的pycharm,然后直接输入pyspider安装即可~
    或者在终端pip install pyspider
1.png
  • windows环境
    同mac环境,最好直接在pycharm中安装

  • linux环境
    因为这个框架一般都是在linux服务器上运行的,本机对框架的需求不大。
    1.ubuntu系统:
    apt-get install python-dev python-distribute libcurl4-openssl-dev libxml2-dev libxslt1-dev python-lxml
    安装上述的依赖环境,等待安装完成后执行pip install pyspider
    这样就安装完成了
    2.centos系统
    centos的话建议使用7系列的版本,这样py直接是2.7,否则还得自己安装py2.7以上的版本。
    安装依赖yum install -y gcc ruby-devel libxml2 libxml2-devel libxslt libxslt-devel
    然后同样的pip install pyspider
    即可完成安装

在终端输入pyspider启动框架,进入http://localhost:5000/,如图所示:

2.png

这样就可以开始使用了~

代码预览

import re
from pyspider.libs.base_handler import *

class Handler(BaseHandler):

    @every(minutes=24 * 60)
    def on_start(self):
        self.crawl('http://www.imdb.com/search/title?count=100&title_type=feature,tv_series,tv_movie&ref_=nv_ch_mm_1', callback=self.index_page)

    @config(age=24 * 60 * 60)
    def index_page(self, response):
        for each in response.doc('a[href^="http"]').items():
            if re.match("http://www.imdb.com/title/tt\\d+/$", each.attr.href):
                self.crawl(each.attr.href, callback=self.detail_page)
        self.crawl([x.attr.href for x in response.doc('#right a').items()], callback=self.index_page)

    @config(priority=2)
    def detail_page(self, response):
        return {
            "url": response.url,
            "title": response.doc('.header > [itemprop="name"]').text(),
            "rating": response.doc('.star-box-giga-star').text(),
            "director": [x.text() for x in response.doc('[itemprop="director"] span').items()],
        }

代码剖析

原谅博主偷了个懒,这段代码不是博主自己敲的,主要是下班回家写博客确实很累,而且这段代码在pyspider的官方demo,运行情况如下,用来做入门很不错~


3.png

好了,不说废话了。这次我们的目标是IMDb,非常有名的电影资料网站。首先,我们看到这段代码是否觉得和我们上次看到的unittest结构很类似?没错,首先,我们创建的class Handler继承pyspider的BaseHandler。程序的入口是on_start()函数,这段代码没有写crawl_config,一般如果 网站反爬虫机制很强的话,会带上crawl_config,结构如下:

crawl_config = {
        "headers" : headers,
        "timeout" : 1000,
        "cookies" : Cookie
        "proxy" : 192.168.1.1:8888
    }

这个我们先简单提一下,在随后的课程再详细介绍。

我们注意到在on_start()函数上方有这样一段代码@every(minutes=24 * 60),这是告诉scheduler(调度器)每天调度一次on_start()函数。

self.crawl('http://www.imdb.com/search/title?count=100&title_type=feature,tv_series,tv_movie&ref_=nv_ch_mm_1',callback=self.index_page)

crawl()函数的两个参数,前一个指的是url,后一个指的是回调函数,也就是执行完请求之后调用的函数。

接下来回调指向了index_page()
@config(age=24 * 60 * 60)
这个设置代表了在一天之内忽略已经请求过的网站,一般都会设置的比every的时间长一点,保证少做重复工作,但是这样写也没有问题,因为我们扒的网站信息是在不断更新的,并不是一成不变的。crawl会返回一个response对象,所有的返回信息都在这个对象里面。

for each in response.doc('a[href^="http"]').items():
        if re.match("http://www.imdb.com/title/tt\\d+/$", each.attr.href):
              self.crawl(each.attr.href, callback=self.detail_page)
        self.crawl([x.attr.href for x in response.doc('#right a').items()], callback=self.index_page)

response.doc是一个PyQuery对象,支持Css Selector。
上面第一行代码找出返回网页源代码里面所有的网页链接,然后通过re(python自带的正则模块),匹配出所有格式为http://www.imdb.com/title/tt开头后面跟着若干数字的网页。如http://www.imdb.com/title/tt3040964/
然后挨个请求self.crawl(each.attr.href, callback=self.detail_page),回调为detail_page

最后一行代码是一个递归的调用,就是如果这一页有翻译按钮,那么久请求下一页并递归调用index_page()函数,这样就可以把网页中所有的电影全部抓取下来。

return {
            "url": response.url,
            "title": response.doc('.header > [itemprop="name"]').text(),
            "rating": response.doc('.star-box-giga-star').text(),
            "director": [x.text() for x in response.doc('[itemprop="director"] span').items()],
        }

detail_page函数是用来吧结果储存在数据库中的,如果我们需要对数据进行过滤,还有on_result(self, result)函数,它会传入result作为参数。重写on_result的函数之后我们就可以对数据进行过滤。比如过滤掉一些无用的数据。上面的四行数据处理的代码如果看不懂可以参看前面讲过的知识。

至此,今天的代码剖析完毕。今天只是讲了一下pyspider的简单应用,pyspider还有很多很实用的方法可以去发觉,比如和phantomJS结合,抓取ajax的动态数据,只需要你的服务器有phantomJs环境,然后再crawl函数中加入self.crawl('http://www.twitch.tv/directory/game/Dota%202', fetch_type='js', callback=self.index_page)fetch_type即可。

最后我讲一下pyspider的管理台界面都有什么作用,参见上图的2.png,第一个group我也不是太清楚作用,只知道把group设置为delete然后status设置为stop,24小时之后任务会自动被删除。我们要开始一个任务,需要吧status设置为RUNNING然后在点击后面的run按钮。rate指的是每秒抓取多少次网页,一般情况下建议1以下,不容易被封。brust指的是并发度~后面的active Tasks可以看到现在正在执行的task的状态,最后一个就是抓取的result。

写在最后

今天我们讲解了pyspider的简单使用,下一章我们讲一下scrapy的简单使用,让大家能上手这个爬虫界的利器。

最后附上我前两天讲解抓瓜子网信息的代码。


#!/usr/bin/env python
# -*- encoding: utf-8 -*-
# Created on 2016-05-01 11:31:38
# Project: guazi

from pyspider.libs.base_handler import *
import pymongo

class Handler(BaseHandler):
    client = pymongo.MongoClient('localhost', 27017)
    guazi2 = client['guazi2']
    car = guazi2['car']
    
    crawl_config = {
    }

    @every(minutes=24 * 60)
    def on_start(self):
        self.crawl('http://www.guazi.com/bj/buy', callback=self.index_page)

    @config(age=10 * 24 * 60 * 60)
    def index_page(self, response):
        for each in response.doc('body > div.header > div.hd-top.clearfix > div.c2city > div > div > dl > dd > a').items():
            self.crawl(each.attr.href, callback=self.second_page)

    @config(age=10 * 24 * 60 * 60)
    def second_page(self, response):
        num = int(response.doc('div.seqBox.clearfix > p > b').text())
        urls = [response.url+'o{}/'.format(str(i)) for i in range(1,num/40+2,1)]
        for each in urls:
            self.crawl(each, callback=self.third_page)
            
    @config(age=10 * 24 * 60 * 60)
    def third_page(self, response):
        for each in response.doc('div.list > ul > li > div > a').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('body > div.w > div > div.laybox.clearfix > div.det-sumright.appoint > div.dt-titbox > h1').text(),
            "address": response.doc('body > div.w > div > div.laybox.clearfix > div.det-sumright.appoint > ul > li:nth-child(5) > b').text(),
            "cartype": response.doc('body > div.w > div > div.laybox.clearfix > div.det-sumright.appoint > ul > li:nth-child(3) > b').text(),
            "price": response.doc('body > div.w > div > div.laybox.clearfix > div.det-sumright.appoint > div.basic-box > div.pricebox > span.fc-org.pricestype > b').text().replace(u'¥',''),
            "region":response.doc('#base > ul > li.owner').text()
        }
    
    def on_result(self, result):
        self.car.insert_one(result)

大家做个参考写的不好,轻喷

有兴趣的同学可以加群498945822一起交流学习哦~~
发现问题的同学欢迎指正,直接说就行,不用留面子,博主脸皮厚!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容