Scrapy+Flask+Mongodb+Swift 开发全攻略(1)

cymt 10年前

来源:叶孤城___的简书

Scrapy+Flask+Mongodb+Swift 开发全攻略(1)

先一一介绍一下上面4个东西。第一个叫做Scrapy的东西是用python写的爬虫框架。

Flask是python写的一个非常有名的web开发框架,python界有两个名气最大的web开发框架,Flask是其中之一,另一个叫做Django,为什么不用Django的原因就是Django太庞大了,我们开发服务端并不需要render html之类的view层,只需要提供Restful接口,所以使用Django开发不是个明智的选择,而且Django内置了很多多余的功能,而Flask比较精简,很多额外的功能都可以通过安装Flask的扩展来实现。

Mongodb是一个非关系型数据库,它存储数据的方式不同于mysql等关系型数据库,是以key-value形式存取数据的,总的来说数据格式有点像json。和mysql各有优劣。我们这里将会使用mongodb来做我们的数据库。

Swift不多说了,iOS开发都懂得。

那么,这个系列的教程到底是想干什么呢?简单来说,就是实现一个人完成获得资源+编写服务端+iOS客户端+服务端部署上线+客户端上AppStore。这是个漫长的过程,我也在学习过程中,可能过程中唯一轻松的就是iOS客户端编写的部分,所以我把这个部分放在最后,先做最难得。再做简单的。

我之前是从来没有写过服务端的,只有大四的时候写过一个月左右的JSP,那都是很多年前的老黄历了,当时用的好像还是serverlet之类的东西。

所以用python编写服务端我也是头一遭。肯定漏洞百出,代码极其ugly,不过他山之石,可以攻玉。每个人都可以在我写这篇的过程中提出意见和建议。我们共同进步。

废话不多说。我们开始第一步,写一个爬虫获取我们需要的资源。

其实这里的内容大部分学自我前几天转发的那篇blog

看过我blog的同学应该有印象,我年前的时候有用BeautifulSoup和urllib这两个python框架写过一个爬虫,用来爬www.dbmeizi.com这个网站的美女图片。那么今天,我会用scrapy编写一个功能更完整的爬虫。他有如下几个功能。

1.爬取dbmeizi.com上每个图片的url和title。

2.把图片url和title和一些自定义字段放在mongodb里。

首先确保你的mac安装了xcode的commandline工具和python界的cocoapods,叫做pip,还有mongodb(可以去官网下载)。

然后安装scrapy这个python库,很简单。在Terminal里运行sudo pip install scrapy,输入密码之后点击回车。搞定。

我们的爬虫爬完数据之后需要把数据存入mongodb,所以需要一个用来连接mongodb的第三方库,这个库叫做"pymongo",我们也可以用pip来安装。

sudo pip install pymongo,就可以安装了。

接下来,用scrapy startproject(这两个单词合起来是一个命令)来生成一个爬虫。

输入scrapy startprojct dbmeizi

然后scrapy帮我们生成了这么一个模板。

Scrapy+Flask+Mongodb+Swift 开发全攻略(1)

现在重点关注一下这几个文件。

1.items.py,这里你可以吧items.py看作是mvc中的model,在items里我们定义了自己需要的模型。

2.piplines.py pipline俗称管道,这个文件主要用来把我们获取的item类型存入mongodb

3.spiders文件夹。 这里用来存放我们的爬虫文件。

4.settings.py 这里需要设置一些常量,例如mongodb的数据库名,数据库地址和数据库端口号等等。

第一步:定义Model层

我们可以先设想一下,dbmeizi.com这个网站,每一个美女图片包括哪些内容?

我们先看一张图。

Scrapy+Flask+Mongodb+Swift 开发全攻略(1)

这张图显示了dbmeizi.com这个网站里每张图片包含的信息。所以我们可以规定model有以下内容。

1.image的URL

2.image的title

3.可以设置一个star以后可以用来排序,让用户打分,看看哪个美女最受欢迎

4.还有一个id,防止后面插入数据库的时候插入重复数据

ok,所以打开items.py我们修改后的代码是这样的。

from scrapy.item import Item, Field  class MeiziItem(Item):      # define the fields for your item here like:      # name = scrapy.Field()      datasrc = Field()      title = Field()      dataid = Field()      startcount = Field()

我们定义了一个class叫做MeiziItem,继承自scrapy的类Item,然后为我们的类定义了4个属性,datasrc用来保存等下拉去的image-url,title用来保存图片的title,dataid用来记录图片id防止重复图片,starcount是喜欢次数,以后我们开发iOS端的时候可以设计一个喜欢的功能。每次用户喜欢那么startcount都+1.

第二步:编写爬虫

打开spiders文件夹,新建一个dbmeizi_scrapy.py文件。

在文件里写如下内容.

