<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title><![CDATA[运维进行时]]></title> 
<link>https://blog.liuts.com/index.php</link> 
<description><![CDATA[互联网运维与架构]]></description> 
<language>zh-cn</language> 
<copyright><![CDATA[运维进行时]]></copyright>
<item>
<link>https://blog.liuts.com/post/248/</link>
<title><![CDATA[基于Django与Celery实现异步对列任务]]></title> 
<author>刘天斯 &lt;liutiansi@gmail.com&gt;</author>
<category><![CDATA[Python]]></category>
<pubDate>Tue, 18 Aug 2015 11:42:06 +0000</pubDate> 
<guid>https://blog.liuts.com/post/248/</guid> 
<description>
<![CDATA[ 
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在运营系统中经常用到异步方式来处理我们的任务，比如将业务上线流程串成任务再写入队列，通过后台作业节点去调度执行。比较典型的案例为腾讯的蓝鲸、织云、云智慧等平台。本译文结合Django+Celery+Redis实现一个定期从Flickr 获取图片并展示的简单案例，方便大家理解实现异步对列任务的过程。<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;刚接触django的时候，我经历过的最让人沮丧的事情是需要定期运行一段代码。我写了一个需要每天上午12点执行一个动作的不错的函数。很简单是不是？错了。事实证明，这对我来说是一个巨大的困难点，因为，那时我使用Cpane类型的虚拟主机管理系统，它能专门提供一个很友好，很方便的图形用户界面来设置cron作业。<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 经过反复研究，我发现了一个很好的解决方案 - Celery，一个用于在后台运行任务的强大的异步作业队列。但是，这也导致了其它的问题，因为我无法找到一系列简单的指令将celery集成到Django项目中。<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 当然，我最终还是设法成功搞定了它 - 这正是本文将介绍的内容：如何将celery集成到一个Django项目，创建周期性任务。<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 该项目利用Python3.4，Django的1.8.2，celery3.1.18和Redis3.0.2.<br/><br/><strong>一、概述</strong><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 由于大篇幅的文字，为了您的方便，请参阅下表中的每一步的简要信息，并获取相关的代码。<br/>步骤&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;概要&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Git标签<br/>样板&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;样板下载&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="https://github.com/realpython/Picha/releases/tag/v1" target="_blank">V1</a><br/>建立&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;集成Celery和Django&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="https://github.com/realpython/Picha/releases/tag/v2" target="_blank">V2</a><br/>Celery任务&nbsp;&nbsp;&nbsp;&nbsp;添加基本的Celery任务&nbsp;&nbsp;&nbsp;&nbsp;<a href="https://github.com/realpython/Picha/releases/tag/v3" target="_blank">V3</a><br/>周期性任务&nbsp;&nbsp;&nbsp;&nbsp;添加周期性任务&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="https://github.com/realpython/Picha/releases/tag/v4" target="_blank">V4</a><br/>本地运行&nbsp;&nbsp;&nbsp;&nbsp;本地运行我们的应用程序&nbsp;&nbsp;&nbsp;&nbsp;<a href="https://github.com/realpython/Picha/releases/tag/v5" target="_blank">V5</a><br/>远程运行&nbsp;&nbsp;&nbsp;&nbsp;远程运行我们的应用程序&nbsp;&nbsp;&nbsp;&nbsp;<a href="https://github.com/realpython/Picha/releases/tag/v5" target="_blank">V5</a><br/><br/><strong>二、什么是Celery</strong><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; “Celery是一个异步任务队列/基于分布式消息传递的作业队列。它侧重于实时操作，但对调度的支持也很好。”本文，我们将重点讲解周期性执行任务的调度特点。<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 为什么这一点有用呢？<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;•回想一下你不得不在将来运行某一特定任务的经历。也许你需要每隔一小时访问一个API。或者，也许你需要在这一天结束时发送一批电子邮件。不论任务大小，Celery都可以使得调度周期性任务变的很容易。<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;•你永远不希望终端用户等待那些不必要的页面加载或动作执行完成。如果你的应用程序工作流的一部分是一个需要很长时间的程序，当资源可用时，你就可以使用Celery在后台执行这段程序，从而使你的应用程序可以继续响应客户端的请求。这样可以使任务在应用程序的环境之外运行。<br/><br/><strong>三、构建项目</strong><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在深入了解Celery之前，先从Github库中获取开始项目。确保激活一个虚拟的环境，安装必要的软件，并运行迁移。然后启动服务器，通过你的浏览器导航到http://localhost:8000/。你应当能看到‘恭喜你的第一个Django页面’。完成后，关闭服务器。<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 接下来，我们开始安装celery。<br/><textarea name="code" class="c" rows="15" cols="100">
$ pip install celery==3.1.18
$ pip freeze > requirements.txt
</textarea><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 现在，我们通过简单的三步将celery集成到django项目中。<br/><strong>步骤一：创建celery.py</strong><br/>在“picha“目录下，创建celery.py，代码如下：<br/><textarea name="code" class="python" rows="15" cols="100">
from __future__ import absolute_import
import os
from celery import Celery
from django.conf import settings

# set the default Django settings module for the 'celery' program.
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'picha.settings')
app = Celery('picha')

# Using a string here means the worker will not have to
# pickle the object when using Windows.
app.config_from_object('django.conf:settings')
app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)


@app.task(bind=True)
def debug_task(self):
&nbsp;&nbsp;&nbsp;&nbsp;print('Request: &#123;0!r&#125;'.format(self.request))
</textarea><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 请注意代码中的注释。<br/><strong>步骤二：引入celery应用</strong><br/>为了确保在django启动时加载了celery应用，在settings.py旁边新建__init__.py，并添加以下代码到__init__.py中。<br/><textarea name="code" class="python" rows="15" cols="100">
from __future__ import absolute_import

# This will make sure the app is always imported when
# Django starts so that shared_task will use this app.
from .celery import app as celery_app
</textarea><br/>完成以上步骤后，你的项目目录应该是这样的：<br/><textarea name="code" class="c" rows="15" cols="100">
├── manage.py
├── picha
│&nbsp;&nbsp; ├── __init__.py
│&nbsp;&nbsp; ├── celery.py
│&nbsp;&nbsp; ├── settings.py
│&nbsp;&nbsp; ├── urls.py
│&nbsp;&nbsp; └── wsgi.py
└── requirements.txt
</textarea><br/><strong>步骤三：安装 Redis作为Celery的“中间件”</strong><br/>&nbsp;&nbsp;&nbsp;&nbsp;Celery使用中间件在django项目与celery监控者之间传递消息。在本教程中，我们使用redis作为消息中间代理。<br/>首先，从官方下载页面或通过brew（BREW安装Redis）安装Redis，然后打开你的终端上，在一个新的终端窗口，启动服务器：<br/><textarea name="code" class="c" rows="15" cols="100">
$ redis-server
</textarea><br/>你可以通过在终端中输入如下命令测试Redis是否正常工作。<br/><textarea name="code" class="c" rows="15" cols="100">
$ redis-cli ping
</textarea><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Redis应该回复PONG - 试试吧！<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一旦Redis正常启动了，把下面的代码添加到你的settings.py文件中：<br/><textarea name="code" class="python" rows="15" cols="100">
# CELERY STUFF
BROKER_URL = 'redis://localhost:6379'
CELERY_RESULT_BACKEND = 'redis://localhost:6379'
CELERY_ACCEPT_CONTENT = ['application/json']
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'
CELERY_TIMEZONE = 'Africa/Nairobi'
</textarea><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 你还需要添加Redis的作为Django项目的依赖：<br/><textarea name="code" class="c" rows="15" cols="100">
$ pip install redis==2.10.3
$ pip freeze > requirements.txt
</textarea><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 就是这样了！你现在应该能够在Django中使用Celery。有关设置Celery与Django的更多信息，请查看官方Celery文档。<br/>在继续下面步骤之前，让我们进行一些完整性检查，以确保一切都是正常的。<br/>测试Celery worker已准备好接收任务：<br/><textarea name="code" class="c" rows="15" cols="100">
$ celery -A picha worker -l info
...
[2015-07-07 14:07:07,398: INFO/MainProcess] Connected to redis://localhost:6379//
[2015-07-07 14:07:07,410: INFO/MainProcess] mingle: searching for neighbors
[2015-07-07 14:07:08,419: INFO/MainProcess] mingle: all alone
</textarea><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 使用CTRL-C杀死该段程序。现在，测试Celery任务调度程序是否已经准备好：<br/><textarea name="code" class="c" rows="15" cols="100">
$ celery -A picha beat -l info
...
[2015-07-07 14:08:23,054: INFO/MainProcess] beat: Starting...
</textarea><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在上述完成时再次终止该进程。<br/><br/><strong>1、Celery任务</strong><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Celery利用celery调用的常规Python函数作为任务。<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 例如，让我们把这个基本函数变为celery的任务：<br/><textarea name="code" class="python" rows="15" cols="100">
def add(x, y):
&nbsp;&nbsp;&nbsp;&nbsp;return x + y
</textarea><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 首先，添加一个装饰器。<br/><textarea name="code" class="python" rows="15" cols="100">
from celery.decorators import task

@task(name="sum_two_numbers")
def add(x, y):
&nbsp;&nbsp;&nbsp;&nbsp;return x + y
</textarea><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 然后你可以通过以下方式利用celery异步运行该任务：<br/><textarea name="code" class="python" rows="15" cols="100">
add.delay(7, 8)
</textarea><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 很简单，对不对？<br/>所以，这对于解决类似你要加载一个网页，而不需要用户等待一些后台程序的完成这些类型的任务来说是非常完美的。<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;让我们来看一个例子...<br/>让我们再回到Django项目的版本3，它包括一个接受来自用户的反馈的应用程序，人们形象地称之为反馈：<br/><textarea name="code" class="c" rows="15" cols="100">
├── feedback
│&nbsp;&nbsp; ├── __init__.py
│&nbsp;&nbsp; ├── admin.py
│&nbsp;&nbsp; ├── emails.py
│&nbsp;&nbsp; ├── forms.py
│&nbsp;&nbsp; ├── models.py
│&nbsp;&nbsp; ├── tests.py
│&nbsp;&nbsp; └── views.py
├── manage.py
├── picha
│&nbsp;&nbsp; ├── __init__.py
│&nbsp;&nbsp; ├── celery.py
│&nbsp;&nbsp; ├── settings.py
│&nbsp;&nbsp; ├── urls.py
│&nbsp;&nbsp; └── wsgi.py
├── requirements.txt
└── templates
&nbsp;&nbsp;&nbsp;&nbsp;├── base.html
&nbsp;&nbsp;&nbsp;&nbsp;└── feedback
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;├── contact.html
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;└── email
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;├── feedback_email_body.txt
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;└── feedback_email_subject.txt
</textarea><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 安装新的必要软件，启动应用程序，并导航到http://localhost:8000/feedback/。你应该看到如下结果：<br/><a href="https://blog.liuts.com/attachment.php?fid=376" target="_blank"><img src="https://blog.liuts.com/attachment.php?fid=376" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/>让我们连接celery任务。<br/><br/><strong>2、添加任务</strong><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 基本上，用户提交反馈表后，我们希望让他继续以他舒服的方式往下进行，而我们在后台进行处理反馈，发送电子邮件等等。<br/>要做到这一点，首先添加一个叫tasks.py的文件到“feedback”目录：<br/><textarea name="code" class="python" rows="15" cols="100">
from celery.decorators import task
from celery.utils.log import get_task_logger

from feedback.emails import send_feedback_email

logger = get_task_logger(__name__)


@task(name="send_feedback_email_task")
def send_feedback_email_task(email, message):
&nbsp;&nbsp;&nbsp;&nbsp;"""sends an email when feedback form is filled successfully"""
&nbsp;&nbsp;&nbsp;&nbsp;logger.info("Sent feedback email")
&nbsp;&nbsp;&nbsp;&nbsp;return send_feedback_email(email, message)
</textarea><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 然后按照如下内容更新forms.py：<br/><textarea name="code" class="python" rows="15" cols="100">
from django import forms
from feedback.tasks import send_feedback_email_task


