Pyspider框架(四)

一、项目环境部署

由于pyspider具有各种组件,因此您只需运行pyspider即可启动独立的第三个免费服务实例。或者使用MySQL或MongoDB和RabbitMQ来部署分布式爬网集群。要在产品环境中部署pyspider,在每个进程中运行组件并在数据库服务中存储数据更可靠和更灵活。

1.依赖安装

  • 要在每个进程中部署pyspider组件,至少需要一个数据库服务。

  • pyspider现在支持MySQL、MongoDB和PostgreSQL。你可以从中选一个。

  • 您需要一个消息队列服务来将这些组件连接在一起。您可以使用RabbitMQ、Beanstalk或Redis作为消息队列。

  • 即使您以前使用pip安装过pyspider。要安装MySQL/MongoDB/RabbitMQ的需求,必须使用pyspider[all]安装。pip install pyspider[all]

如果你正在使用Ubuntu(上面是针对windows而言的),试试:
apt-get install python python-dev python-distribute python-pip libcurl4-openssl-dev libxml2-dev libxslt1-dev python-lxml-----这是安装安装二进制包(直接在ubuntu的真实环境下安装),然后在进行pip install pyspider[all]命令来进行安装(在自己创建的虚拟环境下进行)。

2.项目部署

本文档基于MySQL + Redis(此项目所用的工具)

(1)config.json

尽管可以使用命令行指定参数。配置文件是更好的选择。

{
  "taskdb": "mysql+taskdb://username:password@host:port/taskdb",#username代表登录数据库的用户名,password是登录密码,host是数据库在主机上的ip地址,port是数据库端口号,taskdb是使用的数据库名。
  "projectdb": "mysql+projectdb://username:password@host:port/projectdb",
  "resultdb": "mysql+resultdb://username:password@host:port/resultdb",
  "message_queue": "redis://host:6379/db",
  "webui": {
    "username": "some_name",
    "password": "some_passwd",
    "need-auth": true
  }
}

通过运行pyspide --helppyspider webui --help,您可以获得完整的子命令选项。“webui”在JSON中是子命令的配置。您可以为其他类似的组件添加参数。

(2)Database Connection URI

“taskdb”“projectdb”“resultdb”使用数据库连接URI,格式如下:

mysql:
    mysql+type://user:passwd@host:port/database
sqlite:
    # relative path
    sqlite+type:///path/to/database.db
    # absolute path
    sqlite+type:////path/to/database.db
    # memory database
    sqlite+type://
mongodb:
    mongodb+type://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]]
    more: http://docs.mongodb.org/manual/reference/connection-string/
sqlalchemy:
    sqlalchemy+postgresql+type://user:passwd@host:port/database
    sqlalchemy+mysql+mysqlconnector+type://user:passwd@host:port/database
    more: http://docs.sqlalchemy.org/en/rel_0_9/core/engines.html
local:
    local+projectdb://filepath,filepath

type:
    should be one of `taskdb`, `projectdb`, `resultdb`.
(3) Message Queue URL

您可以使用连接URL指定消息队列:

rabbitmq:
    amqp://username:password@host:5672/%2F
    Refer: https://www.rabbitmq.com/uri-spec.html
beanstalk:
    beanstalk://host:11300/
redis:
    redis://host:6379/db
    redis://host1:port1,host2:port2,...,hostn:portn (for redis 3.x in cluster mode)
builtin:
    None

提示:您需要创建自己编码utf8的数据库。pyspider不会自动为您创建数据库。创建数据库和相应的表之后,进行config.json文件配置。最后运行,在webui界面上创建自己的项目。

3.running

您应该使用子命令单独运行组件。您可以在命令后添加&使其在后台运行,并使用screen或nohup来防止ssh会话结束后退出。建议使用Supervisor管理组件。

# start **only one** scheduler instance
pyspider -c config.json scheduler

# phantomjs
pyspider -c config.json phantomjs

# start fetcher / processor / result_worker instances as many as your needs
pyspider -c config.json --phantomjs-proxy="localhost:25555" fetcher
pyspider -c config.json processor
pyspider -c config.json result-worker

# start webui, set `--scheduler-rpc` if scheduler is not running on the same host as webui
pyspider -c config.json webui
create table scrapydoc (
id int primary key auto_increment,
title varchar(128),
url varchar(256) unique,
html mediumblob,
content mediumblob,
`index` int
);#这是创建在结果数据库中表,来记录需要的信息。