from scrapy import Spider  from scrapy.selector import Selector  from dbmeizi.items import MeiziItem  class dbmeiziSpider(Spider):      name = "dbmeiziSpider"      allowed_domin =["dbmeizi.com"]      start_urls = [          "http://www.dbmeizi.com",       ]      def parse(self, response):          liResults = Selector(response).xpath('//li[@class="span3"]')          for li in liResults:              for img in li.xpath('.//img'):                  item = MeiziItem()                  item['title'] = img.xpath('@data-title').extract()                  item['dataid'] = img.xpath('@data-id').extract()                  item['datasrc'] = img.xpath('@data-src').extract()                  item['startcount'] = 0                  yield item

可能很多人看到这就晕菜了。我尽量尝试讲的清楚明白。

首先我们定义了一个类名为dbmeiziSpider的类,继承自Spider类,然后这个类有3个基础的属性,name表示这个爬虫的名字,等一下我们在命令行状态启动爬虫的时候,爬虫的名字就是name规定的。

allowed_domin意思就是指在dbmeizi.com这个域名爬东西。

start_urls是一个数组,里面用来保存需要爬的页面,目前我们只需要爬首页。所以只有一个地址。

然后def parse就是定义了一个parse方法(肯定是override的,我觉得父类里肯定有一个同名方法),然后在这里进行解析工作,这个方法有一个response参数,你可以把response想象成,scrapy这个框架在把start_urls里的页面下载了,然后response里全部都是html代码和css代码。

然后,liResults = Selector(response).xpath('//li[@class="span3"]') 这句话什么意思呢?

这句话的意思就是从html里的最开始一直到最后,搜索所有class="span3"的li标签。

我们获得了li这个标签后,再通过for img in li.xpath('.//img'):这个循环取出所有img标签,最后一个for循环里新建我们之前创建的MeiziItem,然后赋值。

如果实在看不懂,那么你需要看两个东西一个是xpath,一个是我之前写的一片《iOS程序员写爬虫》那篇blog。

Ok,我们的爬虫写好了。

第三步:将我们的MeiziItem存入数据库中

打开settings.py,我们修改成如下样子。

BOT_NAME = 'dbmeizi'  SPIDER_MODULES = ['dbmeizi.spiders']  NEWSPIDER_MODULE = 'dbmeizi.spiders'  ITEM_PIPELINES = ['dbmeizi.pipelines.MongoDBPipeline',]   MONGODB_SERVER = "localhost"  MONGODB_PORT = 27017  MONGODB_DB = "dbmeizi"  MONGODB_COLLECTION = "meizi"  # Crawl responsibly by identifying yourself (and your website) on the user-agent  #USER_AGENT = 'stack (+http://www.yourdomain.com)'

请注意ITEM_PIPELINES那个常数,这个常数是用来规定我们获取爬虫爬下来的数据并将之转为model类型之后应该做什么事。很简单,这个常数告诉我们转为model类型之后区pipelines.py里找MongoDBPipeline这个class。这个class会替我们完成接下来的工作。

下面几个MONGODB打头的常数用来规定MONGODB的一些基本信息,比如server是哪个啊,端口是哪个之类的。

强烈建议自己去简单的学习一下mongodb基础知识。起码会简单的增删改查,在mongodb的shell里多练练,要不然完全看不懂。

在settings.py里修改之后,我们打开pipelines.py。修改如下。

import pymongo  from scrapy.conf import settings  from scrapy.exceptions import DropItem  from scrapy import log  class MongoDBPipeline(object):      def __init__(self):          connection = pymongo.MongoClient(              settings['MONGODB_SERVER'],              settings['MONGODB_PORT']          )          db = connection[settings['MONGODB_DB']]          self.collection = db[settings['MONGODB_COLLECTION']]      def process_item(self, item, spider):          valid = True          for data in item:              if not data:                  valid = False                  raise DropItem("Missing {0}!".format(data))          if valid:              self.collection.insert(dict(item))              log.msg("Meizi added to MongoDB database!",                      level=log.DEBUG, spider=spider)          return item

我们定义了一个类,名字叫做MongoDBPipeline,注意,这个名字是与我们在settings里的ITEM_PIPELINES这个常数里面规定的时一致的。注意别写错了。

init就是python中的构造方法,这个方法里我们主要是建立于mongodb的链接,所以用上了pymongo这个框架。然后将一个collection作为类的一个属性,在mongodb中,一个collection你可以想象成mysql中的一个table。

在process_item这个方法中,我们主要是将item存入数据库。注意self.collection.insert(dict(item))这句话,就是将我们的MeiziItem存入数据库。

ok,大功告成,我们现在运行一下。

1.启动mongodb

Scrapy+Flask+Mongodb+Swift 开发全攻略(1)

2.运行爬虫

Scrapy+Flask+Mongodb+Swift 开发全攻略(1)

3.检查我们的数据库是否有数据

Scrapy+Flask+Mongodb+Swift 开发全攻略(1)

大功告成。

如果你编写的爬虫老是运行不了,首先检查是否用pip安装了需要的框架,或者哪里写错了。

最后放上github地址:

https://github.com/zangqilong198812/DbMeiziScrapy