爬虫服务端学习研究(Flask+MongoDB+Nginx)

在笔者浅显的认识中,一个简单的分布式爬虫雏形就是爬虫客户端通过RESTAPI和 爬虫服务端通讯,做的事情应该是发布和领取爬取任务,同时能够将爬取下来数据做一个文件存储,现在开始一个简易的爬虫服务端设计

1.框架

理论上用到的api不会超过10个,所以flask 比较合适,当然擅长Django也可以用Django,作为初级使用,也不会有高并发的前提下,Flask比较轻还是比较好用的。数据库自然是MongoDB了,因为爬取下来的数据格式的很难说不会变吧。 然后自然得用Nginx做转发了
那么先搭建一个基于 MongoDB+Flask+uwsgi+Nginx的简单restful 服务端

2.代码

基本流程就那样,先用 virtualenv 切下Python环境,然后在pip install
具体代码没啥看的,都是比较初级的使用主要,用到几个包是有
1.mongoengine 和MongoDB交互用的
2.apscheduler 弄个定时任务用
3.Flask 不解释了

具体贴一下代码好了
mongo_main.py 用来放数据库ORM的

import threading

from mongoengine import *

connect("spiderdbs")
lock = threading.Lock()

class TargetUrl(Document):
    url=StringField(required=True,unique=True)
    title=StringField(required=True)
    # 0 为爬取 1 爬取中 2爬取完毕
    state=IntField(required=True,default=0)
    #上一次的请求时间
    lastworktime = LongField()
    #完成时间,暂时没用到
    success_time=StringField()

netresult.py 用来放响应数据的,通过 flask的jsonify(),或者json.dumps 返回json格式的响应给客户端

class CommonResult(object):
    def __init__(self,isok):
        self.isok=isok

    def serialize(self):
        return  self.__dict__
    
    
class ErrorResult(CommonResult):
    def __init__(self,error_code,error_msg):
        super().__init__(False)
        self.errorcode=error_code
        self.errormsg=error_msg
        
class SucceessResult(CommonResult):
    def __init__(self,data):
        super().__init__(True)
        self.data=data

然后就是主程序了,flask 确实很轻
myflaskapp.py

import json

from mongoengine import NotUniqueError

import netresult

import time

from mongo_main import TargetUrl,lock
from flask import Flask, abort, Response, request, jsonify

app = Flask(__name__)




@app.route('/spider/<int:id>')
def hello_worldaa(id):
    return 'Hello, World!' + str(id)

#只接受post请求
@app.route('/spider/addwork', methods=["POST"])
def addwork():
    jsondata = request.get_json()
    title = jsondata["title"]
    if not title:
        return jsonify(netresult.ErrorResult("300", "参数错误").serialize())
    url = jsondata["url"]
    if not url:
        return jsonify(netresult.ErrorResult("300", "参数错误").serialize())
    target = TargetUrl(title=str(title), url=str(url))
    try:
        target.save()
    except NotUniqueError:
        return jsonify(netresult.ErrorResult("301", "数据重复").serialize())
    return jsonify(netresult.CommonResult(True).serialize())


@app.route('/spider/queryworks')
def queryworks():
    findobjs=[]
    with lock:
#这里有个要注意的地方,TargetUrl.objects(state=0)[:5]生成的
#列表内容没有立刻加到内存里面去
#(自行去看Python yield)
#在update之前没有全部遍历过一遍的话,update后 findobjs又会变为空集合
        findobjs = TargetUrl.objects(state=0)[:5]
        if (len(findobjs)>0):
        # print([{"url": tar.url, "title": tar.title} for tar in findobjs])
            findobjs.update(state=1, lastworktime=int(time.time()))
    outlist=[{"url": tar.url, "title": tar.title} for tar in findobjs]
    return json.dumps(netresult.SucceessResult({"targets": outlist
                                                }).serialize())

if __name__ == '__main__':
    
    app.run(threaded=True)

在看下定时任务,这个就是每隔一段时间清理掉一些数据,在独立进程中调用就可以了
db_sync.py 使用时 直接 python db_sync.py即可
功能是依赖于apscheduler 实现的,可以去看看相关资料

# coding=utf-8
from apscheduler.schedulers.blocking import BlockingScheduler
import time
import os
from mongo_main import TargetUrl,lock

#避免有任务卡住了,2小时还没有的完成可以当作失败了
timelimt = 7200

def runapp():
    num=TargetUrl.objects(state=1,lastworktime__lt=int(time.time())-timelimt ).update(state=0)
    print(num)



if __name__ == '__main__':
    
    scheduler = BlockingScheduler()
    job = scheduler.add_job(runapp, 'interval', minutes=5)
    print('Press Ctrl+{0} to exit'.format('Break' if os.name == 'nt' else 'C'))
    try:
        scheduler.start()
    except (KeyboardInterrupt, SystemExit):
        scheduler.shutdown()

3.Nginx+ uwsgi

写好的flaskapi还是需要放出来使用的,Nginx+uwsgi安全可靠
配起来也不算麻烦,就搞一下
安装方式略,随便搜一搜一大片
uwsgi安装好后,在flask项目中写一个wsgi.py,用来作为uwsgi控制的入口,py名字可以改,不过这个看起来明白用来干嘛的
wsgi.py

from myflaskapp import app
if __name__ == '__main__':
    app.run()

仔细看是不是没啥用,然后在同一目录下,创建uwsgi.ini,这是uwsgi的配置文件,很有用

[uwsgi]
socket = :3031
module = wsgi:app
processes = 4
threads = 2
master = true
home = /root/pythonenvs/python36/env

需关注 socket 就是端口啦,module 就是flask的入口,也就是我们刚才写看着无用的wsgi.py的目的啦,home是Python的环境目录,可以直接用virtualenv 生成的env环境(我就是这样啦),其他的就复制我的,没错的
保存好了以后
在当前目录敲命令

uwsgi uwsgi.ini

uwsgi 就在3031端口起来了,同时flask app也被拉起来了

然后我们在Nginx里面设置下,所有 spider路径下的请求就转发到uwsgi 的3031端口 也就是发到我们的flask app里面
打开Nginx的配置项,安装完了Nginx以后都会有个默认项,笔者的在
/etc/nginx/sites-enabled/default
在里面插入,别的不要动就好了,然后重启下Nginx,细节还是自己搜索吧,网上也是一大片


location /spider/ {
                   
                 include uwsgi_params;
                 uwsgi_pass 127.0.0.1:3031;

                }

这样就完成了,我们可以用get和post的方式访问和同步数据了,也就是爬虫客户端可以在这台服务器上提交爬取目标和领取爬取任务了

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

推荐阅读更多精彩内容