一、项目环境部署
由于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 --help
和pyspider 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文件中注册)