class FeedbackForm(forms.Form):
&nbsp;&nbsp;&nbsp;&nbsp;email = forms.EmailField(label="Email Address")
&nbsp;&nbsp;&nbsp;&nbsp;message = forms.CharField(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;label="Message", widget=forms.Textarea(attrs=&#123;'rows': 5&#125;))
&nbsp;&nbsp;&nbsp;&nbsp;honeypot = forms.CharField(widget=forms.HiddenInput(), required=False)

&nbsp;&nbsp;&nbsp;&nbsp;def send_email(self):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# try to trick spammers by checking whether the honeypot field is
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# filled in; not super complicated/effective but it works
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if self.cleaned_data['honeypot']:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return False
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;send_feedback_email_task.delay(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.cleaned_data['email'], self.cleaned_data['message'])
</textarea><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 大体上，send_feedback_email_task.delay(email, message)的函数过程，并发送反馈电子邮件等都是在用户继续使用该网站的同时作为后台进程运行。<br/>注：在views.py中的success_url被设置为将用户重定向到/ 目录，这个目录还不存在。我们会在下一节设置这个终点启动。<br/><br/><strong>3、周期任务</strong><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 通常情况下，你经常需要安排一个任务在特定的时间运行 - 例如，一个web scraper 可能需要每天都运行。这样的任务，被称为周期性任务，很容易建立利用celery启动。<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; celery使用“celery beat”来安排定期任务。celery beat定期运行任务，然后由celery worker执行任务。<br/>例如，下面的任务计划每15分钟运行一次：<br/><textarea name="code" class="python" rows="15" cols="100">
from celery.task.schedules import crontab
from celery.decorators import periodic_task


@periodic_task(run_every=(crontab(minute='*/15')), name="some_task", ignore_result=True)
def some_task():
&nbsp;&nbsp;&nbsp;&nbsp;# do something
</textarea><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 让我们通过往Django项目中添加功能来看一个更强大的例子。<br/>回到Django项目版本4，它包括另一个新的应用程序，叫做photos，这个应用程序使用 Flickr API获取新照片用来显示在网站：<br/><textarea name="code" class="c" rows="15" cols="100">
├── feedback
│&nbsp;&nbsp; ├── __init__.py
│&nbsp;&nbsp; ├── admin.py
│&nbsp;&nbsp; ├── emails.py
│&nbsp;&nbsp; ├── forms.py
│&nbsp;&nbsp; ├── models.py
│&nbsp;&nbsp; ├── tasks.py
│&nbsp;&nbsp; ├── tests.py
│&nbsp;&nbsp; └── views.py
├── manage.py
├── photos
│&nbsp;&nbsp; ├── __init__.py
│&nbsp;&nbsp; ├── admin.py
│&nbsp;&nbsp; ├── models.py
│&nbsp;&nbsp; ├── settings.py
│&nbsp;&nbsp; ├── tests.py
│&nbsp;&nbsp; ├── utils.py
│&nbsp;&nbsp; └── views.py
├── picha
│&nbsp;&nbsp; ├── __init__.py
│&nbsp;&nbsp; ├── celery.py
│&nbsp;&nbsp; ├── settings.py
│&nbsp;&nbsp; ├── urls.py
│&nbsp;&nbsp; └── wsgi.py
├── requirements.txt
└── templates
&nbsp;&nbsp;&nbsp;&nbsp;├── base.html
&nbsp;&nbsp;&nbsp;&nbsp;├── feedback
&nbsp;&nbsp;&nbsp;&nbsp;│&nbsp;&nbsp; ├── contact.html
&nbsp;&nbsp;&nbsp;&nbsp;│&nbsp;&nbsp; └── email
&nbsp;&nbsp;&nbsp;&nbsp;│&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ├── feedback_email_body.txt
&nbsp;&nbsp;&nbsp;&nbsp;│&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; └── feedback_email_subject.txt
&nbsp;&nbsp;&nbsp;&nbsp;└── photos
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;└── photo_list.html
</textarea><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 安装新的必要软件，运行迁移，然后启动服务器，以确保一切都是好的。重新测试反馈表。这次，它应该重定向好了。<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 下一步是什么？<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 既然我们需要周期性的调用Flickr API，以获取更多的照片添加到我们的网站，我们可以添加一个celery任务。<br/><br/><strong>4、添加任务</strong><br/>往photos应用中添加一个tasks.py。<br/><textarea name="code" class="python" rows="15" cols="100">
from celery.task.schedules import crontab
from celery.decorators import periodic_task
from celery.utils.log import get_task_logger

from photos.utils import save_latest_flickr_image

logger = get_task_logger(__name__)


@periodic_task(
&nbsp;&nbsp;&nbsp;&nbsp;run_every=(crontab(minute='*/15')),
&nbsp;&nbsp;&nbsp;&nbsp;name="task_save_latest_flickr_image",
&nbsp;&nbsp;&nbsp;&nbsp;ignore_result=True
)
def task_save_latest_flickr_image():
&nbsp;&nbsp;&nbsp;&nbsp;"""
&nbsp;&nbsp;&nbsp;&nbsp;Saves latest image from Flickr
&nbsp;&nbsp;&nbsp;&nbsp;"""
&nbsp;&nbsp;&nbsp;&nbsp;save_latest_flickr_image()
&nbsp;&nbsp;&nbsp;&nbsp;logger.info("Saved image from Flickr")
</textarea><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在这里，我们通过在一个task中包装这个函数，来实现每15分钟运行一次save_latest_flickr_image()函数。该@periodic_task装饰器抽象出代码来运行celery任务，使得tasks.py干净，易于阅读！<br/><br/><strong>5、本地运行</strong><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 准备开始运行了？<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在Django应用程序和Redis运行的前提下，打开两个新的终端窗口/标签。在每一个新的窗口中，导航到你的项目目录，激活你的虚拟环境，然后运行下面的命令（每个窗口一个）：<br/><textarea name="code" class="c" rows="15" cols="100">
$ celery -A picha worker -l info
$ celery -A picha beat -l info
</textarea><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 当你访问http://127.0.0.1:8000/ 网址的时候，你现在应该能看到一个图片。我们的应用程序每15分钟从Flickr 获取一张图片。<br/><a href="https://blog.liuts.com/attachment.php?fid=377" target="_blank"><img src="https://blog.liuts.com/attachment.php?fid=377" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/><a href="https://blog.liuts.com/attachment.php?fid=378" target="_blank"><img src="https://blog.liuts.com/attachment.php?fid=378" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/>通过photos/tasks.py查看代码。点击“Feedback”按钮发送一些反馈意见：<br/><a href="https://blog.liuts.com/attachment.php?fid=379" target="_blank"><img src="https://blog.liuts.com/attachment.php?fid=379" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/><a href="https://blog.liuts.com/attachment.php?fid=380" target="_blank"><img src="https://blog.liuts.com/attachment.php?fid=380" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 以上是通过celery任务运行的。更多的请查看<span style="color: #FF4500;">feedback/tasks.py</span>。<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 就这样，你成功的启动并运行了 Picha项目！<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 当你本地开发Django项目时，这是一个很好的测试，但是当你需要部署到生产环境- 就像 DigitalOcean时，就不那么合适了。为此，建议你通过使用Supervisor在后台作为一个守护进程运行celery worker和调度器。<br/><br/><strong>6、远程运行</strong><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 安装很简单。从版本库中获取版本5（如果你还没有的话）。然后，SSH到远程服务器，并运行：<br/><textarea name="code" class="c" rows="15" cols="100">
$ sudo apt-get install supervisor
</textarea><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 然后，通过在远程服务器上“/etc/supervisor/conf.d/” 目录下添加配置文件来告知Supervisor celery的workers。在我们的例子中，我们需要两个这样的配置文件 - 一个用于Celery worker，一个是Celery scheduler。<br/>在本地，在项目的根目录下创建一个“supervisor”的文件夹，然后添加下面的文件。<br/><span style="color: #8B0000;">Celery Worker: picha_celery.conf</span><br/><textarea name="code" class="python" rows="15" cols="100">
; ==================================
;&nbsp;&nbsp;celery worker supervisor example
; ==================================

; the name of your supervisord program
[program:pichacelery]

; Set full path to celery program if using virtualenv
command=/home/mosh/.virtualenvs/picha/bin/celery worker -A picha --loglevel=INFO

; The directory to your Django project
directory=/home/mosh/sites/picha

; If supervisord is run as the root user, switch users to this UNIX user account
; before doing any processing.
user=mosh

; Supervisor will start as many instances of this program as named by numprocs
numprocs=1

; Put process stdout output in this file
stdout_logfile=/var/log/celery/picha_worker.log

; Put process stderr output in this file
stderr_logfile=/var/log/celery/picha_worker.log

; If true, this program will start automatically when supervisord is started
autostart=true

; May be one of false, unexpected, or true. If false, the process will never
; be autorestarted. If unexpected, the process will be restart when the program
; exits with an exit code that is not one of the exit codes associated with this
; process’ configuration (see exitcodes). If true, the process will be
; unconditionally restarted when it exits, without regard to its exit code.
autorestart=true

; The total number of seconds which the program needs to stay running after
; a startup to consider the start successful.
startsecs=10

; Need to wait for currently executing tasks to finish at shutdown.
; Increase this if you have very long running tasks.
stopwaitsecs = 600

; When resorting to send SIGKILL to the program to terminate it
; send SIGKILL to its whole process group instead,
; taking care of its children as well.
killasgroup=true

; if your broker is supervised, set its priority higher
; so it starts first
priority=998
</textarea><br/><span style="color: #8B0000;">Celery Scheduler: picha_celerybeat.conf</span><br/><textarea name="code" class="python" rows="15" cols="100">
; ================================
;&nbsp;&nbsp;celery beat supervisor example
; ================================

; the name of your supervisord program
[program:pichacelerybeat]

; Set full path to celery program if using virtualenv
command=/home/mosh/.virtualenvs/picha/bin/celerybeat -A picha --loglevel=INFO

; The directory to your Django project
directory=/home/mosh/sites/picha

; If supervisord is run as the root user, switch users to this UNIX user account
; before doing any processing.
user=mosh

; Supervisor will start as many instances of this program as named by numprocs
numprocs=1

; Put process stdout output in this file
stdout_logfile=/var/log/celery/picha_beat.log

; Put process stderr output in this file
stderr_logfile=/var/log/celery/picha_beat.log

; If true, this program will start automatically when supervisord is started
autostart=true

; May be one of false, unexpected, or true. If false, the process will never
; be autorestarted. If unexpected, the process will be restart when the program
; exits with an exit code that is not one of the exit codes associated with this
; process’ configuration (see exitcodes). If true, the process will be
; unconditionally restarted when it exits, without regard to its exit code.
autorestart=true

; The total number of seconds which the program needs to stay running after
; a startup to consider the start successful.
startsecs=10

; if your broker is supervised, set its priority higher
; so it starts first
priority=999
</textarea><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 注：确保更新这些文件的路径，以匹配你的远程服务器的文件系统。<br/>基本上，这些supervisor 配置文件告诉supervisord如何运行并管理我们的'programs'（因为它们是由supervisord调用）。<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在上面的例子中，我们已经创建了两个名为“pichacelery”和“pichacelerybeat”的supervisord程序。<br/>现在，只需将这些文件拷贝到远程服务器的/etc/supervisor/conf.d/目录下。<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 我们还需要在远程服务器上创建上面脚本中提到的日志文件：<br/><textarea name="code" class="c" rows="15" cols="100">
$ touch /var/log/celery/picha_worker.log
$ touch /var/log/celery/picha_beat.log
</textarea><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 最后，运行以下命令，使 Supervisor 知道它所管理的程序的存在 - 例如，pichacelery和pichacelerybeat：<br/><textarea name="code" class="c" rows="15" cols="100">
$ sudo supervisorctl reread
$ sudo supervisorctl update
</textarea><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 运行以下命令停止，启动，和/或检查pichacelery程序的状态：<br/><textarea name="code" class="c" rows="15" cols="100">
$ sudo supervisorctl stop pichacelery
$ sudo supervisorctl start pichacelery
$ sudo supervisorctl status pichacelery
</textarea><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 你可以通过阅读官方文档获取Supervisor的更多信息。<br/><br/><strong>7、最后提示</strong><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1. 千万不要传递Django模型对象到celery任务。为了避免模型对象在传递给celery任务之前已经改变了，传递celery的主键给celery。然后，在运行之前使用主键从数据库中获取对象。<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2. 默认celery调度会在本地创建一些文件存储它的调度表。这些文件是“celerybeat-schedule.db”和“celerybeat.pid”。如果你在使用版本控制系统，比如Git（你应该使用！），请忽略这个文件，不要将它们添加到你的代码库中，因为它们是为本地运行的进程服务的。<br/><br/><strong>8、下一步</strong><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 以上就是将celery集成到一个django项目的基本介绍。<br/>想要更多？<br/>1. 深入研究官方celery用户指南，以了解更多信息。<br/>2. 创建一个Fabfile来设置Supervisor和配置文件。确保添加命令到reread和 update Supervisor。<br/>3. 从repo中获取这个项目，并打开一个Pull 请求来添加一个新的celery任务。<br/>编码快乐！<br/><br/>原文：<a href="https://realpython.com/blog/python/asynchronous-tasks-with-django-and-celery/" target="_blank">https://realpython.com/blog/python/asynchronous-tasks-with-django-and-celery/</a><br/>Tags - <a href="https://blog.liuts.com/tags/django/" rel="tag">django</a> , <a href="https://blog.liuts.com/tags/celery/" rel="tag">celery</a> , <a href="https://blog.liuts.com/tags/%25E5%25BC%2582%25E6%25AD%25A5/" rel="tag">异步</a> , <a href="https://blog.liuts.com/tags/%25E4%25BB%25BB%25E5%258A%25A1/" rel="tag">任务</a> , <a href="https://blog.liuts.com/tags/%25E5%25AF%25B9%25E5%2588%2597/" rel="tag">对列</a>
]]>
</description>
</item><item>
<link>https://blog.liuts.com/post/246/</link>
<title><![CDATA[《python自动化运维：技术与最佳实践》之OMServer平台环境部署详解【主控制端】]]></title> 
<author>刘天斯 &lt;liutiansi@gmail.com&gt;</author>
<category><![CDATA[Python]]></category>
<pubDate>Sat, 20 Dec 2014 22:34:26 +0000</pubDate> 
<guid>https://blog.liuts.com/post/246/</guid> 
<description>
<![CDATA[ 
	<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;主控端是OMServer的核心角色，负责接收加密的协议串且进行解密，解析成OMServer调用的任务模块，同时结合角色中的saltstack、ansible或func组件，向目标业务服务器集群（被控机）发送执行任务，执行完毕后，将返回的执行结果加解密处理，最后逐级返回给系统管理员，角色所在位置见以下架构图：<br/><a href="https://blog.liuts.com/attachment.php?fid=366" target="_blank"><img src="https://blog.liuts.com/attachment.php?fid=366" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/><strong>一、环境部署</strong><br/>1、部署saltstack、ansible或func组件，详细见本书相关章节，此处省略；<br/><br/>2、安装rpyc模块<br/><textarea name="code" class="c" rows="15" cols="100">
# wget https://pypi.python.org/packages/source/r/rpyc/rpyc-3.2.3.tar.gz --no-check-certificate
# tar -zxvf rpyc-3.2.3.tar.gz
# cd rpyc-3.2.3
# python setup.py install
</textarea><br/>3、下载主控端源码<br/>#cd /home <br/>download github地址：https://github.com/yorkoliu/pyauto/tree/master/第十三章/OMServer<br/><br/>修改OMServer/config.py主配置文件<br/><textarea name="code" class="python" rows="15" cols="100">
# -*- coding: utf-8 -*-
#!/usr/bin/env python
AUTO_PLATFORM = "saltstack"&nbsp;&nbsp;&nbsp;&nbsp;#指定组件环境，支持saltstack、ansible、func

#密钥，与项目中setting.py的SECRET_KEY变量保持一致
SECRET_KEY = "ctmj#&amp;8hrgow_^sj$ejt@9fzsmh_o)-=(byt5jmg=e3#foya6u"
</textarea><br/>4、编写任务模块<br/>&nbsp;&nbsp;&nbsp;&nbsp;1）在WEB前端点击【添加模块】，指定模块名称、描述、参数接口信息，提交后记录生成的模块ID（数字）；<br/>&nbsp;&nbsp;&nbsp;&nbsp;2）在主控端OMServer/modules目录存放了各个组件的模块，以不同目录名作为区分，任务模块名称由“Mid_”+模块ID组成，与前端生成的模块ID进行关联，如Mid_1007.py，可参考现有示例进行修改。<br/><br/>5、启动服务<br/><textarea name="code" class="c" rows="15" cols="100">
&nbsp;&nbsp;&nbsp;&nbsp;# cd /home/OMServer
&nbsp;&nbsp;&nbsp;&nbsp;# python OMservermain.py &

&nbsp;&nbsp;&nbsp;&nbsp;检查11511端口是否已监听
&nbsp;&nbsp;&nbsp;&nbsp;# netstat -an&#124;grep 11511
</textarea><br/><br/><strong>二、校验环境</strong><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;最后，打开浏览器访问http://omserver.domain.com（自定义域名，可通过修改hosts实现），效果图如下。<br/><a href="https://blog.liuts.com/attachment.php?fid=367" target="_blank"><img src="https://blog.liuts.com/attachment.php?fid=367" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/><br/><strong>三、基于Python构建可扩展的自动化运维平台（WOT分享主题）</strong><br/><iframe src="//www.slideshare.net/slideshow/embed_code/42901993?startSlide=2" width="510" height="420" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" style="border:1px solid #CCC; border-width:1px; margin-bottom:5px; max-width: 100%;" allowfullscreen> </iframe> <div style="margin-bottom:5px"> <strong> <a href="//www.slideshare.net/liutiansi/python-42901993" title="基于Python构建可扩展的自动化运维平台" target="_blank">基于Python构建可扩展的自动化运维平台</a> </strong> from <strong><a href="//www.slideshare.net/liutiansi" target="_blank">我在slideshare.net上的所有分享</a></strong> </div><br/>Tags - <a href="https://blog.liuts.com/tags/python%25E8%2587%25AA%25E5%258A%25A8%25E5%258C%2596%25E8%25BF%2590%25E7%25BB%25B4%25EF%25BC%259A%25E6%258A%2580%25E6%259C%25AF%25E4%25B8%258E%25E6%259C%2580%25E4%25BD%25B3%25E5%25AE%259E%25E8%25B7%25B5/" rel="tag">python自动化运维：技术与最佳实践</a> , <a href="https://blog.liuts.com/tags/python/" rel="tag">python</a> , <a href="https://blog.liuts.com/tags/omserver/" rel="tag">omserver</a> , <a href="https://blog.liuts.com/tags/%25E7%258E%25AF%25E5%25A2%2583%25E9%2583%25A8%25E7%25BD%25B2/" rel="tag">环境部署</a>
]]>
</description>
</item><item>
<link>https://blog.liuts.com/post/245/</link>
<title><![CDATA[《python自动化运维：技术与最佳实践》之OMServer平台环境部署详解【Web服务端】]]></title> 
<author>刘天斯 &lt;liutiansi@gmail.com&gt;</author>
<category><![CDATA[Python]]></category>
<pubDate>Sun, 07 Dec 2014 05:11:55 +0000</pubDate> 
<guid>https://blog.liuts.com/post/245/</guid> 
<description>
<![CDATA[ 
	<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 《python自动化运维：技术与最佳实践》书籍发布已经1个月有余，根据读者反馈，在部署OMServer平台时遇到很多困难及问题，尤其是第一次部署Django环境的读者。因此，作者对书籍中OMServer环境部署章节的内容进行扩充，以便让每位读者都可以轻易完成平台搭建。OMServer平台涉及两个角色，其中一个为Web服务端，运行在Django及rpyc环境，另一角色为主控端，需要部署saltstack、ansible或func主控端环境，本文介绍Web服务端的部署详细步骤。<br/><br/>---环境版本说明---<br/>* Python&nbsp;&nbsp;版本&nbsp;&nbsp;2.6.6<br/>* Django&nbsp;&nbsp;版本&nbsp;&nbsp; 1.4.9<br/>* nginx&nbsp;&nbsp;版本&nbsp;&nbsp;1.5.9<br/>* pcre&nbsp;&nbsp;版本&nbsp;&nbsp;8.34<br/>* rpyc&nbsp;&nbsp;版本&nbsp;&nbsp;3.2.3<br/>* uwsgi&nbsp;&nbsp;版本&nbsp;&nbsp;2.0.4<br/>* django-debug-toolbar&nbsp;&nbsp;版本&nbsp;&nbsp;0.8.5<br/><br/> <strong>一、Django环境部署</strong><br/><textarea name="code" class="c" rows="15" cols="100">
# yum install -y zlib-devel #Nginx环境初始化，安装gzip包
# yum -y install python-devel mysql-devel zlib-devel openssl-devel&nbsp;&nbsp;#MySQL-python关联包

# mkdir –p /data/logs/&nbsp;&nbsp;&nbsp;&nbsp;#创建uwsgi日志目录
# mkdir –p /data/www/&nbsp;&nbsp;&nbsp;&nbsp;#创建项目目录
# mkdir -p /home/install/Django && cd /home/install/Django&nbsp;&nbsp;&nbsp;&nbsp;#创建安装包目录
</textarea><br/>1、安装pcre，pcre是一个轻量级的正则表达式函数库，Nginx的HTTP Rewrite模块会用到，最新版本为8.34（对于OMServer平台环境来说是非必选项）。<br/><textarea name="code" class="c" rows="15" cols="100">
# wget ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-8.34.tar.gz
# tar -zxvf pcre-8.34.tar.gz
# cd pcre-8.34
#./configure
# make && make install
# cd ..
</textarea><br/>2、安装Nginx，Nginx是最流行的高性能HTTP服务器，最新版本为1.5.9。<br/><textarea name="code" class="c" rows="15" cols="100">
# wget http://nginx.org/download/nginx-1.5.9.tar.gz
# tar -zxvf nginx-1.5.9.tar.gz
# cd nginx-1.5.9
#./configure --user=nobody --group=nobody --prefix=/usr/local/nginx --with-http_stub_status_module --with-cc-opt='-O3' --with-cpu-opt=opteron
# make && make install
# cd ..
</textarea><br/>3、安装 MySQL-python，MySQL-python是Python访问MySQL数据库的第三方模块库，最新版本为1.2.3c1。<br/><textarea name="code" class="c" rows="15" cols="100">
# wget http://pypi.python.org/packages/source/M/MySQL-python/MySQL-python-1.2.5.zip --no-check-certificate
# unzip MySQL-python-1.2.5.zip
# cd MySQL-python-1.2.5
# python setup.py install
# cd ..
</textarea><br/>4、rpyc模块安装，用于平台与主控端做数据通讯交互。<br/><textarea name="code" class="c" rows="15" cols="100">
# wget https://pypi.python.org/packages/source/r/rpyc/rpyc-3.2.3.tar.gz --no-check-certificate
# tar -zxvf rpyc-3.2.3.tar.gz
# cd rpyc-3.2.3
# python setup.py install
</textarea><br/>5、安装uwsgi。uwsgi是一个快速的、纯C语言开发的、自维护、对开发者友好的WSGI服务器，旨在提供专业的Python web应用发布和开发，最新版本为2.0.4。<br/><textarea name="code" class="c" rows="15" cols="100">
# wget http://projects.unbit.it/downloads/uwsgi-2.0.4.tar.gz
# tar -zxvf uwsgi-2.0.4.tar.gz
# cd uwsgi-2.0.4
# make
</textarea><br/>出现如下代码成功安装：<br/>################# uWSGI configuration #################<br/>pcre = True<br/>kernel = Linux<br/>malloc = libc<br/>execinfo = False<br/>ifaddrs = True<br/>ssl = True<br/>zlib = True<br/>locking = pthread_mutex<br/>plugin_dir = .<br/>timer = timerfd<br/>yaml = embedded<br/>json = False<br/>filemonitor = inotify<br/>routing = True<br/>debug = False<br/>capabilities = False<br/>xml = False<br/>event = epoll<br/>############## end of uWSGI configuration #############<br/>total build time: 17 seconds<br/>*** uWSGI is ready, launch it with ./uwsgi ***<br/><textarea name="code" class="c" rows="15" cols="100">
# vi /etc/ld.so.conf&nbsp;&nbsp;&nbsp;&nbsp;#添加动态链接库目录/usr/local/lib
添加行：/usr/local/lib
# ldconfig&nbsp;&nbsp;&nbsp;&nbsp;#使之生效

# cp uwsgi /usr/bin
# cd ..
</textarea><br/>6、安装Django，Django是一个Python最流行的开源Web开发框架，最新版本为1.6.5。考虑到兼容与稳定性，本案例使用1.4.9版本进行开发。<br/><textarea name="code" class="c" rows="15" cols="100">
# wget https://www.djangoproject.com/m/releases/1.4/Django-1.4.9.tar.gz
# tar -zxvf Django-1.4.9.tar.gz
# cd Django-1.4.9
# python setup.py install
</textarea><br/>创建一个demo项目，以便验证环境是否正确安装部署。<br/><textarea name="code" class="python" rows="15" cols="100">
# cd /data/www
# django-admin.py startproject demo

# 由于Django1.4版本后对项目目录做了改动，即将manage.py管理任务命令单独放在项目根目录。为后续与OMServer平台目录结构相兼容，我们对目录结构进行调整。
# cd demo/demo && mv * ../ && cd .. && rm -rf demo

# 最终文件目录结构如下：
# ls
__init__.py&nbsp;&nbsp;manage.py&nbsp;&nbsp;settings.py&nbsp;&nbsp;urls.py&nbsp;&nbsp;wsgi.py
</textarea><br/>7、django-debug-toolbar的安装（Django调试利器）<br/><textarea name="code" class="c" rows="15" cols="100">
# wget http://blog.liuts.com/Django/django-debug-toolbar-master.tar.gz
# tar -zxvf django-debug-toolbar-master.tar.gz
# cd django-debug-toolbar-master/
# python setup.py install
</textarea><br/>8、配置Nginx，修改/usr/local/nginx/conf/nginx.conf，最终完整配置如下：<br/><textarea name="code" class="c" rows="15" cols="100">
user&nbsp;&nbsp;nobody;
worker_processes&nbsp;&nbsp;2;

#error_log&nbsp;&nbsp;logs/error.log;
#error_log&nbsp;&nbsp;logs/error.log&nbsp;&nbsp;notice;
#error_log&nbsp;&nbsp;logs/error.log&nbsp;&nbsp;info;

#pid&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logs/nginx.pid;


events &#123;
&nbsp;&nbsp;&nbsp;&nbsp;worker_connections&nbsp;&nbsp;10240;
&#125;


http &#123;
&nbsp;&nbsp;&nbsp;&nbsp;include&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mime.types;
&nbsp;&nbsp;&nbsp;&nbsp;default_type&nbsp;&nbsp;application/octet-stream;

&nbsp;&nbsp;&nbsp;&nbsp;#log_format&nbsp;&nbsp;main&nbsp;&nbsp;'$remote_addr - $remote_user [$time_local] "$request" '
&nbsp;&nbsp;&nbsp;&nbsp;#&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'$status $body_bytes_sent "$http_referer" '
&nbsp;&nbsp;&nbsp;&nbsp;#&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'"$http_user_agent" "$http_x_forwarded_for"';

&nbsp;&nbsp;&nbsp;&nbsp;#access_log&nbsp;&nbsp;logs/access.log&nbsp;&nbsp;main;

&nbsp;&nbsp;&nbsp;&nbsp;sendfile&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;on;
&nbsp;&nbsp;&nbsp;&nbsp;tcp_nopush&nbsp;&nbsp;&nbsp;&nbsp; on;

&nbsp;&nbsp;&nbsp;&nbsp;keepalive_timeout&nbsp;&nbsp;65;

&nbsp;&nbsp;&nbsp;&nbsp;gzip&nbsp;&nbsp;on;
&nbsp;&nbsp;&nbsp;&nbsp;server &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;listen 80;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;server_name demo.domain.com;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;location / &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;uwsgi_pass 127.0.0.1:9000;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;include uwsgi_params;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;uwsgi_param UWSGI_CHDIR&nbsp;&nbsp;/data/www/demo;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;uwsgi_param UWSGI_SCRIPT wsgi;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;access_log off;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;

&nbsp;&nbsp;&nbsp;&nbsp;&#125;

&#125;
</textarea><br/><span style="color: #DC143C;">* uwsgi_param UWSGI_SCRIPT wsgi;参数值wsgi对应项目目录中的wsgi.py，此处文件前缀与参数值要保持一致。</span><br/><br/>9、配置uwsgi，创建uwsgi配置文件/usr/local/nginx/conf/uwsgi.ini，详细内容如下：<br/><textarea name="code" class="c" rows="15" cols="100">
[uwsgi]
socket = 0.0.0.0:9000
master = true
pidfile = /usr/local/nginx/uwsgi.pid
processes = 8
workers = 2
chdir = /data/www/demo
pythonpath = /data/www
profiler=true
memory-report=true
enable-threads = true
logdate=true
limit-as=6048
daemonize=/data/logs/django.log
</textarea><br/>---关键参数及说明---<br/>1）chdir 指定项目目录；<br/>2）pythonpath 指定项目目录上一级<br/>3）processes 指定进程数<br/>4）workers 分配CPU的核数<br/>5）limit-as 子进程分配的内存大小<br/>6）max-requests 分配最大的请求数<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;启动uwsgi与nginx服务，建议配置成服务自启动脚本，便于后续的日常维护。详细启动脚本这里不展开说明，有兴趣的读者可参阅互联网上已经存在的相关资源。<br/>&nbsp;&nbsp;&nbsp;&nbsp;最后启动uwsgi与nginx服务<br/><textarea name="code" class="c" rows="15" cols="100">
# /usr/bin/uwsgi --ini /usr/local/nginx/conf/uwsgi.ini
# /usr/local/nginx/sbin/nginx
</textarea><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;访问http://demo.domain.com，出现如图所示的页面说明Django+uwsgi环境部署成功！<br/><a href="https://blog.liuts.com/attachment.php?fid=364" target="_blank"><img src="https://blog.liuts.com/attachment.php?fid=364" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/><br/><strong>二、OMServer项目部署</strong><br/>1、修改Nginx配置<br/>添加OMServer项目站点配置，[server]域具体内容如下：<br/><textarea name="code" class="c" rows="15" cols="100">
&nbsp;&nbsp;&nbsp;&nbsp;server &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;listen 80;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;server_name omserver.domain.com;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;location / &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;uwsgi_pass 127.0.0.1:9001;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;include uwsgi_params;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;uwsgi_param UWSGI_CHDIR&nbsp;&nbsp;/data/www/OMserverweb;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;uwsgi_param UWSGI_SCRIPT django_wsgi;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;access_log off;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;location ^~ /static &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;root /data/www/OMserverweb;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;location ~* ^.+&#92;.(mpg&#124;avi&#124;mp3&#124;swf&#124;zip&#124;tgz&#124;gz&#124;rar&#124;bz2&#124;doc&#124;xls&#124;exe&#124;ppt&#124;txt&#124;tar&#124;mid&#124;midi&#124;wav&#124;rtf&#124;mpeg)$ &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;root /data/www/OMserverweb/static;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;access_log off;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&nbsp;&nbsp;&#125;
</textarea><br/><span style="color: #DC143C;"><br/>&nbsp;&nbsp;1）切记修改UWSGI_SCRIPT为django_wsgi;<br/>&nbsp;&nbsp;2）监听uwsgi端口修改成127.0.0.1:9001;&nbsp;&nbsp;&nbsp;&nbsp;#多个站点使用不同端口区分<br/></span><br/><br/>2、添加omserver项目uwsgi配置<br/><textarea name="code" class="c" rows="15" cols="100">
# cd /usr/local/nginx/conf
# vi uwsgi_omserver.ini
[uwsgi]
socket = 0.0.0.0:9001
master = true
pidfile = /usr/local/nginx/uwsgi_omserver.pid
processes = 8
chdir = /data/www/OMserverweb
pythonpath = /data/www
profiler=true
memory-report=true
enable-threads = true
logdate=true
limit-as=6048
daemonize=/data/logs/django_omserver.log
</textarea><br/>3、项目源码配置<br/>&nbsp;&nbsp;1）项目源码：<br/>&nbsp;&nbsp;&nbsp;&nbsp;# cd /data/www<br/>&nbsp;&nbsp;&nbsp;&nbsp;下载地址：https://github.com/yorkoliu/pyauto/tree/master/第十三章/OMserverweb<br/>&nbsp;&nbsp;2）导入数据库结构(Mysql)<br/>&nbsp;&nbsp;&nbsp;&nbsp;下载地址：https://github.com/yorkoliu/pyauto/blob/master/第十三章/SQL/OMServer.sql<br/>&nbsp;&nbsp;3）修改setting.py（数据库信息）<br/><textarea name="code" class="python" rows="15" cols="100">
DATABASES = &#123;
&nbsp;&nbsp;&nbsp;&nbsp;'default': &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'NAME': 'OMServer',&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# Or path to database file if using sqlite3.
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'USER': 'omserver_user',&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# Not used with sqlite3.
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'PASSWORD': 'J8w3jZXSG#y34',&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# Not used with sqlite3.
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'HOST': '192.168.1.10',&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# Set to empty string for localhost. Not used with sqlite3.
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'PORT': '3306',&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# Set to empty string for default. Not used with sqlite3.
&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&#125;
</textarea><br/>&nbsp;&nbsp; 4）修改主控端rpyc主机IP<br/>&nbsp;&nbsp;&nbsp;&nbsp;OMserverweb/autoadmin/views.py<br/>&nbsp;&nbsp;&nbsp;&nbsp;<textarea name="code" class="python" rows="15" cols="100">
&nbsp;&nbsp;&nbsp;&nbsp;... ...
&nbsp;&nbsp;&nbsp;&nbsp;try:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;conn=rpyc.connect('192.168.1.20',11511)&nbsp;&nbsp;&nbsp;&nbsp;#修改此处的rpyc主机地址；
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;conn.root.login('OMuser','KJS23o4ij09gHF734iuhsdfhkGYSihoiwhj38u4h')
&nbsp;&nbsp;&nbsp;&nbsp;except Exception,e:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.error('connect rpyc server error:'+str(e))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return HttpResponse('connect rpyc server error:'+str(e))
&nbsp;&nbsp;&nbsp;&nbsp;... ...
&nbsp;&nbsp;&nbsp;&nbsp;</textarea><br/>启动项目uwsgi及Nginx服务<br/><textarea name="code" class="c" rows="15" cols="100">
# /usr/bin/uwsgi --ini /usr/local/nginx/conf/uwsgi_omserver.ini
# killall -9 nginx
# /usr/local/nginx/sbin/nginx
</textarea><br/>4、访问http://omserver.domain.com，出现以下系统界面说明部署成功！<br/><a href="https://blog.liuts.com/attachment.php?fid=365" target="_blank"><img src="https://blog.liuts.com/attachment.php?fid=365" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/><br/>下一步配置<a href="http://blog.liuts.com/post/246/" target="_blank">《python自动化运维：技术与最佳实践》之OMServer平台环境部署详解【主控制端】</a><br/><br/>补：平台涉及开源组件包下载：<br/>Django-1.4.9.tar.gz <a href="http://blog.liuts.com/Django/Django-1.4.9.tar.gz" target="_blank">下载</a><br/>uwsgi-2.0.4.tar.gz <a href="http://blog.liuts.com/Django/uwsgi-2.0.4.tar.gz" target="_blank">下载</a><br/>rpyc-3.2.3.tar.gz <a href="http://blog.liuts.com/Django/rpyc-3.2.3.tar.gz" target="_blank">下载</a><br/>pcre-8.34.tar.gz <a href="http://blog.liuts.com/Django/pcre-8.34.tar.gz" target="_blank">下载</a><br/>nginx-1.5.9.tar.gz <a href="http://blog.liuts.com/Django/nginx-1.5.9.tar.gz" target="_blank">下载</a><br/>MySQL-python-1.2.5.zip <a href="http://blog.liuts.com/Django/MySQL-python-1.2.5.zip" target="_blank">下载</a><br/>django-debug-toolbar-master.tar.gz <a href="http://blog.liuts.com/Django/django-debug-toolbar-master.tar.gz" target="_blank">下载</a><br/>Tags - <a href="https://blog.liuts.com/tags/omserver/" rel="tag">omserver</a> , <a href="https://blog.liuts.com/tags/django%25E7%258E%25AF%25E5%25A2%2583/" rel="tag">django环境</a> , <a href="https://blog.liuts.com/tags/python%25E8%25BF%2590%25E7%25BB%25B4%25E8%2587%25AA%25E5%258A%25A8%25E5%258C%2596/" rel="tag">python运维自动化</a>
]]>
</description>
</item><item>
<link>https://blog.liuts.com/post/237/</link>
<title><![CDATA[基于Python实现的轻量级WebServer-Yorserver1.0]]></title> 
<author>刘天斯 &lt;liutiansi@gmail.com&gt;</author>
<category><![CDATA[Python]]></category>
<pubDate>Tue, 09 Apr 2013 13:39:44 +0000</pubDate> 
<guid>https://blog.liuts.com/post/237/</guid> 
<description>
<![CDATA[ 
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;准备在小组内部做一次《HTTP协议分析》的培训，为了不受限于Request header与response header的内容，想更深入了解服务器端是如何响应、处理一个请求的，花了几天时间写了Yorserver，目前基本的功能都实现，功能清单如下：<br/>1、支持自定义response服务及协议版本；<br/>2、支持Expires及max-age的功能；<br/>3、支持多进程或线程开启；<br/>4、支持错误页及默认页配置；<br/>5、支持access_log及error_log配置；<br/>6、支持gzip压缩配置；<br/>7、支持安全套连接服务HTTPS；<br/>8、支持HTTP MIME自定义配置；<br/>9、支持php、perl、python脚本cgi访问；<br/>10、支持配置文件。<br/>(Centos6.*环境测试通过)<br/><br/><strong>一、配置文件说明yorserver.conf</strong><br/><textarea name="code" class="c" rows="15" cols="100">
# This is the  Yorserver configuration file.
# server_version: Add response HTTP header server version information.
server_version = "YorServer1.0"

# bind_ip: Allows you to bind yorserver to specific IP addresses.
#
bind_ip="0.0.0.0"

# port: Allows you to bind yorserver's port, http default 80 and Https 443.
port=80

# sys_version: Add response HTTP header python version information.
sys_version = ""

# protocol_version: Add response HTTP header protocol version. 
protocol_version = "HTTP/1.0"

# Expires: Add response HTTP header Expires and Max-age version. format:d/h/m(Day/Hour/Minute).
Expires="7d"

# Multiprocess: configure yorserver Multi process support(on/off).
Multiprocess="off"

# Multithreading: configure yorserver Multi threading support(on/off).
Multithreading="on"

# DocumentRoot: configure web server document root.
DocumentRoot="/usr/local/yorserver/www"

# page404: configure web server deafult 404 page.
page404="/404.html"

# indexpage: configure web server deafult index page.
indexpage="/index.html"

# Logfile: configure web server log file path,disable logs Logfile="".
Logfile="/usr/local/yorserver/logs/access.log"

# errorfile: configure web server error file path.
errorfile="/usr/local/yorserver/logs/error.log"

[gzip]
# gzip: Enable(on) or Disable(off) gzip options.
gzip="on"

# configure compress level(1~9)
compresslevel=1

[ssl]
# ssl: Enable(on) or Disable(off) HTTPS options,port options must configure "443".
ssl="off"

# configure privatekey and certificate pem.
privatekey="/home/webkey/privkey.pem"
certificate="/home/webkey/cacert.pem"

[cgim]
# cgi_moudle: Enable(on) or Disable(off) cgi support.
cgi_moudle="on"

# cgi_path: configure cgi path,multiple cgi path use ',' delimited,cgi_path in bin directory.
cgi_path='/cgi-bin',

# cgi_extensions: configure cgi file extension.
cgi_extensions="('.cgi','.py','.pl','.php')"

# contentTypes: configure file mime support.
[contentTypes]
css="text/css"
doc="application/msword"
gif="image/gif"
gz="application/x-gzip"
html="text/html"
htm="text/html"
esp="text/html"
ics="text/calendar"
jpeg="image/jpeg"
jpg="image/jpeg"
js="text/javascript"
pdf="application/pdf"
png="image/png"
rtf="application/rtf"
txt="text/plain"
zip="application/zip"
cgi="text/html"
py="text/html"
pl="text/html"
php="text/html"
</textarea><br/><br/><strong>程序截图</strong><br/>1、访问日志<br/><a href="http://liuts-blog.b0.upaiyun.com/201304/1366039352_9551647c.jpg" target="_blank"><img src="http://liuts-blog.b0.upaiyun.com/201304/1366039352_9551647c.jpg" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/><br/>2、目录列表<br/><a href="https://blog.liuts.com/attachment.php?fid=335" target="_blank"><img src="https://blog.liuts.com/attachment.php?fid=335" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/><br/>3、gzip压缩<br/><a href="https://blog.liuts.com/attachment.php?fid=336" target="_blank"><img src="https://blog.liuts.com/attachment.php?fid=336" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/><br/>4、HTTPS支持<br/><a href="https://blog.liuts.com/attachment.php?fid=337" target="_blank"><img src="https://blog.liuts.com/attachment.php?fid=337" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/><br/>5、PHP CGI<br/><a href="https://blog.liuts.com/attachment.php?fid=338" target="_blank"><img src="https://blog.liuts.com/attachment.php?fid=338" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/><br/>6、python CGI<br/><a href="https://blog.liuts.com/attachment.php?fid=339" target="_blank"><img src="https://blog.liuts.com/attachment.php?fid=339" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/><br/><strong>三、安装</strong><br/>https://github.com/yorkoliu/pyauto/tree/master/%E7%AC%AC%E5%85%AB%E7%AB%A0<br/><br/><br/><strong>四、在线测试</strong>(可启用httpwatch查看效果)<br/><a href="http://blog.liuts.com:8080/" target="_blank">http://blog.liuts.com:8080/</a><br/><a href="http://blog.liuts.com:8080/cgi-bin/index.pl" target="_blank">http://blog.liuts.com:8080/cgi-bin/index.pl</a><br/><a href="http://blog.liuts.com:8080/cgi-bin/index.php" target="_blank">http://blog.liuts.com:8080/cgi-bin/index.php</a><br/><a href="http://blog.liuts.com:8080/cgi-bin/index.py" target="_blank">http://blog.liuts.com:8080/cgi-bin/index.py</a>
]]>
</description>
</item><item>
<link>https://blog.liuts.com/post/217/</link>
<title><![CDATA[构建高性能缓存推送平台(添加squid支持)[原创]]]></title> 
<author>刘天斯 &lt;liutiansi@gmail.com&gt;</author>
<category><![CDATA[Python]]></category>
<pubDate>Fri, 15 Oct 2010 15:13:10 +0000</pubDate> 
<guid>https://blog.liuts.com/post/217/</guid> 
<description>
<![CDATA[ 
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在web2.0网站系统架构中，缓存无处不在。如一个大的CDN平台，一个普通的页面级缓存等。合理的利用缓存可以提高用户下载速度、降低源服务器性能负载。如何高效去维护一个缓存集群？除了提高命中率便是缓存的推送管理。现与大家分享构建一个高性能的缓存推送平台思路及实现。<br/><br/><strong>一、平台架构图</strong><br/><a href="https://blog.liuts.com/attachment.php?fid=224" target="_blank"><img src="https://blog.liuts.com/attachment.php?fid=224" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 说明：平台使用Django+mysql开发，支持POS/GET两种模式，POST方式用于管理员的手工推送，GET方式则用于接口模式。平台将接收到的URL进行校验、分类后统一向所属缓存服务器组进行telnet pureg请求。遍历完所有主机后返回结果串。<br/><br/><strong>二、平台截图</strong><br/><span style="color: #DC143C;">1、管理UI</span><br/><a href="http://blog.liuts.com/attachment/201010/1287152458_1760351a.png" target="_blank"><img src="http://blog.liuts.com/attachment/201010/1287152458_1760351a.png" border="1" width="710"></a><br/><br/><span style="color: #DC143C;">2、接口说明</span><br/><a href="http://blog.liuts.com/attachment/201010/1287157746_26000b73.png" target="_blank"><img src="http://blog.liuts.com/attachment/201010/1287157746_26000b73.png" border="1" width="710"></a><br/><br/><span style="color: #DC143C;">3、接口调用</span><br/><a href="http://blog.liuts.com/attachment/201010/1287153878_23937e08.jpg" target="_blank"><img src="http://blog.liuts.com/attachment/201010/1287153878_23937e08.jpg" border="1" width="710"></a><br/><br/><br/><strong>三、功能说明</strong><br/> <span style="color: #00008B;">1、普通模式</span><br/>&nbsp;&nbsp;&nbsp;&nbsp; 只限制于文件或目录的推送<br/>&nbsp;&nbsp;例：推送http://www.domain.com/web/index.shtml及http://www.domain.com/js/下的全部文件。<br/><br/>&nbsp;&nbsp;1.1、手工方式<br/>&nbsp;&nbsp;输入框中输入：<br/><div class="quote"><div class="quote-title">引用</div><div class="quote-content"><br/>&nbsp;&nbsp; http://www.domain.com/web/index.shtml<br/>&nbsp;&nbsp; http://www.domain.com/js/<br/></div></div>后点［提交推送］按钮。<br/><br/>&nbsp;&nbsp;1.2、接口方式<br/><div class="quote"><div class="quote-title">引用</div><div class="quote-content"><br/>&nbsp;&nbsp;http://www.domain.com/push/executive/?PushURLid=http://www.domain.com/web/index.shtml,http://www.domain.com/js/&Advancedmode=<br/></div></div><br/> <span style="color: #00008B;">2、高级模式</span><br/>&nbsp;&nbsp;&nbsp;&nbsp; 支持正则表达式的URL规则(适合专业人员使用)<br/>&nbsp;&nbsp;例：推送http://www.domain.com/main/下文件名为index，扩展名任意的文件及http://www.domain.com/images/下所有*.swf,*.gif文件。<br/><br/>&nbsp;&nbsp;2.1、手工方式<br/>&nbsp;&nbsp;输入框中输入：<br/><div class="quote"><div class="quote-title">引用</div><div class="quote-content"><br/>&nbsp;&nbsp; http://www.domain.com/main/index..*$<br/>&nbsp;&nbsp; http://www.domain.com/images/.*.(swf&#124;gif)<br/></div></div>选中［高级模式］后点［提交推送］按钮。<br/><br/>&nbsp;&nbsp;2.2、接口方式<br/><div class="quote"><div class="quote-title">引用</div><div class="quote-content"><br/>&nbsp;&nbsp;http://www.domain.com/push/executive/?PushURLid=http://www.domain.com/main/index..*$,http://www.domain.com/images/.*.(swf&#124;gif)&Advancedmode=1<br/></div></div><br/> <span style="color: #00008B;">3、注意事项</span><br/>&nbsp;&nbsp; 手工模式中禁止在输入框中出现空行、多个URL连接。<br/><span style="color: #DC143C;">注：squid主机不支持高级模式及目录推送</span><br/><strong>三、性能测试</strong><br/>#ab -c 1000 -n 5000 http://sys.domain.com/push/executive/?PushURLid=http://1.domain.com/1.js,http://2.domain.com/img/&Advancedmode=<br/>3.1、Nginx+Django+fastcgi模式测试数据<br/><a href="https://blog.liuts.com/attachment.php?fid=219" target="_blank"><img src="https://blog.liuts.com/attachment.php?fid=219" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/><br/>3.2、Nginx+Django+UWSGI模式测试数据<br/><a href="https://blog.liuts.com/attachment.php?fid=226" target="_blank"><img src="https://blog.liuts.com/attachment.php?fid=226" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0" width="711"/></a><br/><br/>结论：对接口进行了压力测试，以5000次1000并发进行请求，fastcgi模式速度很快，但存在很多返回错误，从后台日志来看，都是NGINX 502 Bad Gatewa信息，说明后端fastcgi已经处理超时了，UWSGI模式速度不及fastcgi，但表现得很稳定。最终选择了UWSGI+Nginx组合。<br/><br/><strong>三、平台部署</strong><br/>1、部署环境平台<br/>参考：<a href="http://blog.liuts.com/post/216/" target="_blank">Centos5.4+Nginx-0.8.50+UWSGI-0.9.6.2+Django-1.2.3搭建高性能WEB服务器[原创]</a><br/><br/>2、部署代码<br/>#cd /opt/www<br/>#wget http://blog.liuts.com/Purgesys.tar.gz<br/>#tar -zxvf Purgesys.tar.gz<br/><br/>#cd Purgesys<br/>#vi setting.py<br/><strong><span style="color: #DC143C;">红色为修改项</span></strong><br/><div class="quote"><div class="quote-title">引用</div><div class="quote-content"><br/># Django settings for Purgesys project.<br/><br/>DEBUG = True<br/>TEMPLATE_DEBUG = DEBUG<br/><br/>ADMINS = (<br/>&nbsp;&nbsp;&nbsp;&nbsp; ('Liuts', 'liutiansi@gmail.com'),<br/>)<br/><br/>MANAGERS = ADMINS<br/><br/><span style="color: #DC143C;"><br/>#数据库信息<br/>DATABASES = &#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;'default': &#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'NAME': 'Purgesys',&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# Or path to database file if using sqlite3.<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'USER': 'dbuser',&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# Not used with sqlite3.<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'PASSWORD': 'dbpass',&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# Not used with sqlite3.<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'HOST': '192.168.100.215',&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# Set to empty string for localhost. Not used with sqlite3.<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'PORT': '3306',&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# Set to empty string for default. Not used with sqlite3.<br/>&nbsp;&nbsp;&nbsp;&nbsp;&#125;<br/>&#125;<br/><br/><br/>#varnish管理端口与varnish启动参数.. -T 127.0.0.1:2603保持一致。<br/>VARNISHADMINPORT=2603<br/>SQUIDADMINPORT=80<br/></span><br/><br/># Local time zone for this installation. Choices can be found here:<br/># http://en.wikipedia.org/wiki/List_of_tz_zones_by_name<br/># although not all choices may be available on all operating systems.<br/># On Unix systems, a value of None will cause Django to use the same<br/># timezone as the operating system.<br/># If running in a Windows environment this must be set to the same as your<br/># system time zone.<br/>TIME_ZONE = 'Asia/Shanghai'<br/><br/># Language code for this installation. All choices can be found here:<br/># http://www.i18nguy.com/unicode/language-identifiers.html<br/>LANGUAGE_CODE = 'zh-cn'<br/><br/>SITE_ID = 1<br/><br/># If you set this to False, Django will make some optimizations so as not<br/># to load the internationalization machinery.<br/>USE_I18N = True<br/><br/># If you set this to False, Django will not format dates, numbers and<br/># calendars according to the current locale<br/>USE_L10N = True<br/><br/># Absolute path to the directory that holds media.<br/># Example: "/home/media/media.lawrence.com/"<br/>MEDIA_ROOT = '<span style="color: #DC143C;">/opt/www/Purgesys/</span>static/'<br/><br/># URL that handles the media served from MEDIA_ROOT. Make sure to use a<br/># trailing slash if there is a path component (optional in other cases).<br/># Examples: "http://media.lawrence.com", "http://example.com/media/"<br/>MEDIA_URL = '/static/'<br/><br/># URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a<br/># trailing slash.<br/># Examples: "http://foo.com/media/", "/media/".<br/>ADMIN_MEDIA_PREFIX = '/static/'<br/><br/># Make this unique, and don't share it with anybody.<br/>SECRET_KEY = 'tj)*mv!pc_)!zsk*cki$u_f9fg9&^)2^64qi#8!c8xjji--sm7'<br/><br/># List of callables that know how to import templates from various sources.<br/>TEMPLATE_LOADERS = (<br/>&nbsp;&nbsp;&nbsp;&nbsp;'django.template.loaders.filesystem.Loader',<br/>&nbsp;&nbsp;&nbsp;&nbsp;'django.template.loaders.app_directories.Loader',<br/>#&nbsp;&nbsp;&nbsp;&nbsp; 'django.template.loaders.eggs.Loader',<br/>)<br/><br/>MIDDLEWARE_CLASSES = (<br/>&nbsp;&nbsp;&nbsp;&nbsp;'django.middleware.common.CommonMiddleware',<br/>&nbsp;&nbsp;&nbsp;&nbsp;'django.contrib.sessions.middleware.SessionMiddleware',<br/>&nbsp;&nbsp;&nbsp;&nbsp;'django.middleware.csrf.CsrfViewMiddleware',<br/>&nbsp;&nbsp;&nbsp;&nbsp;'django.contrib.auth.middleware.AuthenticationMiddleware',<br/>&nbsp;&nbsp;&nbsp;&nbsp;'django.contrib.messages.middleware.MessageMiddleware',<br/>)<br/><br/>ROOT_URLCONF = 'Purgesys.urls'<br/><br/>TEMPLATE_DIRS = (<br/>&nbsp;&nbsp;&nbsp;&nbsp;# Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".<br/>&nbsp;&nbsp;&nbsp;&nbsp;# Always use forward slashes, even on Windows.<br/>&nbsp;&nbsp;&nbsp;&nbsp;# Don't forget to use absolute paths, not relative paths.<br/>&nbsp;&nbsp;&nbsp;&nbsp;'<span style="color: #DC143C;">/opt/www/Purgesys/</span>templates'<br/>)<br/><br/>INSTALLED_APPS = (<br/>&nbsp;&nbsp;&nbsp;&nbsp;'django.contrib.auth',<br/>&nbsp;&nbsp;&nbsp;&nbsp;'django.contrib.contenttypes',<br/>&nbsp;&nbsp;&nbsp;&nbsp;'django.contrib.sessions',<br/>&nbsp;&nbsp;&nbsp;&nbsp;'django.contrib.sites',<br/>&nbsp;&nbsp;&nbsp;&nbsp;'django.contrib.messages',<br/>&nbsp;&nbsp;&nbsp;&nbsp;# Uncomment the next line to enable the admin:<br/>&nbsp;&nbsp;&nbsp;&nbsp;# 'django.contrib.admin',<br/>&nbsp;&nbsp;&nbsp;&nbsp;# Uncomment the next line to enable admin documentation:<br/>&nbsp;&nbsp;&nbsp;&nbsp;# 'django.contrib.admindocs',<br/>&nbsp;&nbsp;&nbsp;&nbsp;'Purgesys.purgeapp',<br/>&nbsp;&nbsp;&nbsp;&nbsp;'Purgesys.publicclass',<br/>)<br/><br/></div></div><br/><br/>3、导入数据库文件<br/>cd Purgesys/sql<br/><textarea name="code" class="c" rows="15" cols="100">
#mysql -u dbuser -pdbpass dbname<Purgesys.sql
</textarea><br/>添加用户数据(注意关联关系)：<br/> purgeapp_resource(缓存主机表)<br/> purgeapp_resourcegroup(应用表)<br/><br/>4、Varnish配置项<br/>配置应用主域名set req.http.host = "web.domain.com"，这样做有两个好处：<br/>&nbsp;&nbsp;①对单应用多域名只缓存一份数据;<br/>&nbsp;&nbsp;②有利于缓存推送。<br/><div class="quote"><div class="quote-title">引用</div><div class="quote-content"><br/>sub vcl_recv &#123;<br/>&nbsp;&nbsp; ...<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (req.http.host ~ "web.domain.com") &#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; set req.backend = webserver;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #FF0000;">set req.http.host = "web.domain.com";</span><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (req.request != "GET" && req.request != "HEAD") &#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return(pipe);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#125;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else &#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return(lookup);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#125;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#125;<br/>...<br/>&#125;<br/></div></div><br/><br/>5、Varnish启动参数<br/>-T 0.0.0.0:3500一定要与setting.py中的ADMINPORT=2603保持一致，否则无法进行推送操作。<br/><br/>6、访问测试<br/>http://sys.domain.com/push/<br/><br/>7、缓存推送平台1.0下载<br/><a href="attachment.php?fid=225">点击这里下载文件</a><br/><br/>缓存推送平台1.1下载<br/>(添加squid支持)<br/><a href="attachment.php?fid=236">点击这里下载文件</a><br/><br/><strong>四、后续问题</strong><br/>１、我的服务端口非80怎么办？如URL：http://test.domain.com:8080/static/main.gif。<br/>解决方法：<br/>　　在数据库添加应用主机名称时加上端口便可，即ResourceGroupName(表)插入：<br/>　　“test.domain.com:8080　－　varnish”<br/><br/>如大家有什么疑问或感兴趣的话题可以通过weibo与我交流：<a href="http://t.qq.com/yorkoliu" target="_blank">http://t.qq.com/yorkoliu</a><br/>Tags - <a href="https://blog.liuts.com/tags/python/" rel="tag">python</a> , <a href="https://blog.liuts.com/tags/%25E7%25BC%2593%25E5%25AD%2598/" rel="tag">缓存</a> , <a href="https://blog.liuts.com/tags/%25E6%258E%25A8%25E9%2580%2581/" rel="tag">推送</a> , <a href="https://blog.liuts.com/tags/%25E5%25B9%25B3%25E5%258F%25B0/" rel="tag">平台</a> , <a href="https://blog.liuts.com/tags/varnish/" rel="tag">varnish</a>
]]>
</description>
</item><item>
<link>https://blog.liuts.com/post/184/</link>
<title><![CDATA[开源项目:天涯服务器管理系统 V2.1.1[原创]]]></title> 
<author>刘天斯 &lt;liutiansi@gmail.com&gt;</author>
<category><![CDATA[Python]]></category>
<pubDate>Tue, 09 Mar 2010 10:35:31 +0000</pubDate> 
<guid>https://blog.liuts.com/post/184/</guid> 
<description>
<![CDATA[ 
	&nbsp;&nbsp;&nbsp;&nbsp;一个用于管理服务器的运维软件，可以很方便管理上千台Linux服务器。<br/><br/>项目托管地址：<a href="http://code.google.com/p/tianyaservmanager/" target="_blank">http://code.google.com/p/tianyaservmanager/</a><br/><br/><strong>开源协议</strong><br/>Artistic License/GPL<br/><br/><strong>一、开发包</strong><br/><strong>Client</strong><br/>python 2.5 +<br/>wxpython2.8+<br/>rpyc3.0+<br/>psyco 1.6+<br/>MySQLdb<br/>ConfigParser<br/>pywin32 for py2.5 (windows only)<br/><br/><strong>Server</strong><br/>func<br/>certmaster<br/>cfengine<br/>mysql5.0+<br/>rpyc3.0+<br/><br/><strong>二、支持平台</strong><br/>Windows xp/2000/2003 Linux2.6+ MacOS<br/><br/><strong>三、角色分配</strong><br/>客户端<br/>服务器端<br/><br/><strong>四、功能特点</strong><br/>跨平台、分级管理、实时监控、及时报警、远程操作、可扩展性、在线升级、安全可靠<br/><br/><strong>五、系统架构图</strong><br/><a href="https://blog.liuts.com/attachment.php?fid=71" target="_blank"><img src="https://blog.liuts.com/attachment.php?fid=71" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/><br/><strong>六、功能截图</strong><br/>客户端登录界面<br/><a href="https://blog.liuts.com/attachment.php?fid=63" target="_blank"><img src="https://blog.liuts.com/attachment.php?fid=63" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/>客户端主界面<br/><a href="https://blog.liuts.com/attachment.php?fid=64" target="_blank"><img src="https://blog.liuts.com/attachment.php?fid=64" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/><br/>更多截图：<br/><a href="http://blog.liuts.com/post/175/" target="_blank">http://blog.liuts.com/post/175/</a><br/><br/><strong>七、服务器端Demo</strong><br/><a href="http://blog.liuts.com/post/183/" target="_blank">http://blog.liuts.com/post/183/</a><br/><br/><strong>八、模块编写</strong><br/>XRC（XML Resource）的设计来源于wxWidgets，它的想法很简单，就是将界面设计的工作从程序中独立出来。具体的做法是，创建单独的XML文件，负责 界面设计，程序运行的时候载入，生成界面。这样做的好处是显而易见的。首先，将繁琐的外观设计代码从程序中去掉，程序更清晰易读。其次，XRC文件独立于 程序，程序运行时才调用，因此可以随意更换外观。这种思想并不是wxWidgets的原创，MFC中的RC已经有了，类似的还有HTML和CSS的关系。 wxPython从wxWidgets继承而来，当然也保留了XRC(介绍来源于互联网)。 <br/>更多<a href="http://wiki.wxwidgets.org/Using_XML_Resources_with_XRC" target="_blank">http://wiki.wxwidgets.org/Using_XML_Resources_with_XRC</a><br/><br/><strong>九、目录结构</strong><br/>/var/SERVMANAGER<br/>├─data 存放服务器分类及一般信息(XML格式)<br/>├─img 系统图片资源<br/>├─Module 系统模块UI资源<br/>├─numbers 系统帐号pem密钥文件,默认只有root.pem。<br/>├─sql 系统表结构<br/>└─tmp 系统临时目录(XML格式)<br/><br/><strong>十、初始化系统</strong><br/>修改config.py，配置服务器主机、帐号、密码及数据库。<br/>默认帐号：root<br/>默认密码：123456<br/>运行文件ServManager.py即可。<br/><br/><strong>十一、声明</strong><br/>由于平台目前只在公司内部使用，因些会存在很多不完善的地方，大家在使用过程当中出现问题本人将不负任何责任，软件只供学习与交流用，同时禁止用于任何商业用途。<br/><br/>如大家有什么疑问或感兴趣的话题可以通过weibo与我交流：<a href="http://t.qq.com/yorkoliu" target="_blank">http://t.qq.com/yorkoliu</a><br/>Tags - <a href="https://blog.liuts.com/tags/%25E5%25BC%2580%25E6%25BA%2590/" rel="tag">开源</a> , <a href="https://blog.liuts.com/tags/%25E6%259C%258D%25E5%258A%25A1%25E5%2599%25A8%25E7%25AE%25A1%25E7%2590%2586/" rel="tag">服务器管理</a> , <a href="https://blog.liuts.com/tags/wxpython/" rel="tag">wxpython</a>
]]>
</description>
</item><item>
<link>https://blog.liuts.com/post/183/</link>
<title><![CDATA[服务器管理系统服务器端Demo]]></title> 
<author>刘天斯 &lt;liutiansi@gmail.com&gt;</author>
<category><![CDATA[Python]]></category>
<pubDate>Tue, 09 Mar 2010 02:03:53 +0000</pubDate> 
<guid>https://blog.liuts.com/post/183/</guid> 
<description>
<![CDATA[ 
	开源客户端地址：<a href="http://code.google.com/p/tianyaservmanager/" target="_blank">http://code.google.com/p/tianyaservmanager/</a><br/>代码比较简单就不加以说明了,大家有任何疑问可以留言。<br/><strong>服务代码</strong><br/><textarea name="code" class="python" rows="15" cols="100">
import time
import os
import re
from cPickle import dumps
from rpyc import Service
from rpyc.utils.server import ThreadedServer

#----------------------------------------------------------------------------&nbsp;&nbsp;#
# Name:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ServManagerServer.py&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #
# Purpose:&nbsp;&nbsp;&nbsp;&nbsp; system service Module&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #
# Author:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Liutiansi&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #
# Email:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; liutiansi@gamil.com&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#
# Created:&nbsp;&nbsp;&nbsp;&nbsp; 2009/03/03&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#
# Copyright:&nbsp;&nbsp; (c) 2009&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#
#-----------------------------------------------------------------------------&nbsp;&nbsp;#

class ManagerService(Service):

&nbsp;&nbsp;&nbsp;&nbsp;#Login--------------------------------------------------------------
&nbsp;&nbsp;&nbsp;&nbsp;def exposed_login(self,user,passwd):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if user=="admin" and passwd=="123456":
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.Checkout_pass=True
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.Checkout_pass=False
&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;#group1---------------------------------------------------------------
&nbsp;&nbsp;&nbsp;&nbsp;def exposed_Runcommands(self,Parameter1="",Parameter2="",Parameter3="",Parameter4=""):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pinglist=""
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if self.Checkout_pass!=True:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return dumps("Illegal User!")
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;except:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return dumps("Illegal Login!")
&nbsp;&nbsp;
&nbsp;&nbsp;#明码传输&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pinglist = os.popen("/usr/local/bin/python /var/system/ModuleClass.py "+str(Parameter1)+" '"+Parameter2+"' "+str(Parameter3)+" "+str(Parameter4)).readlines()

&nbsp;&nbsp;#加密传输,Decryption方法不提供，用户可自定义。
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#pinglist = os.popen("/usr/local/bin/python /var/system/ModuleClass.py "+self.Decryption(str(Parameter1))+" '"+self.Decryption(str(Parameter2))+"' "+self.Decryption(str(Parameter3))+" "+str(Parameter4)).readlines()
&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return dumps(eval(pinglist[0]))

s=ThreadedServer(ManagerService,port=7758,auto_register=False)
s.start()
</textarea><br/><br/><strong>模块代码</strong><br/><textarea name="code" class="python" rows="15" cols="100">
# -*- coding: utf-8 -*-
import os
import re
import time
import sys
import string
import xmlrpclib
import func.overlord.client as fc

#----------------------------------------------------------------------------&nbsp;&nbsp;#
# Name:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ModuleClass.py&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #
# Purpose:&nbsp;&nbsp;&nbsp;&nbsp; system run Module&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#
# Author:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Liutiansi&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #
# Email:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; liutiansi@gamil.com&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#
# Created:&nbsp;&nbsp;&nbsp;&nbsp; 2009/03/03&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#
# Copyright:&nbsp;&nbsp; (c) 2009&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#
#-----------------------------------------------------------------------------&nbsp;&nbsp;#

class ModuleClassMain():
&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;def dorun(self,argvstr):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for parstr in argvstr:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if parstr.find(r'`')!=-1:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;client = fc.Overlord(argvstr[1])

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#输出系统日志
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if argvstr[0]=="3101":
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pinglist =client.command.run("/usr/bin/tail -"+str(argvstr[2])+" /var/log/messages")
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;except Exception,e:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pass
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print pinglist

if __name__ == '__main__':
&nbsp;&nbsp;&nbsp;&nbsp;app = ModuleClassMain()
&nbsp;&nbsp;&nbsp;&nbsp;app.dorun(sys.argv[1:])
</textarea><br/>如大家有什么疑问或感兴趣的话题可以通过weibo与我交流：<a href="http://t.qq.com/yorkoliu" target="_blank">http://t.qq.com/yorkoliu</a><br/>Tags - <a href="https://blog.liuts.com/tags/python/" rel="tag">python</a> , <a href="https://blog.liuts.com/tags/rpyc/" rel="tag">rpyc</a> , <a href="https://blog.liuts.com/tags/%25E6%259C%258D%25E5%258A%25A1%25E5%2599%25A8%25E7%25AB%25AF/" rel="tag">服务器端</a> , <a href="https://blog.liuts.com/tags/demo/" rel="tag">demo</a>
]]>
</description>
</item><item>
<link>https://blog.liuts.com/post/182/</link>
<title><![CDATA[写一个爬虫程序[原创]]]></title> 
<author>刘天斯 &lt;liutiansi@gmail.com&gt;</author>
<category><![CDATA[Python]]></category>
<pubDate>Mon, 08 Mar 2010 02:33:42 +0000</pubDate> 
<guid>https://blog.liuts.com/post/182/</guid> 
<description>
<![CDATA[ 
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;写爬虫是一项复杂、枯噪、反复的工作，考虑的问题包括采集效率、链路异常处理、数据质量(与站点编码规范关系很大)等。整理自己写一个爬虫程序，单台服务器可以启用1~8个实例同时采集，然后将数据入库。<br/><textarea name="code" class="python" rows="15" cols="100">
#-*- coding:utf-8 -*-
#!/usr/local/bin/python
import sys, time, os,string
import mechanize
import urlparse
from BeautifulSoup import BeautifulSoup
import re
import MySQLdb
import logging
import cgi
from optparse import OptionParser
#----------------------------------------------------------------------------#
# Name:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TySpider.py&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#
# Purpose:&nbsp;&nbsp;&nbsp;&nbsp; WebSite&nbsp;&nbsp;Spider Module&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #
# Author:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;刘天斯&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #
# Email:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; liutiansi@gamil.com&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#
# Created:&nbsp;&nbsp;&nbsp;&nbsp; 2010/02/16&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#
# Copyright:&nbsp;&nbsp; (c) 2010&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#
#----------------------------------------------------------------------------#


"""
&#124;--------------------------------------------------------------------------
&#124; 定义 loging class;
&#124;--------------------------------------------------------------------------
&#124;
&#124; 功能：记录系统相关日志信息。
&#124; 
&#124;
"""
class Pubclilog():
&nbsp;&nbsp;&nbsp;&nbsp;def __init__(self):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.logfile = 'website_log.txt'

&nbsp;&nbsp;&nbsp;&nbsp;def iniLog(self):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger = logging.getLogger()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;filehandler = logging.FileHandler(self.logfile)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;streamhandler = logging.StreamHandler()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fmt = logging.Formatter('%(asctime)s, %(funcName)s, %(message)s')
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.setLevel(logging.DEBUG) 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.addHandler(filehandler) 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.addHandler(streamhandler)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return [logger,filehandler]


"""
&#124;--------------------------------------------------------------------------
&#124; 定义 tySpider class;
&#124;--------------------------------------------------------------------------
&#124;
&#124; 功能：抓取分类、标题等信息
&#124; 
&#124;
"""
class BaseTySpider:

&nbsp;&nbsp;&nbsp;&nbsp;#初始化相关成员方法
&nbsp;&nbsp;&nbsp;&nbsp;def __init__(self,X,log_switch):

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#数据库连接
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.conn = MySQLdb.connect(db='dbname',host='192.168.0.10', user='dbuser',passwd='SDFlkj934y5jsdgfjh435',charset='utf8')

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#分类及标题页面Community
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.CLASS_URL = 'http://test.abc.com/aa/CommTopicsPage?'

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#发表回复页
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.Content_URL = 'http://test.bac.com/aa/CommMsgsPage?'

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#开始comm值
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.X=X

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#当前comm id取模，方面平均到表
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.mod=self.X%5

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#Community文件下载页
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.body=""

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#self.bodySoup对象
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.soup=None

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#发表回复页下载内容变量
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.Contentbody=""

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#发表回复页内容self.ContentbodySoup对象
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.Contentsoup=None

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#日志开关
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.log_switch=log_switch


&nbsp;&nbsp;&nbsp;&nbsp;#======================获取名称及分类方法==========================
&nbsp;&nbsp;&nbsp;&nbsp;def _SpiderClass(self,nextpage=None):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if nextpage==None:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FIXED_QUERY = 'cmm='+str(self.X)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FIXED_QUERY = nextpage[1:]

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rd = mechanize.Browser()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rd.addheaders = [("User-agent", "Tianya/2010 (compatible; MSIE 6.0;Windows NT 5.1)")]
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rd.open(self.CLASS_URL + FIXED_QUERY)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.body=rd.response().read()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#rd=mechanize.Request(self.CLASS_URL + FIXED_QUERY)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#response = mechanize.urlopen(rd)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#self.body=response.read()

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;except Exception,e:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if self.log_switch=="on":
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logapp=Pubclilog()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger,hdlr = logapp.iniLog()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.info(self.CLASS_URL + FIXED_QUERY+str(e))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hdlr.flush()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.removeHandler(hdlr)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.soup = BeautifulSoup(self.body)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NextPageObj= self.soup("a", &#123;'class' : re.compile("fs-paging-item fs-paging-next")&#125;)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.cursor = self.conn.cursor()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if nextpage==None:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Ttag=str(self.soup.table)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#print Ttag

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"""
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;------------------分析结构体-----------------
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<table cellspacing="0" cellpadding="0">
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<tr>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<td>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<h1 title="Dunhill">Dunhill</h1>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <td valign="middle">
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<div class="fs-comm-cat">
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="fs-icons fs-icon-cat"> </span> <a href="TopByCategoryPage?cid=211&amp;ref=commnav-cat">中国</a> &raquo; <a href="TopByCategoryPage?cid=211&amp;subcid=273&amp;ref=commnav-cat">人民</a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</div>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</tr>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</table>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"""

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soupTable=BeautifulSoup(Ttag)

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#定位到第一个h1标签
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tableh1 = soupTable("h1")
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#print self.X
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#print "Name:"+tableh1[0].string.strip().encode('utf-8')

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#处理无类型的
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#定位到表格中符合规则“^TopByCategory”A链接块，tablea[0]为第一个符合条件的连接文字，tablea[1]...
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tablea = soupTable("a", &#123;'href' : re.compile("^TopByCategory")&#125;)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if tablea[0].string.strip()=="":
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pass
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#print "BigCLass:"+tablea[0].string.strip().encode('utf-8')
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#print "SubClass:"+tablea[1].string.strip().encode('utf-8')
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;except Exception,e:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if self.log_switch=="on":
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logapp=Pubclilog()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger,hdlr = logapp.iniLog()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.info("[noClassInfo]"+str(self.X)+str(e))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hdlr.flush()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.removeHandler(hdlr)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.cursor.execute("insert into baname"+str(self.mod)+" values('%d','%d','%s')" %(self.X,-1,tableh1[0].string.strip().encode('utf-8')))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.conn.commit() 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self._SpiderTitle()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if NextPageObj:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NextPageURL=NextPageObj[0]['href']
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self._SpiderClass(NextPageURL)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return


&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#获取链接二对象的href值
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;classlink=tablea[1]['href']
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;par_dict=cgi.parse_qs(urlparse.urlparse(classlink).query)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#print "CID:"+par_dict["cid"][0]
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#print "SubCID:"+par_dict["subcid"][0]
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#print "---------------------------------------"
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#插入数据库
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.cursor.execute("insert into class values('%d','%s')" %(int(par_dict["cid"][0]),tablea[0].string.strip().encode('utf-8')))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.cursor.execute("insert into subclass values('%d','%d','%s')" %(int(par_dict["subcid"][0]),int(par_dict["cid"][0]),tablea[1].string.strip().encode('utf-8'))) 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.cursor.execute("insert into baname"+str(self.mod)+" values('%d','%d','%s')" %(self.X,int(par_dict["subcid"][0]),tableh1[0].string.strip().encode('utf-8')))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.conn.commit() 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self._SpiderTitle()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if NextPageObj:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NextPageURL=NextPageObj[0]['href']
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self._SpiderClass(NextPageURL)

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.body=None
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.soup=None
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Ttag=None
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soupTable=None
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;table=None
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;table1=None
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;classlink=None
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;par_dict=None
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;except Exception,e:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if self.log_switch=="on":
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logapp=Pubclilog()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger,hdlr = logapp.iniLog()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.info("[ClassInfo]"+str(self.X)+str(e))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hdlr.flush()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.removeHandler(hdlr)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self._SpiderTitle()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if NextPageObj:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NextPageURL=NextPageObj[0]['href']
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self._SpiderClass(NextPageURL)




&nbsp;&nbsp;&nbsp;&nbsp;#====================获取标题方法=========================
&nbsp;&nbsp;&nbsp;&nbsp;def _SpiderTitle(self):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#查找标题表格对象(table)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soupTitleTable=self.soup("table", &#123;'class' : "fs-topic-list"&#125;)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#查找标题行对象(tr)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TitleTr = soupTitleTable[0]("tr", &#123;'onmouseover' : re.compile("^this&#92;.className='fs-row-hover'")&#125;)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"""
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-----------分析结构体--------------
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<tr class="fs-alt-row" onmouseover="this.className='fs-row-hover'" onmouseout="this.className='fs-alt-row'">
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<td valign="middle" class="fs-hot-topic-dots-ctn">
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<div class="fs-hot-topic-dots" style="background-position:0 -0px" title="点击量：12"></div>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<td valign="middle" class="fs-topic-name">
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="CommMsgsPage?cmm=16081&amp;tid=2718969307756232842&amp;ref=regulartopics" id="a53" title="【新人报到】欢迎美国人民加入" target="_blank">【新人报到】欢迎美国人民加入</a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="fs-meta">
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="fs-icons fs-icon-mini-reply"> </span>0
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="fs-icons fs-icon-pageview"> </span>12</span>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<td valign="middle">
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a class="fs-tiny-user-avatar umhook " href="ProfilePage?uid=8765915421039908242" title="中国人"><img src="http://img1.sohu.com.cn/aa/images/138/0/P/1/s.jpg" /></a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<td valign="middle" style="padding-left:4px">
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="Profile?uid=8765915421039908242" id="b53" title="中国人" class="umhook">中国人</a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<td valign="middle" class="fs-topic-last-mdfy fs-meta">2-14</td>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</tr>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"""
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for CurrTr in TitleTr:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#初始化置顶及精华状态
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Title_starred='N'
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Title_sticky='N'

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#获取当前记录的BeautifulSoup对象
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soupCurrTr=BeautifulSoup(str(CurrTr))

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#BeautifulSoup分析HTML有误，只能通过span的标志数来获取贴子状态，会存在一定误差
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#如只有精华时也会当成置顶来处理。
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TitleStatus=soupCurrTr("span", &#123;'title' : ""&#125;)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TitlePhotoViewer=soupCurrTr("a", &#123;'href' : re.compile("^PhotoViewer")&#125;)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if TitlePhotoViewer.__len__()==1:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TitlePhotoViewerBool=0
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TitlePhotoViewerBool=1
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if TitleStatus.__len__()==3-TitlePhotoViewerBool:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Title_starred='Y'
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Title_sticky='Y'
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;elif TitleStatus.__len__()==2-TitlePhotoViewerBool:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Title_sticky='Y'

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#获取贴子标题
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Title=soupCurrTr.a.next.strip()

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#获取贴子ID
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;par_dict=cgi.parse_qs(urlparse.urlparse(soupCurrTr.a['href']).query)

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#获取回复数及浏览器
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TitleNum=soupCurrTr("td", &#123;'class' : "fs-topic-name"&#125;)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TitleArray=string.split(str(TitleNum[0]),'&#92;n')
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Title_ReplyNum=string.split(TitleArray[len(TitleArray)-4],'>')[2]
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Title_ViewNum=string.split(TitleArray[len(TitleArray)-2],'>')[2][:-6]

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#获取贴子作者
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TitleAuthorObj=soupCurrTr("td", &#123;'style' : "padding-left:4px"&#125;)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Title_Author=TitleAuthorObj[0].next.next.next.string.strip().encode('utf-8')


&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#获取回复时间
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TitleTime=soupCurrTr("td", &#123;'class' : re.compile("^fs-topic-last-mdfy fs-meta")&#125;)

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"""
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print "X:"+str(self.X)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print "Title_starred:"+Title_starred
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print "Title_sticky:"+Title_sticky
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print "Title:"+Title

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#获取贴子内容连接URL
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print "Title_link:"+soupCurrTr.a['href']
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print "CID:"+par_dict["tid"][0]
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print "Title_ReplyNum:"+Title_ReplyNum
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print "Title_ViewNum:"+Title_ViewNum
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print "Title_Author:"+Title_Author
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print "TitleTime:"+TitleTime[0].string.strip().encode('utf-8')
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"""

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#入库
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.cursor.execute("insert into Title"+str(self.mod)+" values('%s','%d','%s','%d','%d','%s','%s','%s','%s')" %(par_dict["tid"][0], &#92;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.X,Title,int(Title_ReplyNum),int(Title_ViewNum),Title_starred,Title_sticky, &#92;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Title_Author.decode('utf-8'),TitleTime[0].string.strip().encode('utf-8')))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.conn.commit()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self._SpiderContent(par_dict["tid"][0])
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;except Exception,e:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if self.log_switch=="on":
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logapp=Pubclilog()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger,hdlr = logapp.iniLog()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.info("[Title]"+str(self.X)+'-'+par_dict["tid"][0]+'-'+str(e))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hdlr.flush()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.removeHandler(hdlr)


&nbsp;&nbsp;&nbsp;&nbsp;#======================获取发表及回复方法=======================
&nbsp;&nbsp;&nbsp;&nbsp;def _SpiderContent(self,ID,nextpage=None):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if nextpage==None:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FIXED_QUERY = 'cmm='+str(self.X)+'&tid='+ID+'&ref=regulartopics'
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FIXED_QUERY = nextpage[9:]

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rd = mechanize.Browser()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rd.addheaders = [("User-agent", "Tianya/2010 (compatible; MSIE 6.0;Windows NT 5.1)")]
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rd.open(self.Content_URL + FIXED_QUERY)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.Contentbody=rd.response().read()

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#rd=mechanize.Request(self.Content_URL + FIXED_QUERY)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#response = mechanize.urlopen(rd)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#self.Contentbody=response.read()

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.Contentsoup = BeautifulSoup(self.Contentbody)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NextPageObj= self.Contentsoup("a", &#123;'class' : re.compile("fs-paging-item fs-paging-next")&#125;)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Tdiv=self.Contentsoup("div", &#123;'class' : "fs-user-action"&#125;)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;i=0
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for Currdiv in Tdiv:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if i==0:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Ctype='Y'
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Ctype='N'
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#发表时间
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soupCurrdiv=BeautifulSoup(str(Currdiv))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PosttimeObj=soupCurrdiv("span", &#123;'class' : "fs-meta"&#125;)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Posttime=PosttimeObj[0].next[1:]
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Posttime=Posttime[0:-3]
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#IP地址
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IPObj=soupCurrdiv("a", &#123;'href' : re.compile("CommMsgAddress")&#125;)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if IPObj:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IP=IPObj[0].next.strip()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IP=''


&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#发表／回复内容
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ContentObj=soupCurrdiv("div", &#123;'class' :"fs-user-action-body"&#125;)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Content=ContentObj[0].renderContents().strip()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"""
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print "ID:"+str(self.X)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print "ID:"+ID
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print "Ctype:"+Ctype
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print "POSTTIME:"+Posttime
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print "IP:"+IP
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print "Content:"+Content
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"""

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.cursor.execute("insert into Content"+str(self.mod)+" values('%s','%d','%s','%s','%s','%s')" %(ID,self.X,Ctype,Posttime,IP,Content.decode('utf-8')))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.conn.commit() 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;i+=1

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;except Exception,e:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if self.log_switch=="on":
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logapp=Pubclilog()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger,hdlr = logapp.iniLog()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.info("[Content]"+str(self.X)+'-'+ID+'-'+str(e))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hdlr.flush()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.removeHandler(hdlr)

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#如“下一页”有链接刚继续遍历
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if NextPageObj:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NextPageURL=NextPageObj[0]['href']
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self._SpiderContent(ID,NextPageURL)


&nbsp;&nbsp;&nbsp;&nbsp;def __del__(self):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.cursor.close()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.conn.close()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;except Exception,e:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pass

#遍历comm范围
def initapp(StartValue,EndValue,log_switch):
&nbsp;&nbsp;&nbsp;&nbsp;for x in range(StartValue,EndValue): 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;app=BaseTySpider(x,log_switch)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;app._SpiderClass()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;app=None

if __name__ == "__main__":
&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;#定义命令行参数
&nbsp;&nbsp;&nbsp;&nbsp;MSG_USAGE = "TySpider.py [ -s StartNumber EndNumber ] -l [on&#124;off] [-v][-h]"
&nbsp;&nbsp;&nbsp;&nbsp;parser = OptionParser(MSG_USAGE)
&nbsp;&nbsp;&nbsp;&nbsp;parser.add_option("-s", "--set", nargs=2,action="store", 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dest="comm_value",
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;type="int",
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;default=False, 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;help="配置名称ID值范围。".decode('utf-8'))
&nbsp;&nbsp;&nbsp;&nbsp;parser.add_option("-l", "--log", action="store", 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dest="log_switch",
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;type="string",
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;default="on", 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;help="错误日志开关".decode('utf-8'))
&nbsp;&nbsp;&nbsp;&nbsp;parser.add_option("-v","--version", action="store_true", dest="verbose",
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;help="显示版本信息".decode('utf-8'))
&nbsp;&nbsp;&nbsp;&nbsp;opts, args = parser.parse_args()

&nbsp;&nbsp;&nbsp;&nbsp;if opts.comm_value:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if opts.comm_value[0]>opts.comm_value[1]:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print "终止值比起始值还小？"
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if opts.log_switch=="on":
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log_switch="on"
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log_switch="off"
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;initapp(opts.comm_value[0],opts.comm_value[1],log_switch)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit();

&nbsp;&nbsp;&nbsp;&nbsp;if opts.verbose:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print "WebSite Scider V1.0 beta."
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit;
</textarea><br/><br/>如大家有什么疑问或感兴趣的话题可以通过weibo与我交流：<a href="http://t.qq.com/yorkoliu" target="_blank">http://t.qq.com/yorkoliu</a><br/>Tags - <a href="https://blog.liuts.com/tags/%25E7%2588%25AC%25E8%2599%25AB/" rel="tag">爬虫</a> , <a href="https://blog.liuts.com/tags/python/" rel="tag">python</a>
]]>
</description>
</item><item>
<link>https://blog.liuts.com/post/177/</link>
<title><![CDATA[服务器管理系统－手机终端[原创]]]></title> 
<author>root &lt;admin@yourname.com&gt;</author>
<category><![CDATA[Python]]></category>
<pubDate>Tue, 05 Jan 2010 13:31:37 +0000</pubDate> 
<guid>https://blog.liuts.com/post/177/</guid> 
<description>
<![CDATA[ 
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;每逢佳节回老家不知道孩子们是否都安康，这回好了，3G时代已经到来，不用带上那笨重的本本也能够管理服务器了，只要有手机信号就行，呵呵。系统基于pys60+socket开发，需要什么样的功能，在服务器端写相应的模块即可，客户端升级也比较方便。安全方面使用加密传输＋IP限制就差不多了。<br/><strong>default.py代码</strong><br/><textarea name="code" class="python" rows="15" cols="100">
﻿# -*- coding: utf-8 -*-
import appuifw
import e32
import string
import graphics
import md5
from appuifw import *
from graphics import *
from moni import monitor

"""
作者：刘天斯
邮箱：liutiansi@gmail.com
最后更新：2008-01-26 11:27
功能：Linux服务器手机版(客户端脚本),系统基于pys60+socket开发；
"""

def handle_redraw(rect):
&nbsp;&nbsp;&nbsp;&nbsp;canvas.blit(bgimage)

def exit_key_handler():
&nbsp;&nbsp;&nbsp;&nbsp;app_lock.signal()
&nbsp;&nbsp;&nbsp;&nbsp;appuifw.app.set_exit()
&nbsp;&nbsp;&nbsp;&nbsp;
def handle_tab(index):
&nbsp;&nbsp;&nbsp;&nbsp;global app
&nbsp;&nbsp;&nbsp;&nbsp;global lb
&nbsp;&nbsp;&nbsp;&nbsp;global canvas
&nbsp;&nbsp;&nbsp;&nbsp;if index == 0:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;appuifw.app.body = canvas
&nbsp;&nbsp;&nbsp;&nbsp;else:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;appuifw.app.body = app.getgetinfo(index)

if __name__ == '__main__':
&nbsp;&nbsp;&nbsp;&nbsp;appuifw.app.set_tabs(["主界面".decode("utf8"), "数据区".decode("utf8"), "实时区".decode("utf8"), "帮助".decode("utf8")],handle_tab)
&nbsp;&nbsp;&nbsp;&nbsp;app = monitor()
&nbsp;&nbsp;&nbsp;&nbsp;#系统环境初始化；
&nbsp;&nbsp;&nbsp;&nbsp;img=Image.new((208,196))
&nbsp;&nbsp;&nbsp;&nbsp;try:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bgimage=Image.open(u"e:&#92;&#92;System&#92;&#92;Apps&#92;&#92;monitor&#92;&#92;monitor.jpg")
&nbsp;&nbsp;&nbsp;&nbsp;except IOError,e:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;appuifw.note(u"ERROR:"+e,"error")
&nbsp;&nbsp;&nbsp;&nbsp;canvas=appuifw.Canvas(event_callback=None, redraw_callback=handle_redraw)
&nbsp;&nbsp;&nbsp;&nbsp;appuifw.app.body = canvas
&nbsp;&nbsp;&nbsp;&nbsp;appuifw.app.screen = 'normal'
&nbsp;&nbsp;&nbsp;&nbsp;appuifw.app.title = "服务器管理1.0".decode("utf8")
&nbsp;&nbsp;&nbsp;&nbsp;appuifw.app.exit_key_handler = exit_key_handler
&nbsp;&nbsp;&nbsp;&nbsp;app_lock = e32.Ao_lock()
&nbsp;&nbsp;&nbsp;&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;#用户验证;
&nbsp;&nbsp;&nbsp;&nbsp;Inputpasswd=appuifw.query("请输入管理密码：".decode("utf8"), "code")
&nbsp;&nbsp;&nbsp;&nbsp;usermm=md5.new()
&nbsp;&nbsp;&nbsp;&nbsp;usermm.update(Inputpasswd)
&nbsp;&nbsp;&nbsp;&nbsp;if usermm.hexdigest()==app.sys_passwd():
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;appuifw.note("验证通过！".decode("utf8"), "conf")
&nbsp;&nbsp;&nbsp;&nbsp;else:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;appuifw.note("密码错误。".decode("utf8"), "error")
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;app_lock.signal()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;appuifw.app.set_exit()
&nbsp;&nbsp;&nbsp;&nbsp;app_lock.wait()
</textarea><br/><strong>monitor.py代码</strong><br/><textarea name="code" class="python" rows="15" cols="100">
﻿# -*- coding: utf-8 -*-
import appuifw
import e32
import string
import graphics
from appuifw import *
from graphics import *
import socket
import md5
import time

"""
作者：刘天斯
邮箱：liutiansi@gmail.com
最后更新：2008-01-26 11:27
功能：Linux服务器手机版(客户端脚本),系统基于pys60+socket开发；
"""
class monitor:
&nbsp;&nbsp;&nbsp;&nbsp;#定义退出函数;
&nbsp;&nbsp;&nbsp;&nbsp;def __init__(self):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#IP列表
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.lines=[]

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#读取配置文件串
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.configstr=[]

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#选择服务器索引
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.index=0

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#返回服务器串
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.getinfo=""

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#空数据串
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.nullinfo="暂无数据！"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#帮助串
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.helpinfo="Linux服务器管理1.0&#92;n　　　系统帮助信息：&#92;n状态：检查服务器应用状态。&#92;n管理：对应用进行操作。&#92;n设置：配制系统参数。"

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#标签项索引
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.tabsIndex=0
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#展示文本对象
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.infotxt= appuifw.Text()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.infotxt.style=appuifw.STYLE_BOLD

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#读取配制文件
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.configfile=file(u"e:&#92;&#92;System&#92;&#92;Apps&#92;&#92;monitor&#92;&#92;config.ini",'r')
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.configstr=string.split(self.configfile.read().strip().decode("utf8"),',')
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#实时时间+间隔时间+md5+返回记录数
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.configfile.close()

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#菜单项
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.ipfw=[u'192.168.0/24',u'192.168.1/24',u'192.168.2/24',u'192.168.2/24']
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;appuifw.app.menu = [("状态".decode("utf8"), (("检测".decode("utf8"), self.server_check),("实时".decode("utf8"), self.server_realtime))),
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;("管理".decode("utf8"), (("应用管理".decode("utf8"), self.server_do),("最新日志".decode("utf8"), self.server_newslog),("选择日志".decode("utf8"), self.server_selelog))),
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;("设置".decode("utf8"), (("实时时间".decode("utf8"), self.sys_realtime),("实时间隔".decode("utf8"), self.sys_gaptime),("修改密码".decode("utf8"), self.sys_repasswd),("记录数目".decode("utf8"), self.sys_lognum))),
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;("关于".decode("utf8"), self.sys_about)]

&nbsp;&nbsp;&nbsp;&nbsp;#发送socket指令方法(发送串,显示屏ID)；
&nbsp;&nbsp;&nbsp;&nbsp;def server_sendsocket(self,get_sendstr):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if get_sendstr!="":
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sock.connect(('server.sina.com.cn', 80))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#get_sendstr=base64.urlsafe_b64encode(get_sendstr)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sock.send(get_sendstr)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.getinfo+=sock.recv(1024)+"&#92;n"
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sock.close()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;except:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;appuifw.note("socket异常!".decode("utf8"),"conf")
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.server_listinfo(self.tabsIndex)

&nbsp;&nbsp;&nbsp;&nbsp;#操作方法(操作类型,显示屏ID)；
&nbsp;&nbsp;&nbsp;&nbsp;def server_do(self,option=1):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#option=1 检测服务器状态；
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#option=2 实时检测服务器状态；
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#option=3 最新服务器日志；
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#option=4 选择服务器日志；
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if self.index==0 and option!=3:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.server_list()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.index=appuifw.selection_list(choices=self.lines,search_field=1)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if self.index!=None and option!=3:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#返回简IP;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if self.lines[self.index][:3]=="192":
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;shortip="1"
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if option==3:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.server_sendsocket(str(option)+",,"+self.configstr[2]+",,"+self.configstr[3])
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Alg=Algorithm() #制定自己的算法
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.server_sendsocket(str(option)+","+str(shortip)+","+self.configstr[2]+","+string.split(self.lines[self.index],'.')[3]+","+self.configstr[3])＋Alg
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#格式：操作ID+IP类型+MD5pw+IP末段+功能码＋算法；

&nbsp;&nbsp;&nbsp;&nbsp;#服务器状态检测；&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;def server_check(self):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.getinfo=""
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.index=0
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.tabsIndex=1
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.server_do(1)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.lines=[]

&nbsp;&nbsp;&nbsp;&nbsp; #服务器实时状态检测；&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;def server_realtime(self):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.getinfo=""
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.index=0
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.tabsIndex=2
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;i=0
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while 1:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;time.sleep(1)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;i+=1
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if i%int(self.configstr[1])==0 or i==int(self.configstr[0]):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.server_do(1)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if i==int(self.configstr[0]):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.lines=[]

&nbsp;&nbsp;&nbsp;&nbsp;#服务器最新日志
&nbsp;&nbsp;&nbsp;&nbsp;def server_newslog(self):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.getinfo=""
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.index=0
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.tabsIndex=1
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.server_do(3)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.lines=[]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;#选择服务器日志
&nbsp;&nbsp;&nbsp;&nbsp;def server_selelog(self):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.getinfo=""
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.index=0
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.tabsIndex=1
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.server_do(4)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.lines=[]
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;#获取服务器列表；
&nbsp;&nbsp;&nbsp;&nbsp;def server_list(self):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;iplistFile=open(u"e:&#92;&#92;System&#92;&#92;Apps&#92;&#92;monitor&#92;&#92;ip.txt",'r')
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;except IOError,e:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;appuifw.note(u"ERROR:"+e,"error")
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;serverindex=appuifw.selection_list(choices=self.ipfw,search_field=1)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for nowline in [l.strip() for l in iplistFile]:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if nowline[:3]==self.ipfw[serverindex][:3]:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.lines.append(nowline.decode("utf8"))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;del nowline
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;iplistFile.close()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.lines.sort()

&nbsp;&nbsp;&nbsp;&nbsp;#写配制文件；
&nbsp;&nbsp;&nbsp;&nbsp;def sys_writesysconfig(self):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f = file(u"e:&#92;&#92;System&#92;&#92;Apps&#92;&#92;monitor&#92;&#92;config.ini",'w+')
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;except IOError,e:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;appuifw.note(u"ERROR:"+e,"error")
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print >> f,str(self.configstr[0])+","+str(self.configstr[1])+","+str(self.configstr[2])+","+str(self.configstr[3])
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f.seek(0)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f.close()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;appuifw.note("数据更新成功！".decode("utf8"), "conf")

&nbsp;&nbsp;&nbsp;&nbsp;#配制实时时间；
&nbsp;&nbsp;&nbsp;&nbsp;def sys_realtime(self):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;realtime = appuifw.query("间隔监控时间：".decode("utf8"), "number",int(self.configstr[0]))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if int(realtime)!=int(self.configstr[0]):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.configstr[0]=realtime
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.sys_writesysconfig()

&nbsp;&nbsp;&nbsp;&nbsp;#配制间隔时间；
&nbsp;&nbsp;&nbsp;&nbsp;def sys_gaptime(self):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gaptime = appuifw.query("实时监控时间：".decode("utf8"), "number",int(self.configstr[1]))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if int(gaptime)!=int(self.configstr[1]):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.configstr[1]=gaptime
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.sys_writesysconfig()

&nbsp;&nbsp;&nbsp;&nbsp;#修改密码；
&nbsp;&nbsp;&nbsp;&nbsp;def sys_repasswd(self):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;passwd = appuifw.query("新密码:".decode("utf8"), "code")
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if passwd!="":
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;usermm=md5.new()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;usermm.update(passwd)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.configstr[2]=usermm.hexdigest()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.sys_writesysconfig()

&nbsp;&nbsp;&nbsp;&nbsp;#配制返回记录数；
&nbsp;&nbsp;&nbsp;&nbsp;def sys_lognum(self):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lognum = appuifw.query("返回记录数：".decode("utf8"), "number",int(self.configstr[3]))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if int(lognum)!=int(self.configstr[3]):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.configstr[3]=lognum
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.sys_writesysconfig()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;#显示数据
&nbsp;&nbsp;&nbsp;&nbsp;def server_listinfo(self,tabsIndex):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.infotxt.set(self.getinfo.decode("utf8"))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;appuifw.app.body = self.infotxt
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;appuifw.app.activate_tab(tabsIndex)

&nbsp;&nbsp;&nbsp;&nbsp;#返回PASSWD
&nbsp;&nbsp;&nbsp;&nbsp;def sys_passwd(self):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;&nbsp;self.configstr[2].strip()

&nbsp;&nbsp;&nbsp;&nbsp;#返回文本对象
&nbsp;&nbsp;&nbsp;&nbsp;def getgetinfo(self,tabsIndex):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if tabsIndex==3:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.infotxt.set(self.helpinfo.decode("utf8"))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;elif self.tabsIndex==tabsIndex:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.infotxt.set(self.getinfo.decode("utf8"))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.infotxt.set(self.nullinfo.decode("utf8"))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return self.infotxt
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;#about
&nbsp;&nbsp;&nbsp;&nbsp;def sys_about(self):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;appuifw.note(u"Linux Monitor1.0&#92;nAuthor:Liutiansi&#92;nMail:liutiansi@gmail.com&#92;nCopyright:http://blog.liuts.com", "info")
</textarea><br/><br/><strong>支持手机</strong><br/><div class="quote"><div class="quote-title">引用</div><div class="quote-content"><br/>S60 1st：<br/>7650、3650、3660、N-GAGE、N-GAGE QD、松下X700、西门子SX1<br/><br/>S60 2nd：<br/>6600<br/><br/>S60 2nd FP1：<br/>6620（6600美版）、6260、3230、6670、7610、松下X800、联想P930、三星SGH-D728、摩托罗拉V1000<br/><br/>S60 2nd FP2：<br/>6681、6682（6681美版）、6680、6630<br/><br/>S60 2nd FP3：<br/>N70、N70音乐版、N70 IE版、N72、N90<br/><br/>S60 3rd：<br/>3250、3250XM、5500 sport、5500 sport音乐版、E50、E60、E61、E62（E61大陆行）、E61i、E65、E70、N71、N73、N73音乐版、N73 IE版、N75、N77、N80、N91、N91 8GB、N92、N93、N93i、三星SGH-i400、LG KS10<br/><br/>S60 3rd FP1：<br/>5700 XpressMusic、6110 Navigator、6120 classic、6121 classic（6120美版）、6290、N76、N95、E90 Communicator、三星SGH-i520<br/></div></div><br/><strong>平台截图</strong><br/><br/>我的手机MAIN<br/><a href="https://blog.liuts.com/attachment.php?fid=49" target="_blank"><img src="https://blog.liuts.com/attachment.php?fid=49" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/><br/>主界面<br/><a href="https://blog.liuts.com/attachment.php?fid=53" target="_blank"><img src="https://blog.liuts.com/attachment.php?fid=53" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/><br/>部分功能菜单<br/><a href="https://blog.liuts.com/attachment.php?fid=50" target="_blank"><img src="https://blog.liuts.com/attachment.php?fid=50" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/><a href="https://blog.liuts.com/attachment.php?fid=51" target="_blank"><img src="https://blog.liuts.com/attachment.php?fid=51" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/><a href="https://blog.liuts.com/attachment.php?fid=52" target="_blank"><img src="https://blog.liuts.com/attachment.php?fid=52" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/><a href="https://blog.liuts.com/attachment.php?fid=48" target="_blank"><img src="https://blog.liuts.com/attachment.php?fid=48" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/><br/>打包下载<br/><a href="attachment.php?fid=55">点击这里下载文件</a><br/><br/>如大家有什么疑问或感兴趣的话题可以通过weibo与我交流：<a href="http://t.qq.com/yorkoliu" target="_blank">http://t.qq.com/yorkoliu</a><br/>Tags - <a href="https://blog.liuts.com/tags/pys60/" rel="tag">pys60</a> , <a href="https://blog.liuts.com/tags/%25E6%259C%258D%25E5%258A%25A1%25E5%2599%25A8%25E7%25AE%25A1%25E7%2590%2586%25E5%25B9%25B3%25E5%258F%25B0/" rel="tag">服务器管理平台</a>
]]>
</description>
</item><item>
<link>https://blog.liuts.com/post/151/</link>
<title><![CDATA[Ping for GUI]]></title> 
<author>root &lt;admin@yourname.com&gt;</author>
<category><![CDATA[Python]]></category>
<pubDate>Thu, 22 Jan 2009 14:59:38 +0000</pubDate> 
<guid>https://blog.liuts.com/post/151/</guid> 
<description>
<![CDATA[ 
	用python写的GUI，功能是用PING探测各地IP的延时值并生成简单报表，方便了解网络健康状态。<a href="https://blog.liuts.com/attachment.php?fid=13" target="_blank"><img src="https://blog.liuts.com/attachment.php?fid=13" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/><br/><a href="attachment.php?fid=39">点击这里下载文件</a><br/>Tags - <a href="https://blog.liuts.com/tags/ping/" rel="tag">ping</a>
]]>
</description>
</item>
</channel>
</rss>