注意:当运行出现ImportError: No module named mysql.connector的时候,解决文档如下:https://segmentfault.com/q/1010000006507996/a-1020000006603879(对于这个错误就是就是直接pip install mysql-connector);如果还出现ImportError: No module named redis的话,解决文档如下:(就是直接pip install redis即可)https://blog.csdn.net/hq86937375/article/details/86609939

二、案例

爬取scrapy文档小案例

1.数据库的表设计:

create table res_scrapydoc (
id int primary key auto_increment,
title varchar(128),
url varchar(256) unique,
html mediumblob,
content mediumblob,
`index` int  "为每个爬取的url添加一个序号,以便区别,
但是数据库中不一定按顺序显示,因为每个url爬取的优先级不同"
);

注意:表名的取名不要和项目名一样上面这个表放到结果数据库中。(对于pyspider框架要在数据库中设置3个数据库)

2. 脚本代码如下

#!/usr/bin/env python
# -*- encoding: utf-8 -*-
# Created on 2019-06-19 12:19:32
# Project: scrapydoc

from pyspider.libs.base_handler import *


class Handler(BaseHandler):
    crawl_config = {
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 \
            (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36',
        'itag': '1.5',
        'etag': False,
        'last_modified': False
    }#这里是全局配置,在这里写相当于在所有的crawl中进行相应的设置。

    @every(minutes=24 * 60)
    def on_start(self):
        self.crawl('https://docs.scrapy.org/en/latest/index.html', callback=self.index_page)

    @config(age=10 * 24 * 60 * 60)
    def index_page(self, response):
        #解析出所有的标题url
        urls = response.etree.xpath('//div[@class="wy-menu wy-menu-vertical"]//li/a/@href')
        urls = ['%s%s'%('https://docs.scrapy.org/en/latest/',x) for x in urls]
        #print(urls)
        title = response.etree.xpath('//div[@id="scrapy-version-documentation"]/h1/text()')[0]
        #print(title)
        html = response.text#如果是中文,要进行编码设置。
        content = response.etree.xpath('string(//div[@itemprop="articleBody"])')#加string是获取内容,不加则是一个内容对象。
        #print(content)
        #产生新的任务
        for index, url in enumerate(urls):
            self.crawl(url, callback=self.detail_page, save={'index': index+1})
        return {
            'title': title,
            'html': html,
            'content': content,
            'url': response.url,
            'index': 0
        }

    @config(priority=2)
    def detail_page(self, response):
        title = response.etree.xpath('//div[@itemprop="articleBody"]//h1/text()')[0]
        print(title)
        html = response.text
        content = response.etree.xpath('string(//div[@class="wy-grid-for-nav"]//div[@class="section"])')
        print(content)
        return {
            "url": response.url,
            "title": title,
            "content": content,
            "html": html,
            "index": response.save['index']
        }

3. 自己编写的继承ResultWorker的py文件代码如下(这里创建的是my_resultworker.py文件)

from pyspider.result import ResultWorker


class MyResultworker(ResultWorker):
    def on_result(self, task, result):
        if not result:
            return
        #放我们要存的数据
        #可以写我们自己的接口
        self.resultdb._replace(tablename='res_scrapydoc', **self.resultdb._stringify(result))

        # self.resultdb.dbcur.execute('insert into scrapydoc (`title`, `url`, `html`, `content`, `index`) values (%s, %s, %s, %s, %s)', (result['title'], result['url'], result['html'], result['content'], result['index']))
        #调用父类的方法,使用webui界面查看
        super().on_result(task, {'title': result['title']})



4. config.json文件代码如下

{
  "taskdb": "mysql+taskdb://admin:[email protected]:3306/ps_task",
  "projectdb": "mysql+projectdb://admin:[email protected]:3306/ps_project",
  "resultdb": "mysql+resultdb://admin:[email protected]:3306/ps_result",
  "message_queue": "redis://192.168.212.131:6379/0",
  "webui": {
    "username": "admin",
    "password": "admin",
    "need-auth": true
  },
  "result_worker": {
    "result_cls": "my_resultworker.MyResultworker"
  }#将my_resultworker.py中的MyResultworker注册打这个文件中
}

注意:对于做以上的项目案例步骤是
(1)首先写三个数据库,对于结果数据库创建一个接受结果数据的数据表,但是这个表不能和项目名重名。
(2)进行配置config.json文件
(3)编写爬取相应网站的脚本代码
(4)写完脚本代码后,return后面的结果会存储到ResultWorker里面,所以这里根据自己的需求来写自己的一个类,但这个类必须继承ResultWorker
(5)将自己接受结果的类进行注册(在config.json文件中注册)

你可能感兴趣的:(Pyspider框架(四))